com.vaadin.addon.calendar.gwt.client.ui.VCalendarPaintable.java Source code

Java tutorial

Introduction

Here is the source code for com.vaadin.addon.calendar.gwt.client.ui.VCalendarPaintable.java

Source

/*
@VaadinAddonLicenseForJavaFiles@
 */
package com.vaadin.addon.calendar.gwt.client.ui;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ContextMenuEvent;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.CalendarEvent;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.CalendarEventId;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.DateUtil;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.SimpleDayCell;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.SimpleDayCell.MonthEventLabel;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.WeekGrid.DateCell;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.WeekGrid.DateCell.DateCellSlot;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.WeekGrid.DateCell.DayEvent;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.dd.CalendarDropHandler;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.dd.CalendarMonthDropHandler;
import com.vaadin.addon.calendar.gwt.client.ui.schedule.dd.CalendarWeekDropHandler;
import com.vaadin.addon.calendar.ui.Calendar;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.TooltipInfo;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.VConsole;
import com.vaadin.terminal.gwt.client.ui.Action;
import com.vaadin.terminal.gwt.client.ui.ActionOwner;
import com.vaadin.terminal.gwt.client.ui.dd.VHasDropHandler;

/**
 * Handles communication between {@link Calendar} on the server side and
 * {@link VCalendar} on the client side.
 * 
 * @since 1.0.0
 * @version
 * @VERSION@
 */
public class VCalendarPaintable extends VCalendar implements Paintable, VHasDropHandler, ActionOwner {

    public static final String ACCESSCRITERIA = "-ac";
    public static final String ATTR_WEEK = "w";
    public static final String ATTR_DOW = "dow";
    public static final String ATTR_FDATE = "fdate";
    public static final String ATTR_DATE = "date";
    public static final String ATTR_STYLE = "extracss";
    public static final String ATTR_DESCRIPTION = "desc";
    public static final String ATTR_TIMETO = "tto";
    public static final String ATTR_TIMEFROM = "tfrom";
    public static final String ATTR_DATETO = "dto";
    public static final String ATTR_DATEFROM = "dfrom";
    public static final String ATTR_CAPTION = "caption";
    public static final String ATTR_INDEX = "i";
    public static final String ATTR_SCROLL = "scroll";
    public static final String ATTR_FDOW = "fdow";
    public static final String ATTR_NOW = "now";
    public static final String ATTR_READONLY = "readonly";
    public static final String ATTR_DISABLED = "disabled";
    public static final String ATTR_MONTH_NAMES = "mNames";
    public static final String ATTR_DAY_NAMES = "dNames";
    public static final String ATTR_FORMAT24H = "format24h";
    public static final String ATTR_ALLDAY = "allday";
    public static final String ATTR_NAVIGATION = "navigation";

    private ApplicationConnection client;

    private CalendarDropHandler dropHandler;

    private String PID;

    private final HashMap<String, String> actionMap = new HashMap<String, String>();

    /**
     * 
     */
    public VCalendarPaintable() {

        // Listen to events
        registerListeners();
    }

    /**
     * Registers listeners on the calendar so server can be notified of the
     * events
     */
    protected void registerListeners() {
        setListener(new DateClickListener() {
            public void dateClick(String date) {
                if (!isDisabledOrReadOnly()
                        && getClient().hasEventListeners(VCalendarPaintable.this, CalendarEventId.DATECLICK)) {
                    client.updateVariable(getPaintableId(), CalendarEventId.DATECLICK, date, true);
                }
            }
        });
        setListener(new ForwardListener() {
            public void forward() {
                if (client.hasEventListeners(VCalendarPaintable.this, CalendarEventId.FORWARD)) {
                    client.updateVariable(getPaintableId(), ATTR_NAVIGATION, true, true);
                }
            }
        });
        setListener(new BackwardListener() {
            public void backward() {
                if (client.hasEventListeners(VCalendarPaintable.this, CalendarEventId.BACKWARD)) {
                    client.updateVariable(getPaintableId(), ATTR_NAVIGATION, false, true);
                }
            }
        });
        setListener(new RangeSelectListener() {
            public void rangeSelected(String value) {
                if (client.hasEventListeners(VCalendarPaintable.this, CalendarEventId.RANGESELECT)) {
                    client.updateVariable(getPaintableId(), CalendarEventId.RANGESELECT, value, true);
                }
            }
        });
        setListener(new WeekClickListener() {
            public void weekClick(String event) {
                if (!isDisabledOrReadOnly()
                        && client.hasEventListeners(VCalendarPaintable.this, CalendarEventId.WEEKCLICK)) {
                    client.updateVariable(getPaintableId(), CalendarEventId.WEEKCLICK, event, true);
                }
            }
        });
        setListener(new EventMovedListener() {
            public void eventMoved(CalendarEvent event) {
                if (client.hasEventListeners(VCalendarPaintable.this, CalendarEventId.EVENTMOVE)) {
                    StringBuilder sb = new StringBuilder();
                    sb.append(event.getIndex());
                    sb.append(":");
                    sb.append(DateUtil.formatClientSideDate(event.getStart()));
                    sb.append("-");
                    sb.append(DateUtil.formatClientSideTime(event.getStartTime()));
                    client.updateVariable(getPaintableId(), CalendarEventId.EVENTMOVE, sb.toString(), true);
                }
            }
        });
        setListener(new EventResizeListener() {
            public void eventResized(CalendarEvent event) {
                if (client.hasEventListeners(VCalendarPaintable.this, CalendarEventId.EVENTRESIZE)) {
                    StringBuilder buffer = new StringBuilder();
                    buffer.append(event.getIndex());
                    buffer.append(",");

                    buffer.append(DateUtil.formatClientSideDate(event.getStart()));
                    buffer.append("-");
                    buffer.append(DateUtil.formatClientSideTime(event.getStartTime()));

                    buffer.append(",");

                    buffer.append(DateUtil.formatClientSideDate(event.getEnd()));
                    buffer.append("-");
                    buffer.append(DateUtil.formatClientSideTime(event.getEndTime()));

                    client.updateVariable(getPaintableId(), CalendarEventId.EVENTRESIZE, buffer.toString(), true);
                }
            }
        });
        setListener(new ScrollListener() {
            public void scroll(int scrollPosition) {
                client.updateVariable(getPaintableId(), ATTR_SCROLL, scrollPosition, false);
            }
        });
        setListener(new EventClickListener() {
            public void eventClick(CalendarEvent event) {
                if (client.hasEventListeners(VCalendarPaintable.this, CalendarEventId.EVENTCLICK)) {
                    client.updateVariable(getPaintableId(), CalendarEventId.EVENTCLICK, event.getIndex(), true);
                }
            }
        });
        setListener(new MouseEventListener() {
            public void contextMenu(ContextMenuEvent event, final Widget widget) {
                final NativeEvent ne = event.getNativeEvent();
                int left = ne.getClientX();
                int top = ne.getClientY();
                top += Window.getScrollTop();
                left += Window.getScrollLeft();
                client.getContextMenu().showAt(new ActionOwner() {
                    public String getPaintableId() {
                        return VCalendarPaintable.this.getPaintableId();
                    }

                    public ApplicationConnection getClient() {
                        return VCalendarPaintable.this.getClient();
                    }

                    @SuppressWarnings("deprecation")
                    public Action[] getActions() {
                        if (widget instanceof SimpleDayCell) {
                            /*
                             * Month view
                             */
                            SimpleDayCell cell = (SimpleDayCell) widget;
                            Date start = new Date(cell.getDate().getYear(), cell.getDate().getMonth(),
                                    cell.getDate().getDate(), 0, 0, 0);

                            Date end = new Date(cell.getDate().getYear(), cell.getDate().getMonth(),
                                    cell.getDate().getDate(), 23, 59, 59);

                            return VCalendarPaintable.this.getActionsBetween(start, end);
                        } else if (widget instanceof DateCell) {
                            /*
                             * Week and Day view
                             */
                            DateCell cell = (DateCell) widget;
                            int slotIndex = DOM.getChildIndex(cell.getElement(),
                                    (Element) ne.getEventTarget().cast());
                            DateCellSlot slot = cell.getSlot(slotIndex);
                            return VCalendarPaintable.this.getActionsBetween(slot.getFrom(), slot.getTo());
                        } else if (widget instanceof DayEvent) {
                            /*
                             * Context menu on event
                             */
                            DayEvent dayEvent = (DayEvent) widget;
                            CalendarEvent event = dayEvent.getCalendarEvent();
                            Action[] actions = VCalendarPaintable.this.getActionsBetween(event.getStartTime(),
                                    event.getEndTime());
                            for (Action action : actions) {
                                ((VCalendarAction) action).setEvent(event);
                            }
                            return actions;

                        } else if (widget instanceof MonthEventLabel) {
                            MonthEventLabel mel = (MonthEventLabel) widget;
                            CalendarEvent event = mel.getCalendarEvent();
                            Action[] actions = VCalendarPaintable.this.getActionsBetween(event.getStartTime(),
                                    event.getEndTime());
                            for (Action action : actions) {
                                ((VCalendarAction) action).setEvent(event);
                            }
                            return actions;
                        }
                        return null;
                    }
                }, left, top);
            }
        });
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal
     * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection)
     */
    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
        // This call should be made first. Ensure correct implementation,
        // and let the containing layout manage caption, etc.
        if (client.updateComponent(this, uidl, true)) {
            return;
        }

        // Save reference to server connection object to be able to send
        // user interaction later
        this.client = client;
        PID = uidl.getId();
        set24HFormat(uidl.getBooleanAttribute(ATTR_FORMAT24H));
        setDayNames(uidl.getStringArrayAttribute(ATTR_DAY_NAMES));
        setMonthNames(uidl.getStringArrayAttribute(ATTR_MONTH_NAMES));

        setFirstDayNumber(uidl.getIntAttribute(ATTR_FIRSTDAYOFWEEK));
        setLastDayNumber(uidl.getIntAttribute(ATTR_LASTDAYOFWEEK));

        setFirstHourOfTheDay(uidl.getIntAttribute(ATTR_FIRSTHOUROFDAY));
        setLastHourOfTheDay(uidl.getIntAttribute(ATTR_LASTHOUROFDAY));

        setReadOnly(uidl.hasAttribute(ATTR_READONLY) && uidl.getBooleanAttribute(ATTR_READONLY));

        setDisabled(uidl.hasAttribute(ATTR_DISABLED) && uidl.getBooleanAttribute(ATTR_DISABLED));

        setRangeSelectAllowed(client.hasEventListeners(this, CalendarEventId.RANGESELECT));
        setRangeMoveAllowed(client.hasEventListeners(this, CalendarEventId.EVENTMOVE));
        setEventResizeAllowed(client.hasEventListeners(this, CalendarEventId.EVENTRESIZE));
        setEventMoveAllowed(client.hasEventListeners(this, CalendarEventId.EVENTMOVE));

        UIDL daysUidl = uidl.getChildUIDL(0);
        int daysCount = daysUidl.getChildCount();
        boolean monthView = daysCount > 7;
        if (monthView) {
            updateMonthView(uidl, daysUidl);
        } else {
            updateWeekView(uidl, daysUidl);
        }

        // check for DD -related access criteria
        Iterator<Object> childIterator = uidl.getChildIterator();
        while (childIterator.hasNext()) {
            UIDL child = (UIDL) childIterator.next();

            // Drag&drop
            if (ACCESSCRITERIA.equals(child.getTag())) {
                if (monthView && !(getDropHandler() instanceof CalendarMonthDropHandler)) {
                    setDropHandler(new CalendarMonthDropHandler());

                } else if (!monthView && !(getDropHandler() instanceof CalendarWeekDropHandler)) {
                    setDropHandler(new CalendarWeekDropHandler());
                }

                getDropHandler().setCalendarPaintable(this);
                getDropHandler().updateAcceptRules(child);

            } else {
                setDropHandler(null);
            }

            // Actions
            if ("actions".equals(child.getTag())) {
                updateActionMap(child);
            }
        }
    }

    /**
     * Returns the ApplicationConnection used to connect to the server side
     */
    public ApplicationConnection getClient() {
        return client;
    }

    /** Transforms uidl to list of CalendarEvents */
    protected ArrayList<CalendarEvent> getEvents(UIDL childUIDL) {
        int eventCount = childUIDL.getChildCount();
        ArrayList<CalendarEvent> events = new ArrayList<CalendarEvent>();
        for (int i = 0; i < eventCount; i++) {
            UIDL eventUIDL = childUIDL.getChildUIDL(i);

            int index = eventUIDL.getIntAttribute(ATTR_INDEX);
            String caption = eventUIDL.getStringAttribute(ATTR_CAPTION);
            String datefrom = eventUIDL.getStringAttribute(ATTR_DATEFROM);
            String dateto = eventUIDL.getStringAttribute(ATTR_DATETO);
            String timefrom = eventUIDL.getStringAttribute(ATTR_TIMEFROM);
            String timeto = eventUIDL.getStringAttribute(ATTR_TIMETO);
            String desc = eventUIDL.getStringAttribute(ATTR_DESCRIPTION);
            String style = eventUIDL.getStringAttribute(ATTR_STYLE);
            boolean allDay = eventUIDL.getBooleanAttribute(ATTR_ALLDAY);

            CalendarEvent e = new CalendarEvent();

            e.setCaption(caption);
            e.setDescription(desc);
            e.setIndex(index);
            e.setEnd(dateformat_date.parse(dateto));
            e.setStart(dateformat_date.parse(datefrom));
            e.setStartTime(dateformat_datetime.parse(datefrom + " " + timefrom));
            e.setEndTime(dateformat_datetime.parse(dateto + " " + timeto));
            e.setStyleName(style);
            e.setFormat24h(is24HFormat());
            e.setAllDay(allDay);

            events.add(e);

            registerEventToolTip(e);
        }
        return events;
    }

    /**
     * Register the description of the event as a tooltip for this paintable.
     * This way, any event displaying widget can use the event index as a key to
     * display the tooltip.
     */
    private void registerEventToolTip(CalendarEvent e) {
        if (e.getDescription() != null && !"".equals(e.getDescription())) {
            TooltipInfo info = new TooltipInfo(e.getDescription());
            client.registerTooltip(this, e.getIndex(), info);

        } else {
            client.registerTooltip(this, e.getIndex(), null);
        }
    }

    private List<Day> getDaysFromUIDL(UIDL daysUIDL) {
        List<Day> days = new ArrayList<VCalendar.Day>();
        for (int i = 0; i < daysUIDL.getChildCount(); i++) {
            UIDL dayUidl = daysUIDL.getChildUIDL(i);
            String date = dayUidl.getStringAttribute(ATTR_DATE);
            String localized_date_format = dayUidl.getStringAttribute(ATTR_FDATE);
            int dayOfWeek = dayUidl.getIntAttribute(ATTR_DOW);
            int week = dayUidl.getIntAttribute(ATTR_WEEK);
            days.add(new Day(date, localized_date_format, dayOfWeek, week));
        }
        return days;
    }

    private void updateMonthView(UIDL uidl, UIDL daysUidl) {
        int firstDayOfWeek = uidl.getIntAttribute(ATTR_FDOW);
        Date today = dateformat_datetime.parse(uidl.getStringAttribute(ATTR_NOW));
        super.updateMonthView(firstDayOfWeek, today, daysUidl.getChildCount(), getEvents(uidl.getChildUIDL(1)),
                getDaysFromUIDL(daysUidl));
    }

    private void updateWeekView(UIDL uidl, UIDL daysUidl) {
        int scroll = uidl.getIntVariable(ATTR_SCROLL);
        Date today = dateformat_datetime.parse(uidl.getStringAttribute(ATTR_NOW));
        int daysCount = daysUidl.getChildCount();
        int firstDayOfWeek = uidl.getIntAttribute(ATTR_FDOW);

        super.updateWeekView(scroll, today, daysCount, firstDayOfWeek, getEvents(uidl.getChildUIDL(1)),
                getDaysFromUIDL(daysUidl));
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.vaadin.addon.calendar.gwt.client.ui.GWTCalendar#handleTooltipEvent
     * (com.google.gwt.user.client.Event)
     */
    @Override
    public void handleTooltipEvent(Event event, Object key) {
        if (client != null) {
            client.handleTooltipEvent(event, this, key);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.vaadin.terminal.gwt.client.ui.dd.VHasDropHandler#getDropHandler()
     */
    public CalendarDropHandler getDropHandler() {
        return dropHandler;
    }

    /**
     * Set the drop handler
     * 
     * @param dropHandler
     *            The drophandler to use
     */
    public void setDropHandler(CalendarDropHandler dropHandler) {
        this.dropHandler = dropHandler;
    }

    private Action[] getActionsBetween(Date start, Date end) {
        List<Action> actions = new ArrayList<Action>();
        for (int i = 0; i < actionKeys.size(); i++) {
            final String actionKey = actionKeys.get(i);
            Date actionStartDate;
            Date actionEndDate;
            try {
                actionStartDate = getActionStartDate(actionKey);
                actionEndDate = getActionEndDate(actionKey);
            } catch (ParseException pe) {
                VConsole.error("Failed to parse action date");
                continue;
            }

            boolean startIsValid = start.compareTo(actionStartDate) >= 0;
            boolean endIsValid = end.compareTo(actionEndDate) <= 0;
            if (startIsValid && endIsValid) {
                VCalendarAction a = new VCalendarAction(this, actionKey);
                a.setCaption(getActionCaption(actionKey));
                a.setIconUrl(getActionIcon(actionKey));
                a.setActionStartDate(start);
                a.setActionEndDate(end);
                actions.add(a);
            }
        }

        return actions.toArray(new Action[actions.size()]);
    }

    private List<String> actionKeys = new ArrayList<String>();

    private void updateActionMap(UIDL c) {
        actionMap.clear();
        actionKeys.clear();

        final Iterator<?> it = c.getChildIterator();
        while (it.hasNext()) {
            final UIDL action = (UIDL) it.next();
            final String key = action.getStringAttribute("key");
            final String caption = action.getStringAttribute("caption");
            final String formatted_start = action.getStringAttribute("start");
            final String formatted_end = action.getStringAttribute("end");
            String id = key + "-" + formatted_start + "-" + formatted_end;
            actionMap.put(id + "_c", caption);
            actionMap.put(id + "_s", formatted_start);
            actionMap.put(id + "_e", formatted_end);
            actionKeys.add(id);
            if (action.hasAttribute("icon")) {
                actionMap.put(id + "_i", client.translateVaadinUri(action.getStringAttribute("icon")));
            } else {
                actionMap.remove(id + "_i");
            }
        }
    }

    /**
     * Get the text that is displayed for a context menu item
     * 
     * @param actionKey
     *            The unique action key
     * @return
     */
    public String getActionCaption(String actionKey) {
        return actionMap.get(actionKey + "_c");
    }

    /**
     * Get the icon url for a context menu item
     * 
     * @param actionKey
     *            The unique action key
     * @return
     */
    public String getActionIcon(String actionKey) {
        return actionMap.get(actionKey + "_i");
    }

    /**
     * Get the start date for an action item
     * 
     * @param actionKey
     *            The unique action key
     * @return
     * @throws ParseException
     */
    public Date getActionStartDate(String actionKey) throws ParseException {
        String dateStr = actionMap.get(actionKey + "_s");
        DateTimeFormat formatter = DateTimeFormat.getFormat(VCalendarAction.ACTION_DATE_FORMAT_PATTERN);
        return formatter.parse(dateStr);
    }

    /**
     * Get the end date for an action item
     * 
     * @param actionKey
     *            The unique action key
     * @return
     * @throws ParseException
     */
    public Date getActionEndDate(String actionKey) throws ParseException {
        String dateStr = actionMap.get(actionKey + "_e");
        DateTimeFormat formatter = DateTimeFormat.getFormat(VCalendarAction.ACTION_DATE_FORMAT_PATTERN);
        return formatter.parse(dateStr);
    }

    /**
     * Returns ALL currently registered events. Use {@link #getActions(Date)} to
     * get the actions for a specific date
     */
    public Action[] getActions() {
        List<Action> actions = new ArrayList<Action>();
        for (int i = 0; i < actionKeys.size(); i++) {
            final String actionKey = actionKeys.get(i);
            final VCalendarAction a = new VCalendarAction(this, actionKey);
            a.setCaption(getActionCaption(actionKey));
            a.setIconUrl(getActionIcon(actionKey));

            try {
                a.setActionStartDate(getActionStartDate(actionKey));
                a.setActionEndDate(getActionEndDate(actionKey));
            } catch (ParseException pe) {
                VConsole.error(pe);
            }

            actions.add(a);
        }
        return actions.toArray(new Action[actions.size()]);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.vaadin.terminal.gwt.client.ui.ActionOwner#getPaintableId()
     */
    public String getPaintableId() {
        return PID;
    }

    @Override
    public boolean isForwardNavigationEnabled() {
        return client.hasEventListeners(this, CalendarEventId.FORWARD);
    }

    @Override
    public boolean isBackwardNavigationEnabled() {
        return client.hasEventListeners(this, CalendarEventId.BACKWARD);
    }
}