diff options
author | John Ahlroos <john@vaadin.com> | 2013-03-27 16:33:28 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2013-04-03 08:03:37 +0000 |
commit | 217ba18e53a8607a9e2480574ec1c3da11f4037f (patch) | |
tree | 2c38b306985b77144e0797e8bc83d386c8575aa3 /server/src | |
parent | 1d25d6d6427f94e93e3bf7417aa968aaa9673dab (diff) | |
download | vaadin-framework-217ba18e53a8607a9e2480574ec1c3da11f4037f.tar.gz vaadin-framework-217ba18e53a8607a9e2480574ec1c3da11f4037f.zip |
Integrate Calendar into core #11079
Everything else integrated, except TB3 tests (ticket #11090, old TB2 tests used instead)
Change-Id: If1700d7680a6c0a45f84d6e3c7b80e6536da78c8
Diffstat (limited to 'server/src')
18 files changed, 4467 insertions, 0 deletions
diff --git a/server/src/com/vaadin/ui/Calendar.java b/server/src/com/vaadin/ui/Calendar.java new file mode 100644 index 0000000000..4bf2885a8c --- /dev/null +++ b/server/src/com/vaadin/ui/Calendar.java @@ -0,0 +1,1822 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui; + +import java.lang.reflect.Method; +import java.text.DateFormat; +import java.text.DateFormatSymbols; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.EventListener; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TimeZone; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.vaadin.data.Container; +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.event.Action; +import com.vaadin.event.Action.Handler; +import com.vaadin.event.dd.DropHandler; +import com.vaadin.event.dd.DropTarget; +import com.vaadin.event.dd.TargetDetails; +import com.vaadin.server.KeyMapper; +import com.vaadin.shared.ui.calendar.CalendarEventId; +import com.vaadin.shared.ui.calendar.CalendarServerRpc; +import com.vaadin.shared.ui.calendar.CalendarState; +import com.vaadin.shared.ui.calendar.DateConstants; +import com.vaadin.ui.components.calendar.CalendarComponentEvent; +import com.vaadin.ui.components.calendar.CalendarComponentEvents; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardEvent; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickEvent; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClick; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClickHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventMoveHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResize; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResizeHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardEvent; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.MoveEvent; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.RangeSelectEvent; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.RangeSelectHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClick; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClickHandler; +import com.vaadin.ui.components.calendar.CalendarDateRange; +import com.vaadin.ui.components.calendar.CalendarTargetDetails; +import com.vaadin.ui.components.calendar.ContainerEventProvider; +import com.vaadin.ui.components.calendar.event.BasicEventProvider; +import com.vaadin.ui.components.calendar.event.CalendarEditableEventProvider; +import com.vaadin.ui.components.calendar.event.CalendarEvent; +import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeEvent; +import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeListener; +import com.vaadin.ui.components.calendar.event.CalendarEventProvider; +import com.vaadin.ui.components.calendar.handler.BasicBackwardHandler; +import com.vaadin.ui.components.calendar.handler.BasicDateClickHandler; +import com.vaadin.ui.components.calendar.handler.BasicEventMoveHandler; +import com.vaadin.ui.components.calendar.handler.BasicEventResizeHandler; +import com.vaadin.ui.components.calendar.handler.BasicForwardHandler; +import com.vaadin.ui.components.calendar.handler.BasicWeekClickHandler; + +/** + * <p> + * Vaadin Calendar is for visualizing events in a calendar. Calendar events can + * be visualized in the variable length view depending on the start and end + * dates. + * </p> + * + * <li>You can set the viewable date range with the {@link #setStartDate(Date)} + * and {@link #setEndDate(Date)} methods. Calendar has a default date range of + * one week</li> + * + * <li>Calendar has two kind of views: monthly and weekly view</li> + * + * <li>If date range is seven days or shorter, the weekly view is used.</li> + * + * <li>Calendar queries its events by using a + * {@link com.vaadin.addon.calendar.event.CalendarEventProvider + * CalendarEventProvider}. By default, a + * {@link com.vaadin.addon.calendar.event.BasicEventProvider BasicEventProvider} + * is used.</li> + * + * @since 7.1 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class Calendar extends AbstractComponent implements + CalendarComponentEvents.NavigationNotifier, + CalendarComponentEvents.EventMoveNotifier, + CalendarComponentEvents.RangeSelectNotifier, + CalendarComponentEvents.EventResizeNotifier, + CalendarEventProvider.EventSetChangeListener, DropTarget, + CalendarEditableEventProvider, Action.Container { + + /** + * Calendar can use either 12 hours clock or 24 hours clock. + */ + public enum TimeFormat { + + Format12H(), Format24H(); + } + + /** Defines currently active format for time. 12H/24H. */ + protected TimeFormat currentTimeFormat; + + /** Internal calendar data source. */ + protected java.util.Calendar currentCalendar = java.util.Calendar + .getInstance(); + + /** Defines the component's active time zone. */ + protected TimeZone timezone; + + /** Defines the calendar's date range starting point. */ + protected Date startDate = null; + + /** Defines the calendar's date range ending point. */ + protected Date endDate = null; + + /** Event provider. */ + private CalendarEventProvider calendarEventProvider; + + /** + * Internal buffer for the events that are retrieved from the event + * provider. + */ + protected List<CalendarEvent> events; + + /** Date format that will be used in the UIDL for dates. */ + protected DateFormat df_date = new SimpleDateFormat("yyyy-MM-dd"); + + /** Time format that will be used in the UIDL for time. */ + protected DateFormat df_time = new SimpleDateFormat("HH:mm:ss"); + + /** Date format that will be used in the UIDL for both date and time. */ + protected DateFormat df_date_time = new SimpleDateFormat( + DateConstants.CLIENT_DATE_FORMAT + "-" + + DateConstants.CLIENT_TIME_FORMAT); + + /** + * Week view's scroll position. Client sends updates to this value so that + * scroll position wont reset all the time. + */ + private int scrollTop = 0; + + /** Caption format for the weekly view */ + private String weeklyCaptionFormat = null; + + /** Map from event ids to event handlers */ + private final Map<String, EventListener> handlers; + + /** + * Drop Handler for Vaadin DD. By default null. + */ + private DropHandler dropHandler; + + /** + * First day to show for a week + */ + private int firstDay = 1; + + /** + * Last day to show for a week + */ + private int lastDay = 7; + + /** + * First hour to show for a day + */ + private int firstHour = 0; + + /** + * Last hour to show for a day + */ + private int lastHour = 23; + + /** + * List of action handlers. + */ + private LinkedList<Action.Handler> actionHandlers = null; + + /** + * Action mapper. + */ + private KeyMapper<Action> actionMapper = null; + + /** + * + */ + private CalendarServerRpcImpl rpc = new CalendarServerRpcImpl(); + + /** + * Returns the logger for the calendar + */ + protected Logger getLogger() { + return Logger.getLogger(Calendar.class.getName()); + } + + /** + * Construct a Vaadin Calendar with a BasicEventProvider and no caption. + * Default date range is one week. + */ + public Calendar() { + this(null, new BasicEventProvider()); + } + + /** + * Construct a Vaadin Calendar with a BasicEventProvider and the provided + * caption. Default date range is one week. + * + * @param caption + */ + public Calendar(String caption) { + this(caption, new BasicEventProvider()); + } + + /** + * <p> + * Construct a Vaadin Calendar with event provider. Event provider is + * obligatory, because calendar component will query active events through + * it. + * </p> + * + * <p> + * By default, Vaadin Calendar will show dates from the start of the current + * week to the end of the current week. Use {@link #setStartDate(Date)} and + * {@link #setEndDate(Date)} to change this. + * </p> + * + * @param eventProvider + * Event provider, cannot be null. + */ + public Calendar(CalendarEventProvider eventProvider) { + this(null, eventProvider); + } + + /** + * <p> + * Construct a Vaadin Calendar with event provider and a caption. Event + * provider is obligatory, because calendar component will query active + * events through it. + * </p> + * + * <p> + * By default, Vaadin Calendar will show dates from the start of the current + * week to the end of the current week. Use {@link #setStartDate(Date)} and + * {@link #setEndDate(Date)} to change this. + * </p> + * + * @param eventProvider + * Event provider, cannot be null. + */ + // this is the constructor every other constructor calls + public Calendar(String caption, CalendarEventProvider eventProvider) { + registerRpc(rpc); + setCaption(caption); + handlers = new HashMap<String, EventListener>(); + setDefaultHandlers(); + currentCalendar.setTime(new Date()); + setEventProvider(eventProvider); + getState().firstDayOfWeek = firstDay; + getState().lastVisibleDayOfWeek = lastDay; + getState().firstHourOfDay = firstHour; + getState().lastHourOfDay = lastHour; + setTimeFormat(null); + + } + + @Override + public CalendarState getState() { + return (CalendarState) super.getState(); + } + + @Override + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); + + initCalendarWithLocale(); + + getState().format24H = TimeFormat.Format24H == getTimeFormat(); + setupDaysAndActions(); + setupCalendarEvents(); + rpc.scroll(scrollTop); + } + + /** + * Set all the wanted default handlers here. This is always called after + * constructing this object. All other events have default handlers except + * range and event click. + */ + protected void setDefaultHandlers() { + setHandler(new BasicBackwardHandler()); + setHandler(new BasicForwardHandler()); + setHandler(new BasicWeekClickHandler()); + setHandler(new BasicDateClickHandler()); + setHandler(new BasicEventMoveHandler()); + setHandler(new BasicEventResizeHandler()); + } + + /** + * Gets the calendar's start date. + * + * @return First visible date. + */ + public Date getStartDate() { + if (startDate == null) { + currentCalendar.set(java.util.Calendar.DAY_OF_WEEK, + currentCalendar.getFirstDayOfWeek()); + return currentCalendar.getTime(); + } + return startDate; + } + + /** + * Sets start date for the calendar. This and {@link #setEndDate(Date)} + * control the range of dates visible on the component. The default range is + * one week. + * + * @param date + * First visible date to show. + */ + public void setStartDate(Date date) { + if (!date.equals(startDate)) { + startDate = date; + markAsDirty(); + } + } + + /** + * Gets the calendar's end date. + * + * @return Last visible date. + */ + public Date getEndDate() { + if (endDate == null) { + currentCalendar.set(java.util.Calendar.DAY_OF_WEEK, + currentCalendar.getFirstDayOfWeek() + 6); + return currentCalendar.getTime(); + } + return endDate; + } + + /** + * Sets end date for the calendar. Starting from startDate, only six weeks + * will be shown if duration to endDate is longer than six weeks. + * + * This and {@link #setStartDate(Date)} control the range of dates visible + * on the component. The default range is one week. + * + * @param date + * Last visible date to show. + */ + public void setEndDate(Date date) { + if (startDate != null && startDate.after(date)) { + startDate = (Date) date.clone(); + markAsDirty(); + } else if (!date.equals(endDate)) { + endDate = date; + markAsDirty(); + } + } + + /** + * Sets the locale to be used in the Calendar component. + * + * @see com.vaadin.ui.AbstractComponent#setLocale(java.util.Locale) + */ + @Override + public void setLocale(Locale newLocale) { + super.setLocale(newLocale); + initCalendarWithLocale(); + } + + /** + * Initialize the java calendar instance with the current locale and + * timezone. + */ + private void initCalendarWithLocale() { + if (timezone != null) { + currentCalendar = java.util.Calendar.getInstance(timezone, + getLocale()); + + } else { + currentCalendar = java.util.Calendar.getInstance(getLocale()); + } + } + + private void setupCalendarEvents() { + int durationInDays = (int) (((endDate.getTime()) - startDate.getTime()) / DateConstants.DAYINMILLIS); + durationInDays++; + if (durationInDays > 60) { + throw new RuntimeException("Daterange is too big (max 60) = " + + durationInDays); + } + + Date firstDateToShow = expandStartDate(startDate, durationInDays > 7); + Date lastDateToShow = expandEndDate(endDate, durationInDays > 7); + + currentCalendar.setTime(firstDateToShow); + events = getEventProvider().getEvents(firstDateToShow, lastDateToShow); + + List<CalendarState.Event> calendarStateEvents = new ArrayList<CalendarState.Event>(); + if (events != null) { + for (int i = 0; i < events.size(); i++) { + CalendarEvent e = events.get(i); + CalendarState.Event event = new CalendarState.Event(); + event.index = i; + event.caption = e.getCaption() == null ? "" : e.getCaption(); + event.dateFrom = df_date.format(e.getStart()); + event.dateTo = df_date.format(e.getEnd()); + event.timeFrom = df_time.format(e.getStart()); + event.timeTo = df_time.format(e.getEnd()); + event.description = e.getDescription() == null ? "" : e + .getDescription(); + event.styleName = e.getStyleName() == null ? "" : e + .getStyleName(); + event.allDay = e.isAllDay(); + calendarStateEvents.add(event); + } + } + getState().events = calendarStateEvents; + } + + private void setupDaysAndActions() { + // Make sure we have a up-to-date locale + initCalendarWithLocale(); + + CalendarState state = getState(); + + state.firstDayOfWeek = currentCalendar.getFirstDayOfWeek(); + + // If only one is null, throw exception + // If both are null, set defaults + if (startDate == null ^ endDate == null) { + String message = "Schedule cannot be painted without a proper date range.\n"; + if (startDate == null) { + throw new IllegalStateException(message + + "You must set a start date using setStartDate(Date)."); + + } else { + throw new IllegalStateException(message + + "You must set an end date using setEndDate(Date)."); + } + + } else if (startDate == null && endDate == null) { + // set defaults + startDate = getStartDate(); + endDate = getEndDate(); + } + + int durationInDays = (int) (((endDate.getTime()) - startDate.getTime()) / DateConstants.DAYINMILLIS); + durationInDays++; + if (durationInDays > 60) { + throw new RuntimeException("Daterange is too big (max 60) = " + + durationInDays); + } + + state.dayNames = getDayNamesShort(); + state.monthNames = getMonthNamesShort(); + + // Use same timezone in all dates this component handles. + // Show "now"-marker in browser within given timezone. + Date now = new Date(); + currentCalendar.setTime(now); + now = currentCalendar.getTime(); + + // Reset time zones for custom date formats + df_date.setTimeZone(currentCalendar.getTimeZone()); + df_time.setTimeZone(currentCalendar.getTimeZone()); + + state.now = (df_date.format(now) + " " + df_time.format(now)); + + Date firstDateToShow = expandStartDate(startDate, durationInDays > 7); + Date lastDateToShow = expandEndDate(endDate, durationInDays > 7); + + currentCalendar.setTime(firstDateToShow); + + DateFormat weeklyCaptionFormatter = getWeeklyCaptionFormatter(); + weeklyCaptionFormatter.setTimeZone(currentCalendar.getTimeZone()); + + Map<CalendarDateRange, Set<Action>> actionMap = new HashMap<CalendarDateRange, Set<Action>>(); + + List<CalendarState.Day> days = new ArrayList<CalendarState.Day>(); + + // Send all dates to client from server. This + // approach was taken because gwt doesn't + // support date localization properly. + while (currentCalendar.getTime().compareTo(lastDateToShow) < 1) { + final Date date = currentCalendar.getTime(); + final CalendarState.Day day = new CalendarState.Day(); + day.date = df_date.format(date); + day.localizedDateFormat = weeklyCaptionFormatter.format(date); + day.dayOfWeek = getDowByLocale(currentCalendar); + day.week = currentCalendar.get(java.util.Calendar.WEEK_OF_YEAR); + + days.add(day); + + // Get actions for a specific date + if (actionHandlers != null) { + for (Action.Handler actionHandler : actionHandlers) { + + // Create calendar which omits time + GregorianCalendar cal = new GregorianCalendar( + getTimeZone(), getLocale()); + cal.clear(); + cal.set(currentCalendar.get(java.util.Calendar.YEAR), + currentCalendar.get(java.util.Calendar.MONTH), + currentCalendar.get(java.util.Calendar.DATE)); + + // Get day start and end times + Date start = cal.getTime(); + cal.add(java.util.Calendar.DATE, 1); + Date end = cal.getTime(); + + boolean monthView = (durationInDays > 7); + + /** + * If in day or week view add actions for each half-an-hour. + * If in month view add actions for each day + */ + if (monthView) { + setActionsForDay(actionMap, start, end, actionHandler); + } else { + setActionsForEachHalfHour(actionMap, start, end, + actionHandler); + } + + } + } + + currentCalendar.add(java.util.Calendar.DATE, 1); + } + state.days = days; + state.actions = createActionsList(actionMap); + } + + private void setActionsForEachHalfHour( + Map<CalendarDateRange, Set<Action>> actionMap, Date start, + Date end, Action.Handler actionHandler) { + GregorianCalendar cal = new GregorianCalendar(getTimeZone(), + getLocale()); + cal.setTime(start); + while (cal.getTime().before(end)) { + Date s = cal.getTime(); + cal.add(java.util.Calendar.MINUTE, 30); + Date e = cal.getTime(); + CalendarDateRange range = new CalendarDateRange(s, e, getTimeZone()); + Action[] actions = actionHandler.getActions(range, this); + if (actions != null) { + Set<Action> actionSet = new HashSet<Action>( + Arrays.asList(actions)); + actionMap.put(range, actionSet); + } + } + } + + private void setActionsForDay( + Map<CalendarDateRange, Set<Action>> actionMap, Date start, + Date end, Action.Handler actionHandler) { + CalendarDateRange range = new CalendarDateRange(start, end, + getTimeZone()); + Action[] actions = actionHandler.getActions(range, this); + if (actions != null) { + Set<Action> actionSet = new HashSet<Action>(Arrays.asList(actions)); + actionMap.put(range, actionSet); + } + } + + private List<CalendarState.Action> createActionsList( + Map<CalendarDateRange, Set<Action>> actionMap) { + if (actionMap.isEmpty()) { + return null; + } + + List<CalendarState.Action> calendarActions = new ArrayList<CalendarState.Action>(); + + SimpleDateFormat formatter = new SimpleDateFormat( + DateConstants.ACTION_DATE_FORMAT_PATTERN); + formatter.setTimeZone(getTimeZone()); + + for (Entry<CalendarDateRange, Set<Action>> entry : actionMap.entrySet()) { + CalendarDateRange range = entry.getKey(); + Set<Action> actions = entry.getValue(); + for (Action action : actions) { + String key = actionMapper.key(action); + CalendarState.Action calendarAction = new CalendarState.Action(); + calendarAction.actionKey = key; + calendarAction.caption = action.getCaption(); + setResource(key, action.getIcon()); + calendarAction.iconKey = key; + calendarAction.startDate = formatter.format(range.getStart()); + calendarAction.endDate = formatter.format(range.getEnd()); + calendarActions.add(calendarAction); + } + } + + return calendarActions; + } + + /** + * Gets currently active time format. Value is either TimeFormat.Format12H + * or TimeFormat.Format24H. + * + * @return TimeFormat Format for the time. + */ + public TimeFormat getTimeFormat() { + if (currentTimeFormat == null) { + SimpleDateFormat f = (SimpleDateFormat) SimpleDateFormat + .getTimeInstance(SimpleDateFormat.SHORT, getLocale()); + String p = f.toPattern(); + if (p.indexOf("HH") != -1 || p.indexOf("H") != -1) { + return TimeFormat.Format24H; + } + return TimeFormat.Format12H; + } + return currentTimeFormat; + } + + /** + * Example: <code>setTimeFormat(TimeFormat.Format12H);</code></br> Set to + * null, if you want the format being defined by the locale. + * + * @param format + * Set 12h or 24h format. Default is defined by the locale. + */ + public void setTimeFormat(TimeFormat format) { + currentTimeFormat = format; + markAsDirty(); + } + + /** + * Returns a time zone that is currently used by this component. + * + * @return Component's Time zone + */ + public TimeZone getTimeZone() { + if (timezone == null) { + return currentCalendar.getTimeZone(); + } + return timezone; + } + + /** + * Set time zone that this component will use. Null value sets the default + * time zone. + * + * @param zone + * Time zone to use + */ + public void setTimeZone(TimeZone zone) { + timezone = zone; + if (!currentCalendar.getTimeZone().equals(zone)) { + if (zone == null) { + zone = TimeZone.getDefault(); + } + currentCalendar.setTimeZone(zone); + df_date_time.setTimeZone(zone); + markAsDirty(); + } + } + + /** + * Get the internally used Calendar instance. This is the currently used + * instance of {@link java.util.Calendar} but is bound to change during the + * lifetime of the component. + * + * @return the currently used java calendar + */ + public java.util.Calendar getInternalCalendar() { + return currentCalendar; + } + + /** + * <p> + * This method restricts the weekdays that are shown. This affects both the + * monthly and the weekly view. The general contract is that <b>firstDay < + * lastDay</b>. + * </p> + * + * <p> + * Note that this only affects the rendering process. Events are still + * requested by the dates set by {@link #setStartDate(Date)} and + * {@link #setEndDate(Date)}. + * </p> + * + * @param firstDay + * the first day of the week to show, between 1 and 7 + */ + public void setFirstVisibleDayOfWeek(int firstDay) { + if (this.firstDay != firstDay && firstDay >= 1 && firstDay <= 7 + && getLastVisibleDayOfWeek() >= firstDay) { + this.firstDay = firstDay; + getState().firstVisibleDayOfWeek = firstDay; + } + } + + /** + * Get the first visible day of the week. Returns the weekdays as integers + * represented by {@link java.util.Calendar#DAY_OF_WEEK} + * + * @return An integer representing the week day according to + * {@link java.util.Calendar#DAY_OF_WEEK} + */ + public int getFirstVisibleDayOfWeek() { + return firstDay; + } + + /** + * <p> + * This method restricts the weekdays that are shown. This affects both the + * monthly and the weekly view. The general contract is that <b>firstDay < + * lastDay</b>. + * </p> + * + * <p> + * Note that this only affects the rendering process. Events are still + * requested by the dates set by {@link #setStartDate(Date)} and + * {@link #setEndDate(Date)}. + * </p> + * + * @param lastDay + * the first day of the week to show, between 1 and 7 + */ + public void setLastVisibleDayOfWeek(int lastDay) { + if (this.lastDay != lastDay && lastDay >= 1 && lastDay <= 7 + && getFirstVisibleDayOfWeek() <= lastDay) { + this.lastDay = lastDay; + getState().lastVisibleDayOfWeek = lastDay; + } + } + + /** + * Get the last visible day of the week. Returns the weekdays as integers + * represented by {@link java.util.Calendar#DAY_OF_WEEK} + * + * @return An integer representing the week day according to + * {@link java.util.Calendar#DAY_OF_WEEK} + */ + public int getLastVisibleDayOfWeek() { + return lastDay; + } + + /** + * <p> + * This method restricts the hours that are shown per day. This affects the + * weekly view. The general contract is that <b>firstHour < lastHour</b>. + * </p> + * + * <p> + * Note that this only affects the rendering process. Events are still + * requested by the dates set by {@link #setStartDate(Date)} and + * {@link #setEndDate(Date)}. + * </p> + * + * @param firstHour + * the first hour of the day to show, between 0 and 23 + */ + public void setFirstVisibleHourOfDay(int firstHour) { + if (this.firstHour != firstHour && firstHour >= 0 && firstHour <= 23 + && firstHour <= getLastVisibleHourOfDay()) { + this.firstHour = firstHour; + getState().firstHourOfDay = firstHour; + } + } + + /** + * Returns the first visible hour in the week view. Returns the hour using a + * 24h time format + * + */ + public int getFirstVisibleHourOfDay() { + return firstHour; + } + + /** + * <p> + * This method restricts the hours that are shown per day. This affects the + * weekly view. The general contract is that <b>firstHour < lastHour</b>. + * </p> + * + * <p> + * Note that this only affects the rendering process. Events are still + * requested by the dates set by {@link #setStartDate(Date)} and + * {@link #setEndDate(Date)}. + * </p> + * + * @param lastHour + * the first hour of the day to show, between 0 and 23 + */ + public void setLastVisibleHourOfDay(int lastHour) { + if (this.lastHour != lastHour && lastHour >= 0 && lastHour <= 23 + && lastHour >= getFirstVisibleHourOfDay()) { + this.lastHour = lastHour; + getState().lastHourOfDay = lastHour; + } + } + + /** + * Returns the last visible hour in the week view. Returns the hour using a + * 24h time format + * + */ + public int getLastVisibleHourOfDay() { + return lastHour; + } + + /** + * Gets the date caption format for the weekly view. + * + * @return The pattern used in caption of dates in weekly view. + */ + public String getWeeklyCaptionFormat() { + return weeklyCaptionFormat; + } + + /** + * Sets custom date format for the weekly view. This is the caption of the + * date. Format could be like "mmm MM/dd". + * + * @param dateFormatPattern + * The date caption pattern. + */ + public void setWeeklyCaptionFormat(String dateFormatPattern) { + if ((weeklyCaptionFormat == null && dateFormatPattern != null) + || (weeklyCaptionFormat != null && !weeklyCaptionFormat + .equals(dateFormatPattern))) { + weeklyCaptionFormat = dateFormatPattern; + markAsDirty(); + } + } + + private DateFormat getWeeklyCaptionFormatter() { + if (weeklyCaptionFormat != null) { + return new SimpleDateFormat(weeklyCaptionFormat, getLocale()); + } else { + return SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT, + getLocale()); + } + } + + /** + * Get the day of week by the given calendar and its locale + * + * @param calendar + * The calendar to use + * @return + */ + private static int getDowByLocale(java.util.Calendar calendar) { + int fow = calendar.get(java.util.Calendar.DAY_OF_WEEK); + + // monday first + if (calendar.getFirstDayOfWeek() == java.util.Calendar.MONDAY) { + fow = (fow == java.util.Calendar.SUNDAY) ? 7 : fow - 1; + } + + return fow; + } + + /** + * Is the user allowed to trigger events which alters the events + * + * @return true if the client is allowed to send changes to server + * @see #isEventClickAllowed() + */ + protected boolean isClientChangeAllowed() { + return !isReadOnly() && isEnabled(); + } + + /** + * Is the user allowed to trigger click events + * + * @return true if the client is allowed to click events + * @see #isClientChangeAllowed() + */ + protected boolean isEventClickAllowed() { + return isEnabled(); + } + + /** + * Fires an event when the user selecing moving forward/backward in the + * calendar. + * + * @param forward + * True if the calendar moved forward else backward is assumed. + */ + protected void fireNavigationEvent(boolean forward) { + if (forward) { + fireEvent(new ForwardEvent(this)); + } else { + fireEvent(new BackwardEvent(this)); + } + } + + /** + * Fires an event move event to all server side move listerners + * + * @param index + * The index of the event in the events list + * @param newFromDatetime + * The changed from date time + */ + protected void fireEventMove(int index, Date newFromDatetime) { + MoveEvent event = new MoveEvent(this, events.get(index), + newFromDatetime); + + if (calendarEventProvider instanceof EventMoveHandler) { + // Notify event provider if it is an event move handler + ((EventMoveHandler) calendarEventProvider).eventMove(event); + } + + // Notify event move handler attached by using the + // setHandler(EventMoveHandler) method + fireEvent(event); + } + + /** + * Fires event when a week was clicked in the calendar. + * + * @param week + * The week that was clicked + * @param year + * The year of the week + */ + protected void fireWeekClick(int week, int year) { + fireEvent(new WeekClick(this, week, year)); + } + + /** + * Fires event when a date was clicked in the calendar. Uses an existing + * event from the event cache. + * + * @param index + * The index of the event in the event cache. + */ + protected void fireEventClick(Integer index) { + fireEvent(new EventClick(this, events.get(index))); + } + + /** + * Fires event when a date was clicked in the calendar. Creates a new event + * for the date and passes it to the listener. + * + * @param date + * The date and time that was clicked + */ + protected void fireDateClick(Date date) { + fireEvent(new DateClickEvent(this, date)); + } + + /** + * Fires an event range selected event. The event is fired when a user + * highlights an area in the calendar. The highlighted areas start and end + * dates are returned as arguments. + * + * @param from + * The start date and time of the highlighted area + * @param to + * The end date and time of the highlighted area + * @param monthlyMode + * Is the calendar in monthly mode + */ + protected void fireRangeSelect(Date from, Date to, boolean monthlyMode) { + fireEvent(new RangeSelectEvent(this, from, to, monthlyMode)); + } + + /** + * Fires an event resize event. The event is fired when a user resizes the + * event in the calendar causing the time range of the event to increase or + * decrease. The new start and end times are returned as arguments to this + * method. + * + * @param index + * The index of the event in the event cache + * @param startTime + * The new start date and time of the event + * @param endTime + * The new end date and time of the event + */ + protected void fireEventResize(int index, Date startTime, Date endTime) { + EventResize event = new EventResize(this, events.get(index), startTime, + endTime); + + if (calendarEventProvider instanceof EventResizeHandler) { + // Notify event provider if it is an event resize handler + ((EventResizeHandler) calendarEventProvider).eventResize(event); + } + + // Notify event resize handler attached by using the + // setHandler(EventMoveHandler) method + fireEvent(event); + } + + /** + * Localized display names for week days starting from sunday. Returned + * array's length is always 7. + * + * @return Array of localized weekday names. + */ + protected String[] getDayNamesShort() { + DateFormatSymbols s = new DateFormatSymbols(getLocale()); + return Arrays.copyOfRange(s.getWeekdays(), 1, 8); + } + + /** + * Localized display names for months starting from January. Returned + * array's length is always 12. + * + * @return Array of localized month names. + */ + protected String[] getMonthNamesShort() { + DateFormatSymbols s = new DateFormatSymbols(getLocale()); + return Arrays.copyOf(s.getShortMonths(), 12); + } + + /** + * Gets a date that is first day in the week that target given date belongs + * to. + * + * @param date + * Target date + * @return Date that is first date in same week that given date is. + */ + protected Date getFirstDateForWeek(Date date) { + int firstDayOfWeek = currentCalendar.getFirstDayOfWeek(); + currentCalendar.setTime(date); + while (firstDayOfWeek != currentCalendar + .get(java.util.Calendar.DAY_OF_WEEK)) { + currentCalendar.add(java.util.Calendar.DATE, -1); + } + return currentCalendar.getTime(); + } + + /** + * Gets a date that is last day in the week that target given date belongs + * to. + * + * @param date + * Target date + * @return Date that is last date in same week that given date is. + */ + protected Date getLastDateForWeek(Date date) { + currentCalendar.setTime(date); + currentCalendar.add(java.util.Calendar.DATE, 1); + int firstDayOfWeek = currentCalendar.getFirstDayOfWeek(); + // Roll to weeks last day using firstdayofweek. Roll until FDofW is + // found and then roll back one day. + while (firstDayOfWeek != currentCalendar + .get(java.util.Calendar.DAY_OF_WEEK)) { + currentCalendar.add(java.util.Calendar.DATE, 1); + } + currentCalendar.add(java.util.Calendar.DATE, -1); + return currentCalendar.getTime(); + } + + /** + * Calculates the end time of the day using the given calendar and date + * + * @param date + * @param calendar + * the calendar instance to be used in the calculation. The given + * instance is unchanged in this operation. + * @return the given date, with time set to the end of the day + */ + private static Date getEndOfDay(java.util.Calendar calendar, Date date) { + java.util.Calendar calendarClone = (java.util.Calendar) calendar + .clone(); + + calendarClone.setTime(date); + calendarClone.set(java.util.Calendar.MILLISECOND, + calendarClone.getActualMaximum(java.util.Calendar.MILLISECOND)); + calendarClone.set(java.util.Calendar.SECOND, + calendarClone.getActualMaximum(java.util.Calendar.SECOND)); + calendarClone.set(java.util.Calendar.MINUTE, + calendarClone.getActualMaximum(java.util.Calendar.MINUTE)); + calendarClone.set(java.util.Calendar.HOUR, + calendarClone.getActualMaximum(java.util.Calendar.HOUR)); + calendarClone.set(java.util.Calendar.HOUR_OF_DAY, + calendarClone.getActualMaximum(java.util.Calendar.HOUR_OF_DAY)); + + return calendarClone.getTime(); + } + + /** + * Calculates the end time of the day using the given calendar and date + * + * @param date + * @param calendar + * the calendar instance to be used in the calculation. The given + * instance is unchanged in this operation. + * @return the given date, with time set to the end of the day + */ + private static Date getStartOfDay(java.util.Calendar calendar, Date date) { + java.util.Calendar calendarClone = (java.util.Calendar) calendar + .clone(); + + calendarClone.setTime(date); + calendarClone.set(java.util.Calendar.MILLISECOND, 0); + calendarClone.set(java.util.Calendar.SECOND, 0); + calendarClone.set(java.util.Calendar.MINUTE, 0); + calendarClone.set(java.util.Calendar.HOUR, 0); + calendarClone.set(java.util.Calendar.HOUR_OF_DAY, 0); + + return calendarClone.getTime(); + } + + /** + * Finds the first day of the week and returns a day representing the start + * of that day + * + * @param start + * The actual date + * @param expandToFullWeek + * Should the returned date be moved to the start of the week + * @return If expandToFullWeek is set then it returns the first day of the + * week, else it returns a clone of the actual date with the time + * set to the start of the day + */ + protected Date expandStartDate(Date start, boolean expandToFullWeek) { + // If the duration is more than week, use monthly view and get startweek + // and endweek. Example if views daterange is from tuesday to next weeks + // wednesday->expand to monday to nextweeks sunday. If firstdayofweek = + // monday + if (expandToFullWeek) { + start = getFirstDateForWeek(start); + + } else { + start = (Date) start.clone(); + } + + // Always expand to the start of the first day to the end of the last + // day + start = getStartOfDay(currentCalendar, start); + + return start; + } + + /** + * Finds the last day of the week and returns a day representing the end of + * that day + * + * @param end + * The actual date + * @param expandToFullWeek + * Should the returned date be moved to the end of the week + * @return If expandToFullWeek is set then it returns the last day of the + * week, else it returns a clone of the actual date with the time + * set to the end of the day + */ + protected Date expandEndDate(Date end, boolean expandToFullWeek) { + // If the duration is more than week, use monthly view and get startweek + // and endweek. Example if views daterange is from tuesday to next weeks + // wednesday->expand to monday to nextweeks sunday. If firstdayofweek = + // monday + if (expandToFullWeek) { + end = getLastDateForWeek(end); + + } else { + end = (Date) end.clone(); + } + + // Always expand to the start of the first day to the end of the last + // day + end = getEndOfDay(currentCalendar, end); + + return end; + } + + /** + * Set the {@link com.vaadin.addon.calendar.event.CalendarEventProvider + * CalendarEventProvider} to be used with this calendar. The EventProvider + * is used to query for events to show, and must be non-null. By default a + * {@link com.vaadin.addon.calendar.event.BasicEventProvider + * BasicEventProvider} is used. + * + * @param calendarEventProvider + * the calendarEventProvider to set. Cannot be null. + */ + public void setEventProvider(CalendarEventProvider calendarEventProvider) { + if (calendarEventProvider == null) { + throw new IllegalArgumentException( + "Calendar event provider cannot be null"); + } + + // remove old listener + if (getEventProvider() instanceof EventSetChangeNotifier) { + ((EventSetChangeNotifier) getEventProvider()).removeEventSetChangeListener(this); + } + + this.calendarEventProvider = calendarEventProvider; + + // add new listener + if (calendarEventProvider instanceof EventSetChangeNotifier) { + ((EventSetChangeNotifier) calendarEventProvider).addEventSetChangeListener(this); + } + } + + /** + * @return the {@link com.vaadin.addon.calendar.event.CalendarEventProvider + * CalendarEventProvider} currently used + */ + public CalendarEventProvider getEventProvider() { + return calendarEventProvider; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarEvents.EventChangeListener#eventChange + * (com.vaadin.addon.calendar.ui.CalendarEvents.EventChange) + */ + public void eventSetChange(EventSetChangeEvent changeEvent) { + // sanity check + if (calendarEventProvider == changeEvent.getProvider()) { + markAsDirty(); + } + } + + /** + * Set the handler for the given type information. Mirrors + * {@link #addListener(String, Class, Object, Method) addListener} from + * AbstractComponent + * + * @param eventId + * A unique id for the event. Usually one of + * {@link CalendarEventId} + * @param eventType + * The class of the event, most likely a subclass of + * {@link CalendarComponentEvent} + * @param listener + * A listener that listens to the given event + * @param listenerMethod + * The method on the lister to call when the event is triggered + */ + protected void setHandler(String eventId, Class<?> eventType, + EventListener listener, Method listenerMethod) { + if (handlers.get(eventId) != null) { + removeListener(eventId, eventType, handlers.get(eventId)); + handlers.remove(eventId); + } + + if (listener != null) { + addListener(eventId, eventType, listener, listenerMethod); + handlers.put(eventId, listener); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.ForwardHandler) + */ + public void setHandler(ForwardHandler listener) { + setHandler(ForwardEvent.EVENT_ID, ForwardEvent.class, listener, + ForwardHandler.forwardMethod); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.BackwardHandler) + */ + public void setHandler(BackwardHandler listener) { + setHandler(BackwardEvent.EVENT_ID, BackwardEvent.class, listener, + BackwardHandler.backwardMethod); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.DateClickHandler) + */ + public void setHandler(DateClickHandler listener) { + setHandler(DateClickEvent.EVENT_ID, DateClickEvent.class, listener, + DateClickHandler.dateClickMethod); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventClickHandler) + */ + public void setHandler(EventClickHandler listener) { + setHandler(EventClick.EVENT_ID, EventClick.class, listener, + EventClickHandler.eventClickMethod); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.WeekClickHandler) + */ + public void setHandler(WeekClickHandler listener) { + setHandler(WeekClick.EVENT_ID, WeekClick.class, listener, + WeekClickHandler.weekClickMethod); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeHandler + * ) + */ + public void setHandler(EventResizeHandler listener) { + setHandler(EventResize.EVENT_ID, EventResize.class, listener, + EventResizeHandler.eventResizeMethod); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.RangeSelectNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.RangeSelectHandler + * ) + */ + public void setHandler(RangeSelectHandler listener) { + setHandler(RangeSelectEvent.EVENT_ID, RangeSelectEvent.class, listener, + RangeSelectHandler.rangeSelectMethod); + + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveHandler) + */ + public void setHandler(EventMoveHandler listener) { + setHandler(MoveEvent.EVENT_ID, MoveEvent.class, listener, + EventMoveHandler.eventMoveMethod); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.CalendarEventNotifier + * #getHandler(java.lang.String) + */ + public EventListener getHandler(String eventId) { + return handlers.get(eventId); + } + + /** + * Get the currently active drop handler + */ + public DropHandler getDropHandler() { + return dropHandler; + } + + /** + * Set the drop handler for the calendar See {@link DropHandler} for + * implementation details. + * + * @param dropHandler + * The drop handler to set + */ + public void setDropHandler(DropHandler dropHandler) { + this.dropHandler = dropHandler; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.event.dd.DropTarget#translateDropTargetDetails(java.util.Map) + */ + public TargetDetails translateDropTargetDetails( + Map<String, Object> clientVariables) { + Map<String, Object> serverVariables = new HashMap<String, Object>(1); + + if (clientVariables.containsKey("dropSlotIndex")) { + int slotIndex = (Integer) clientVariables.get("dropSlotIndex"); + int dayIndex = (Integer) clientVariables.get("dropDayIndex"); + + currentCalendar.setTime(getStartOfDay(currentCalendar, startDate)); + currentCalendar.add(java.util.Calendar.DATE, dayIndex); + + // change this if slot length is modified + currentCalendar.add(java.util.Calendar.MINUTE, slotIndex * 30); + + serverVariables.put("dropTime", currentCalendar.getTime()); + + } else { + int dayIndex = (Integer) clientVariables.get("dropDayIndex"); + currentCalendar.setTime(expandStartDate(startDate, true)); + currentCalendar.add(java.util.Calendar.DATE, dayIndex); + serverVariables.put("dropDay", currentCalendar.getTime()); + } + + CalendarTargetDetails td = new CalendarTargetDetails(serverVariables, + this); + td.setHasDropTime(clientVariables.containsKey("dropSlotIndex")); + + return td; + } + + /** + * Sets a container as a data source for the events in the calendar. + * Equivalent for doing + * <code>Calendar.setEventProvider(new ContainerEventProvider(container))</code> + * + * Use this method if you are adding a container which uses the default + * property ids like {@link BeanItemContainer} for instance. If you are + * using custom properties instead use + * {@link Calendar#setContainerDataSource(com.vaadin.data.Container.Indexed, Object, Object, Object, Object, Object)} + * + * Please note that the container must be sorted by date! + * + * @param container + * The container to use as a datasource + */ + public void setContainerDataSource(Container.Indexed container) { + ContainerEventProvider provider = new ContainerEventProvider(container); + provider.addEventSetChangeListener(new CalendarEventProvider.EventSetChangeListener() { + public void eventSetChange(EventSetChangeEvent changeEvent) { + // Repaint if events change + markAsDirty(); + } + }); + provider.addEventChangeListener(new EventChangeListener() { + public void eventChange(EventChangeEvent changeEvent) { + // Repaint if event changes + markAsDirty(); + } + }); + setEventProvider(provider); + } + + /** + * Sets a container as a data source for the events in the calendar. + * Equivalent for doing + * <code>Calendar.setEventProvider(new ContainerEventProvider(container))</code> + * + * Please note that the container must be sorted by date! + * + * @param container + * The container to use as a data source + * @param captionProperty + * The property that has the caption, null if no caption property + * is present + * @param descriptionProperty + * The property that has the description, null if no description + * property is present + * @param startDateProperty + * The property that has the starting date + * @param endDateProperty + * The property that has the ending date + * @param styleNameProperty + * The property that has the stylename, null if no stylname + * property is present + */ + public void setContainerDataSource(Container.Indexed container, + Object captionProperty, Object descriptionProperty, + Object startDateProperty, Object endDateProperty, + Object styleNameProperty) { + ContainerEventProvider provider = new ContainerEventProvider(container); + provider.setCaptionProperty(captionProperty); + provider.setDescriptionProperty(descriptionProperty); + provider.setStartDateProperty(startDateProperty); + provider.setEndDateProperty(endDateProperty); + provider.setStyleNameProperty(styleNameProperty); + provider.addEventSetChangeListener(new CalendarEventProvider.EventSetChangeListener() { + public void eventSetChange(EventSetChangeEvent changeEvent) { + // Repaint if events change + markAsDirty(); + } + }); + provider.addEventChangeListener(new EventChangeListener() { + public void eventChange(EventChangeEvent changeEvent) { + // Repaint if event changes + markAsDirty(); + } + }); + setEventProvider(provider); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventProvider#getEvents(java. + * util.Date, java.util.Date) + */ + public List<CalendarEvent> getEvents(Date startDate, Date endDate) { + return getEventProvider().getEvents(startDate, endDate); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#addEvent + * (com.vaadin.addon.calendar.event.CalendarEvent) + */ + public void addEvent(CalendarEvent event) { + if (getEventProvider() instanceof CalendarEditableEventProvider) { + CalendarEditableEventProvider provider = (CalendarEditableEventProvider) getEventProvider(); + provider.addEvent(event); + markAsDirty(); + } else { + throw new UnsupportedOperationException( + "Event provider does not support adding events"); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#removeEvent + * (com.vaadin.addon.calendar.event.CalendarEvent) + */ + public void removeEvent(CalendarEvent event) { + if (getEventProvider() instanceof CalendarEditableEventProvider) { + CalendarEditableEventProvider provider = (CalendarEditableEventProvider) getEventProvider(); + provider.removeEvent(event); + markAsDirty(); + } else { + throw new UnsupportedOperationException( + "Event provider does not support removing events"); + } + } + + /** + * Adds an action handler to the calender that handles event produced by the + * context menu. + * + * <p> + * The {@link Handler#getActions(Object, Object)} parameters depend on what + * view the Calendar is in: + * <ul> + * <li>If the Calendar is in <i>Day or Week View</i> then the target + * parameter will be a {@link CalendarDateRange} with a range of + * half-an-hour. The {@link Handler#getActions(Object, Object)} method will + * be called once per half-hour slot.</li> + * <li>If the Calendar is in <i>Month View</i> then the target parameter + * will be a {@link CalendarDateRange} with a range of one day. The + * {@link Handler#getActions(Object, Object)} will be called once for each + * day. + * </ul> + * The Dates passed into the {@link CalendarDateRange} are in the same + * timezone as the calendar is. + * </p> + * + * <p> + * The {@link Handler#handleAction(Action, Object, Object)} parameters + * depend on what the context menu is called upon: + * <ul> + * <li>If the context menu is called upon an event then the target parameter + * is the event, i.e. instanceof {@link CalendarEvent}</li> + * <li>If the context menu is called upon an empty slot then the target is a + * {@link Date} representing that slot + * </ul> + * </p> + */ + public void addActionHandler(Handler actionHandler) { + if (actionHandler != null) { + if (actionHandlers == null) { + actionHandlers = new LinkedList<Action.Handler>(); + actionMapper = new KeyMapper<Action>(); + } + if (!actionHandlers.contains(actionHandler)) { + actionHandlers.add(actionHandler); + markAsDirty(); + } + } + } + + /** + * Is the calendar in a mode where all days of the month is shown + * + * @return Returns true if calendar is in monthly mode and false if it is in + * weekly mode + */ + public boolean isMonthlyMode() { + CalendarState state = (CalendarState) getState(false); + if (state.days != null) { + return state.days.size() > 7; + } else { + // Default mode + return true; + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.event.Action.Container#removeActionHandler(com.vaadin.event + * .Action.Handler) + */ + public void removeActionHandler(Handler actionHandler) { + if (actionHandlers != null && actionHandlers.contains(actionHandler)) { + actionHandlers.remove(actionHandler); + if (actionHandlers.isEmpty()) { + actionHandlers = null; + actionMapper = null; + } + markAsDirty(); + } + } + + private class CalendarServerRpcImpl implements CalendarServerRpc { + + @Override + public void eventMove(int eventIndex, String newDate) { + if (!isClientChangeAllowed()) { + return; + } + if (newDate != null) { + try { + Date d = df_date_time.parse(newDate); + if (eventIndex >= 0 && eventIndex < events.size() + && events.get(eventIndex) != null) { + fireEventMove(eventIndex, d); + } + } catch (ParseException e) { + getLogger().log(Level.WARNING, e.getMessage()); + } + } + } + + @Override + public void rangeSelect(String range) { + if (!isClientChangeAllowed()) { + return; + } + + if (range != null && range.length() > 14 && range.contains("TO")) { + String[] dates = range.split("TO"); + try { + Date d1 = df_date.parse(dates[0]); + Date d2 = df_date.parse(dates[1]); + + fireRangeSelect(d1, d2, true); + + } catch (ParseException e) { + // NOP + } + } else if (range != null && range.length() > 12 + && range.contains(":")) { + String[] dates = range.split(":"); + if (dates.length == 3) { + try { + Date d = df_date.parse(dates[0]); + currentCalendar.setTime(d); + int startMinutes = Integer.parseInt(dates[1]); + int endMinutes = Integer.parseInt(dates[2]); + currentCalendar.add(java.util.Calendar.MINUTE, + startMinutes); + Date start = currentCalendar.getTime(); + currentCalendar.add(java.util.Calendar.MINUTE, + endMinutes - startMinutes); + Date end = currentCalendar.getTime(); + fireRangeSelect(start, end, false); + } catch (ParseException e) { + // NOP + } catch (NumberFormatException e) { + // NOP + } + } + } + } + + @Override + public void forward() { + fireEvent(new ForwardEvent(Calendar.this)); + } + + @Override + public void backward() { + fireEvent(new BackwardEvent(Calendar.this)); + } + + @Override + public void dateClick(String date) { + if (!isClientChangeAllowed()) { + return; + } + if (date != null && date.length() > 6) { + try { + Date d = df_date.parse(date); + fireDateClick(d); + } catch (ParseException e) { + } + } + } + + @Override + public void weekClick(String event) { + if (!isClientChangeAllowed()) { + return; + } + if (event.length() > 0 && event.contains("w")) { + String[] splitted = event.split("w"); + if (splitted.length == 2) { + try { + int yr = 1900 + Integer.parseInt(splitted[0]); + int week = Integer.parseInt(splitted[1]); + fireWeekClick(week, yr); + } catch (NumberFormatException e) { + // NOP + } + } + } + } + + @Override + public void eventClick(int eventIndex) { + if (!isEventClickAllowed()) { + return; + } + if (eventIndex >= 0 && eventIndex < events.size() + && events.get(eventIndex) != null) { + fireEventClick(eventIndex); + } + } + + @Override + public void eventResize(int eventIndex, String newStartDate, + String newEndDate) { + if (!isClientChangeAllowed()) { + return; + } + if (newStartDate != null && !"".equals(newStartDate) + && newEndDate != null && !"".equals(newEndDate)) { + try { + Date newStartTime = df_date_time.parse(newStartDate); + Date newEndTime = df_date_time.parse(newEndDate); + + fireEventResize(eventIndex, newStartTime, newEndTime); + } catch (ParseException e) { + // NOOP + } + } + } + + @Override + public void scroll(int scrollPosition) { + scrollTop = scrollPosition; + markAsDirty(); + } + + @Override + public void actionOnEmptyCell(String actionKey, String startDate, + String endDate) { + Action action = actionMapper.get(actionKey); + SimpleDateFormat formatter = new SimpleDateFormat( + DateConstants.ACTION_DATE_FORMAT_PATTERN); + formatter.setTimeZone(getTimeZone()); + try { + Date start = formatter.parse(startDate); + for (Action.Handler ah : actionHandlers) { + ah.handleAction(action, this, start); + } + + } catch (ParseException e) { + getLogger().log(Level.WARNING, + "Could not parse action date string"); + } + + } + + @Override + public void actionOnEvent(String actionKey, String startDate, + String endDate, int eventIndex) { + Action action = actionMapper.get(actionKey); + SimpleDateFormat formatter = new SimpleDateFormat( + DateConstants.ACTION_DATE_FORMAT_PATTERN); + formatter.setTimeZone(getTimeZone()); + for (Action.Handler ah : actionHandlers) { + ah.handleAction(action, this, events.get(eventIndex)); + } + } + } +}
\ No newline at end of file diff --git a/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvent.java b/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvent.java new file mode 100644 index 0000000000..1f012157b5 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvent.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar; + +import com.vaadin.ui.Calendar; +import com.vaadin.ui.Component; + +/** + * All Calendar events extends this class. + * + * @since 7.1 + * @author Vaadin Ltd. + * + */ +@SuppressWarnings("serial") +public class CalendarComponentEvent extends Component.Event { + + /** + * Set the source of the event + * + * @param source + * The source calendar + * + */ + public CalendarComponentEvent(Calendar source) { + super(source); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.ui.Component.Event#getComponent() + */ + @Override + public Calendar getComponent() { + return (Calendar) super.getComponent(); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvents.java b/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvents.java new file mode 100644 index 0000000000..1904d69898 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvents.java @@ -0,0 +1,603 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.Date; +import java.util.EventListener; + +import com.vaadin.shared.ui.calendar.CalendarEventId; +import com.vaadin.ui.Calendar; +import com.vaadin.ui.components.calendar.event.CalendarEvent; +import com.vaadin.util.ReflectTools; + +/** + * Interface for all Vaadin Calendar events. + * + * @since 7.1.0 + * @author Vaadin Ltd. + */ +public interface CalendarComponentEvents extends Serializable { + + /** + * Notifier interface for notifying listener of calendar events + */ + public interface CalendarEventNotifier extends Serializable { + /** + * Get the assigned event handler for the given eventId. + * + * @param eventId + * @return the assigned eventHandler, or null if no handler is assigned + */ + public EventListener getHandler(String eventId); + } + + /** + * Notifier interface for event drag & drops. + */ + public interface EventMoveNotifier extends CalendarEventNotifier { + + /** + * Set the EventMoveHandler. + * + * @param listener + * EventMoveHandler to be added + */ + public void setHandler(EventMoveHandler listener); + + } + + /** + * MoveEvent is sent when existing event is dragged to a new position. + */ + @SuppressWarnings("serial") + public class MoveEvent extends CalendarComponentEvent { + + public static final String EVENT_ID = CalendarEventId.EVENTMOVE; + + /** Index for the moved Schedule.Event. */ + private CalendarEvent calendarEvent; + + /** New starting date for the moved Calendar.Event. */ + private Date newStart; + + /** + * MoveEvent needs the target event and new start date. + * + * @param source + * Calendar component. + * @param calendarEvent + * Target event. + * @param newStart + * Target event's new start date. + */ + public MoveEvent(Calendar source, CalendarEvent calendarEvent, + Date newStart) { + super(source); + + this.calendarEvent = calendarEvent; + this.newStart = newStart; + } + + /** + * Get target event. + * + * @return Target event. + */ + public CalendarEvent getCalendarEvent() { + return calendarEvent; + } + + /** + * Get new start date. + * + * @return New start date. + */ + public Date getNewStart() { + return newStart; + } + } + + /** + * Handler interface for when events are being dragged on the calendar + * + */ + public interface EventMoveHandler extends EventListener, Serializable { + + /** Trigger method for the MoveEvent. */ + public static final Method eventMoveMethod = ReflectTools.findMethod( + EventMoveHandler.class, "eventMove", MoveEvent.class); + + /** + * This method will be called when event has been moved to a new + * position. + * + * @param event + * MoveEvent containing specific information of the new + * position and target event. + */ + public void eventMove(MoveEvent event); + } + + /** + * Handler interface for day or time cell drag-marking with mouse. + */ + public interface RangeSelectNotifier extends Serializable, + CalendarEventNotifier { + + /** + * Set the RangeSelectHandler that listens for drag-marking. + * + * @param listener + * RangeSelectHandler to be added. + */ + public void setHandler(RangeSelectHandler listener); + } + + /** + * RangeSelectEvent is sent when day or time cells are drag-marked with + * mouse. + */ + @SuppressWarnings("serial") + public class RangeSelectEvent extends CalendarComponentEvent { + + public static final String EVENT_ID = CalendarEventId.RANGESELECT; + + /** Calendar event's start date. */ + private Date start; + + /** Calendar event's end date. */ + private Date end; + + /** + * Defines the event's view mode. + */ + private boolean monthlyMode; + + /** + * RangeSelectEvent needs a start and end date. + * + * @param source + * Calendar component. + * @param start + * Start date. + * @param end + * End date. + * @param monthlyMode + * Calendar view mode. + */ + public RangeSelectEvent(Calendar source, Date start, Date end, + boolean monthlyMode) { + super(source); + this.start = start; + this.end = end; + this.monthlyMode = monthlyMode; + } + + /** + * Get start date. + * + * @return Start date. + */ + public Date getStart() { + return start; + } + + /** + * Get end date. + * + * @return End date. + */ + public Date getEnd() { + return end; + } + + /** + * Gets the event's view mode. Calendar can be be either in monthly or + * weekly mode, depending on the active date range. + * + * @deprecated User {@link Calendar#isMonthlyMode()} instead + * + * @return Returns true when monthly view is active. + */ + @Deprecated + public boolean isMonthlyMode() { + return monthlyMode; + } + } + + /** RangeSelectHandler handles RangeSelectEvent. */ + public interface RangeSelectHandler extends EventListener, Serializable { + + /** Trigger method for the RangeSelectEvent. */ + public static final Method rangeSelectMethod = ReflectTools + .findMethod(RangeSelectHandler.class, "rangeSelect", + RangeSelectEvent.class); + + /** + * This method will be called when day or time cells are drag-marked + * with mouse. + * + * @param event + * RangeSelectEvent that contains range start and end date. + */ + public void rangeSelect(RangeSelectEvent event); + } + + /** Notifier interface for navigation listening. */ + public interface NavigationNotifier extends Serializable { + /** + * Add a forward navigation listener. + * + * @param handler + * ForwardHandler to be added. + */ + public void setHandler(ForwardHandler handler); + + /** + * Add a backward navigation listener. + * + * @param handler + * BackwardHandler to be added. + */ + public void setHandler(BackwardHandler handler); + + /** + * Add a date click listener. + * + * @param handler + * DateClickHandler to be added. + */ + public void setHandler(DateClickHandler handler); + + /** + * Add a event click listener. + * + * @param handler + * EventClickHandler to be added. + */ + public void setHandler(EventClickHandler handler); + + /** + * Add a week click listener. + * + * @param handler + * WeekClickHandler to be added. + */ + public void setHandler(WeekClickHandler handler); + } + + /** + * ForwardEvent is sent when forward navigation button is clicked. + */ + @SuppressWarnings("serial") + public class ForwardEvent extends CalendarComponentEvent { + + public static final String EVENT_ID = CalendarEventId.FORWARD; + + /** + * ForwardEvent needs only the source component. + * + * @param source + * Calendar component. + */ + public ForwardEvent(Calendar source) { + super(source); + } + } + + /** ForwardHandler handles ForwardEvent. */ + public interface ForwardHandler extends EventListener, Serializable { + + /** Trigger method for the ForwardEvent. */ + public static final Method forwardMethod = ReflectTools.findMethod( + ForwardHandler.class, "forward", ForwardEvent.class); + + /** + * This method will be called when date range is moved forward. + * + * @param event + * ForwardEvent + */ + public void forward(ForwardEvent event); + } + + /** + * BackwardEvent is sent when backward navigation button is clicked. + */ + @SuppressWarnings("serial") + public class BackwardEvent extends CalendarComponentEvent { + + public static final String EVENT_ID = CalendarEventId.BACKWARD; + + /** + * BackwardEvent needs only the source source component. + * + * @param source + * Calendar component. + */ + public BackwardEvent(Calendar source) { + super(source); + } + } + + /** BackwardHandler handles BackwardEvent. */ + public interface BackwardHandler extends EventListener, Serializable { + + /** Trigger method for the BackwardEvent. */ + public static final Method backwardMethod = ReflectTools.findMethod( + BackwardHandler.class, "backward", BackwardEvent.class); + + /** + * This method will be called when date range is moved backwards. + * + * @param event + * BackwardEvent + */ + public void backward(BackwardEvent event); + } + + /** + * DateClickEvent is sent when a date is clicked. + */ + @SuppressWarnings("serial") + public class DateClickEvent extends CalendarComponentEvent { + + public static final String EVENT_ID = CalendarEventId.DATECLICK; + + /** Date that was clicked. */ + private Date date; + + /** DateClickEvent needs the target date that was clicked. */ + public DateClickEvent(Calendar source, Date date) { + super(source); + this.date = date; + } + + /** + * Get clicked date. + * + * @return Clicked date. + */ + public Date getDate() { + return date; + } + } + + /** DateClickHandler handles DateClickEvent. */ + public interface DateClickHandler extends EventListener, Serializable { + + /** Trigger method for the DateClickEvent. */ + public static final Method dateClickMethod = ReflectTools.findMethod( + DateClickHandler.class, "dateClick", DateClickEvent.class); + + /** + * This method will be called when a date is clicked. + * + * @param event + * DateClickEvent containing the target date. + */ + public void dateClick(DateClickEvent event); + } + + /** + * EventClick is sent when an event is clicked. + */ + @SuppressWarnings("serial") + public class EventClick extends CalendarComponentEvent { + + public static final String EVENT_ID = CalendarEventId.EVENTCLICK; + + /** Clicked source event. */ + private CalendarEvent calendarEvent; + + /** Target source event is needed for the EventClick. */ + public EventClick(Calendar source, CalendarEvent calendarEvent) { + super(source); + this.calendarEvent = calendarEvent; + } + + /** + * Get the clicked event. + * + * @return Clicked event. + */ + public CalendarEvent getCalendarEvent() { + return calendarEvent; + } + } + + /** EventClickHandler handles EventClick. */ + public interface EventClickHandler extends EventListener, Serializable { + + /** Trigger method for the EventClick. */ + public static final Method eventClickMethod = ReflectTools.findMethod( + EventClickHandler.class, "eventClick", EventClick.class); + + /** + * This method will be called when an event is clicked. + * + * @param event + * EventClick containing the target event. + */ + public void eventClick(EventClick event); + } + + /** + * WeekClick is sent when week is clicked. + */ + @SuppressWarnings("serial") + public class WeekClick extends CalendarComponentEvent { + + public static final String EVENT_ID = CalendarEventId.WEEKCLICK; + + /** Target week. */ + private int week; + + /** Target year. */ + private int year; + + /** + * WeekClick needs a target year and week. + * + * @param source + * Target source. + * @param week + * Target week. + * @param year + * Target year. + */ + public WeekClick(Calendar source, int week, int year) { + super(source); + this.week = week; + this.year = year; + } + + /** + * Get week as a integer. See {@link java.util.Calendar} for the allowed + * values. + * + * @return Week as a integer. + */ + public int getWeek() { + return week; + } + + /** + * Get year as a integer. See {@link java.util.Calendar} for the allowed + * values. + * + * @return Year as a integer + */ + public int getYear() { + return year; + } + } + + /** WeekClickHandler handles WeekClicks. */ + public interface WeekClickHandler extends EventListener, Serializable { + + /** Trigger method for the WeekClick. */ + public static final Method weekClickMethod = ReflectTools.findMethod( + WeekClickHandler.class, "weekClick", WeekClick.class); + + /** + * This method will be called when a week is clicked. + * + * @param event + * WeekClick containing the target week and year. + */ + public void weekClick(WeekClick event); + } + + /** + * EventResize is sent when an event is resized + */ + @SuppressWarnings("serial") + public class EventResize extends CalendarComponentEvent { + + public static final String EVENT_ID = CalendarEventId.EVENTRESIZE; + + private CalendarEvent calendarEvent; + + private Date startTime; + + private Date endTime; + + public EventResize(Calendar source, CalendarEvent calendarEvent, + Date startTime, Date endTime) { + super(source); + this.calendarEvent = calendarEvent; + this.startTime = startTime; + this.endTime = endTime; + } + + /** + * Get target event. + * + * @return Target event. + */ + public CalendarEvent getCalendarEvent() { + return calendarEvent; + } + + /** + * @deprecated Use {@link #getNewStart()} instead + * + * @return the new start time + */ + @Deprecated + public Date getNewStartTime() { + return startTime; + } + + /** + * Returns the updated start date/time of the event + * + * @return The new date for the event + */ + public Date getNewStart() { + return startTime; + } + + /** + * @deprecated Use {@link #getNewEnd()} instead + * + * @return the new end time + */ + @Deprecated + public Date getNewEndTime() { + return endTime; + } + + /** + * Returns the updates end date/time of the event + * + * @return The new date for the event + */ + public Date getNewEnd() { + return endTime; + } + } + + /** + * Notifier interface for event resizing. + */ + public interface EventResizeNotifier extends Serializable { + + /** + * Set a EventResizeHandler. + * + * @param handler + * EventResizeHandler to be set + */ + public void setHandler(EventResizeHandler handler); + } + + /** + * Handler for EventResize event. + */ + public interface EventResizeHandler extends EventListener, Serializable { + + /** Trigger method for the EventResize. */ + public static final Method eventResizeMethod = ReflectTools.findMethod( + EventResizeHandler.class, "eventResize", EventResize.class); + + void eventResize(EventResize event); + } + +} diff --git a/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java b/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java new file mode 100644 index 0000000000..01b766a6db --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java @@ -0,0 +1,86 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar; + +import java.io.Serializable; +import java.util.Date; +import java.util.TimeZone; + +/** + * Class for representing a date range. + * + * @since 7.1.0 + * @author Vaadin Ltd. + * + */ +@SuppressWarnings("serial") +public class CalendarDateRange implements Serializable { + + private Date start; + + private Date end; + + private final transient TimeZone tz; + + /** + * Constructor + * + * @param start + * The start date and time of the date range + * @param end + * The end date and time of the date range + */ + public CalendarDateRange(Date start, Date end, TimeZone tz) { + super(); + this.start = start; + this.end = end; + this.tz = tz; + } + + /** + * Get the start date of the date range + * + * @return the start Date of the range + */ + public Date getStart() { + return start; + } + + /** + * Get the end date of the date range + * + * @return the end Date of the range + */ + public Date getEnd() { + return end; + } + + /** + * Is a date in the date range + * + * @param date + * The date to check + * @return true if the date range contains a date start and end of range + * inclusive; false otherwise + */ + public boolean inRange(Date date) { + if (date == null) { + return false; + } + + return date.compareTo(start) >= 0 && date.compareTo(end) <= 0; + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/CalendarTargetDetails.java b/server/src/com/vaadin/ui/components/calendar/CalendarTargetDetails.java new file mode 100644 index 0000000000..1a3ef67377 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/CalendarTargetDetails.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar; + +import java.util.Date; +import java.util.Map; + +import com.vaadin.event.dd.DropTarget; +import com.vaadin.event.dd.TargetDetailsImpl; +import com.vaadin.ui.Calendar; + +/** + * Drop details for {@link com.vaadin.ui.addon.calendar.ui.Calendar Calendar}. + * When something is dropped on the Calendar, this class contains the specific + * details of the drop point. Specifically, this class gives access to the date + * where the drop happened. If the Calendar was in weekly mode, the date also + * includes the start time of the slot. + * + * @since 7.1 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class CalendarTargetDetails extends TargetDetailsImpl { + + private boolean hasDropTime; + + public CalendarTargetDetails(Map<String, Object> rawDropData, + DropTarget dropTarget) { + super(rawDropData, dropTarget); + } + + /** + * @return true if {@link #getDropTime()} will return a date object with the + * time set to the start of the time slot where the drop happened + */ + public boolean hasDropTime() { + return hasDropTime; + } + + /** + * Does the dropped item have a time associated with it + * + * @param hasDropTime + */ + public void setHasDropTime(boolean hasDropTime) { + this.hasDropTime = hasDropTime; + } + + /** + * @return the date where the drop happened + */ + public Date getDropTime() { + if (hasDropTime) { + return (Date) getData("dropTime"); + } else { + return (Date) getData("dropDay"); + } + } + + /** + * @return the {@link com.vaadin.ui.addon.calendar.ui.Calendar Calendar} + * instance which was the target of the drop + */ + public Calendar getTargetCalendar() { + return (Calendar) getTarget(); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java b/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java new file mode 100644 index 0000000000..b01140eb88 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java @@ -0,0 +1,566 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar; + +import java.util.Collections; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import com.vaadin.data.Container; +import com.vaadin.data.Container.Indexed; +import com.vaadin.data.Container.ItemSetChangeEvent; +import com.vaadin.data.Container.ItemSetChangeNotifier; +import com.vaadin.data.Item; +import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeNotifier; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventMoveHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResize; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResizeHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.MoveEvent; +import com.vaadin.ui.components.calendar.event.BasicEvent; +import com.vaadin.ui.components.calendar.event.CalendarEditableEventProvider; +import com.vaadin.ui.components.calendar.event.CalendarEvent; +import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeListener; +import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeNotifier; +import com.vaadin.ui.components.calendar.event.CalendarEventProvider; +import com.vaadin.ui.components.calendar.event.CalendarEventProvider.EventSetChangeNotifier; + +/** + * A event provider which uses a {@link Container} as a datasource. Container + * used as data source. + * + * NOTE: The data source must be sorted by date! + * + * @since 7.1.0 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class ContainerEventProvider implements CalendarEditableEventProvider, + EventSetChangeNotifier, EventChangeNotifier, EventMoveHandler, + EventResizeHandler, Container.ItemSetChangeListener, + Property.ValueChangeListener { + + // Default property ids + public static final String CAPTION_PROPERTY = "caption"; + public static final String DESCRIPTION_PROPERTY = "description"; + public static final String STARTDATE_PROPERTY = "start"; + public static final String ENDDATE_PROPERTY = "end"; + public static final String STYLENAME_PROPERTY = "styleName"; + + /** + * Internal class to keep the container index which item this event + * represents + * + */ + private class ContainerCalendarEvent extends BasicEvent { + private final int index; + + public ContainerCalendarEvent(int containerIndex) { + super(); + index = containerIndex; + } + + public int getContainerIndex() { + return index; + } + } + + /** + * Listeners attached to the container + */ + private final List<EventSetChangeListener> eventSetChangeListeners = new LinkedList<CalendarEventProvider.EventSetChangeListener>(); + private final List<EventChangeListener> eventChangeListeners = new LinkedList<CalendarEvent.EventChangeListener>(); + + /** + * The event cache contains the events previously created by + * {@link #getEvents(Date, Date)} + */ + private final List<CalendarEvent> eventCache = new LinkedList<CalendarEvent>(); + + /** + * The container used as datasource + */ + private Indexed container; + + /** + * Container properties. Defaults based on using the {@link BasicEvent} + * helper class. + */ + private Object captionProperty = CAPTION_PROPERTY; + private Object descriptionProperty = DESCRIPTION_PROPERTY; + private Object startDateProperty = STARTDATE_PROPERTY; + private Object endDateProperty = ENDDATE_PROPERTY; + private Object styleNameProperty = STYLENAME_PROPERTY; + + /** + * Constructor + * + * @param container + * Container to use as a data source. + */ + public ContainerEventProvider(Container.Indexed container) { + this.container = container; + listenToContainerEvents(); + } + + /** + * Set the container data source + * + * @param container + * The container to use as datasource + * + */ + public void setContainerDataSource(Container.Indexed container) { + // Detach the previous container + detachContainerDataSource(); + + this.container = container; + listenToContainerEvents(); + } + + /** + * Returns the container used as data source + * + */ + public Container.Indexed getContainerDataSource() { + return container; + } + + /** + * Attaches listeners to the container so container events can be processed + */ + private void listenToContainerEvents() { + if (container instanceof ItemSetChangeNotifier) { + ((ItemSetChangeNotifier) container).addItemSetChangeListener(this); + } + if (container instanceof ValueChangeNotifier) { + ((ValueChangeNotifier) container).addValueChangeListener(this); + } + } + + /** + * Removes listeners from the container so no events are processed + */ + private void ignoreContainerEvents() { + if (container instanceof ItemSetChangeNotifier) { + ((ItemSetChangeNotifier) container) + .removeItemSetChangeListener(this); + } + if (container instanceof ValueChangeNotifier) { + ((ValueChangeNotifier) container).removeValueChangeListener(this); + } + } + + /** + * Converts an event in the container to an {@link CalendarEvent} + * + * @param index + * The index of the item in the container to get the event for + * @return + */ + private CalendarEvent getEvent(int index) { + + // Check the event cache first + for (CalendarEvent e : eventCache) { + if (e instanceof ContainerCalendarEvent + && ((ContainerCalendarEvent) e).getContainerIndex() == index) { + return e; + } else if (container.getIdByIndex(index) == e) { + return e; + } + } + + final Object id = container.getIdByIndex(index); + Item item = container.getItem(id); + CalendarEvent event; + if (id instanceof CalendarEvent) { + /* + * If we are using the BeanItemContainer or another container which + * stores the objects as ids then just return the instances + */ + event = (CalendarEvent) id; + + } else { + /* + * Else we use the properties to create the event + */ + BasicEvent basicEvent = new ContainerCalendarEvent(index); + + // Set values from property values + if (captionProperty != null + && item.getItemPropertyIds().contains(captionProperty)) { + basicEvent.setCaption(String.valueOf(item.getItemProperty( + captionProperty).getValue())); + } + if (descriptionProperty != null + && item.getItemPropertyIds().contains(descriptionProperty)) { + basicEvent.setDescription(String.valueOf(item.getItemProperty( + descriptionProperty).getValue())); + } + if (startDateProperty != null + && item.getItemPropertyIds().contains(startDateProperty)) { + basicEvent.setStart((Date) item.getItemProperty( + startDateProperty).getValue()); + } + if (endDateProperty != null + && item.getItemPropertyIds().contains(endDateProperty)) { + basicEvent.setEnd((Date) item.getItemProperty(endDateProperty) + .getValue()); + } + if (styleNameProperty != null + && item.getItemPropertyIds().contains(styleNameProperty)) { + basicEvent.setDescription(String.valueOf(item.getItemProperty( + descriptionProperty).getValue())); + } + event = basicEvent; + } + return event; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventProvider#getEvents(java. + * util.Date, java.util.Date) + */ + public List<CalendarEvent> getEvents(Date startDate, Date endDate) { + eventCache.clear(); + + int[] rangeIndexes = getFirstAndLastEventIndex(startDate, endDate); + for (int i = rangeIndexes[0]; i <= rangeIndexes[1] + && i < container.size(); i++) { + eventCache.add(getEvent(i)); + } + return Collections.unmodifiableList(eventCache); + } + + /** + * Get the first event for a date + * + * @param date + * The date to search for, NUll returns first event in container + * @return Returns an array where the first item is the start index and the + * second item is the end item + */ + private int[] getFirstAndLastEventIndex(Date start, Date end) { + int startIndex = 0; + int size = container.size(); + int endIndex = size - 1; + + if (start != null) { + /* + * Iterating from the start of the container, if range is in the end + * of the container then this will be slow TODO This could be + * improved by using some sort of divide and conquer algorithm + */ + while (startIndex < size) { + Object id = container.getIdByIndex(startIndex); + Item item = container.getItem(id); + Date d = (Date) item.getItemProperty(startDateProperty) + .getValue(); + if (d.compareTo(start) >= 0) { + break; + } + startIndex++; + } + } + + if (end != null) { + /* + * Iterate from the start index until range ends + */ + endIndex = startIndex; + while (endIndex < size - 1) { + Object id = container.getIdByIndex(endIndex); + Item item = container.getItem(id); + Date d = (Date) item.getItemProperty(endDateProperty) + .getValue(); + if (d == null) { + // No end date present, use start date + d = (Date) item.getItemProperty(startDateProperty) + .getValue(); + } + if (d.compareTo(end) >= 0) { + endIndex--; + break; + } + endIndex++; + } + } + + return new int[] { startIndex, endIndex }; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventProvider.EventSetChangeNotifier + * #addListener(com.vaadin.addon.calendar.event.CalendarEventProvider. + * EventSetChangeListener) + */ + public void addEventSetChangeListener(EventSetChangeListener listener) { + if (!eventSetChangeListeners.contains(listener)) { + eventSetChangeListeners.add(listener); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventProvider.EventSetChangeNotifier + * #removeListener(com.vaadin.addon.calendar.event.CalendarEventProvider. + * EventSetChangeListener) + */ + public void removeEventSetChangeListener(EventSetChangeListener listener) { + eventSetChangeListeners.remove(listener); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEvent.EventChangeNotifier#addListener + * (com.vaadin.addon.calendar.event.CalendarEvent.EventChangeListener) + */ + public void addEventChangeListener(EventChangeListener listener) { + if (eventChangeListeners.contains(listener)) { + eventChangeListeners.add(listener); + } + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.addon.calendar.event.CalendarEvent.EventChangeNotifier# + * removeListener + * (com.vaadin.addon.calendar.event.CalendarEvent.EventChangeListener) + */ + public void removeEventChangeListener(EventChangeListener listener) { + eventChangeListeners.remove(listener); + } + + /** + * Get the property which provides the caption of the event + */ + public Object getCaptionProperty() { + return captionProperty; + } + + /** + * Set the property which provides the caption of the event + */ + public void setCaptionProperty(Object captionProperty) { + this.captionProperty = captionProperty; + } + + /** + * Get the property which provides the description of the event + */ + public Object getDescriptionProperty() { + return descriptionProperty; + } + + /** + * Set the property which provides the description of the event + */ + public void setDescriptionProperty(Object descriptionProperty) { + this.descriptionProperty = descriptionProperty; + } + + /** + * Get the property which provides the starting date and time of the event + */ + public Object getStartDateProperty() { + return startDateProperty; + } + + /** + * Set the property which provides the starting date and time of the event + */ + public void setStartDateProperty(Object startDateProperty) { + this.startDateProperty = startDateProperty; + } + + /** + * Get the property which provides the ending date and time of the event + */ + public Object getEndDateProperty() { + return endDateProperty; + } + + /** + * Set the property which provides the ending date and time of the event + */ + public void setEndDateProperty(Object endDateProperty) { + this.endDateProperty = endDateProperty; + } + + /** + * Get the property which provides the style name for the event + */ + public Object getStyleNameProperty() { + return styleNameProperty; + } + + /** + * Set the property which provides the style name for the event + */ + public void setStyleNameProperty(Object styleNameProperty) { + this.styleNameProperty = styleNameProperty; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.Container.ItemSetChangeListener#containerItemSetChange + * (com.vaadin.data.Container.ItemSetChangeEvent) + */ + public void containerItemSetChange(ItemSetChangeEvent event) { + if (event.getContainer() == container) { + // Trigger an eventset change event when the itemset changes + for (EventSetChangeListener listener : eventSetChangeListeners) { + listener.eventSetChange(new EventSetChangeEvent(this)); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.data.Property.ValueChangeListener#valueChange(com.vaadin.data + * .Property.ValueChangeEvent) + */ + public void valueChange(ValueChangeEvent event) { + /* + * TODO Need to figure out how to get the item which triggered the the + * valuechange event and then trigger a EventChange event to the + * listeners + */ + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveHandler + * #eventMove + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.MoveEvent) + */ + public void eventMove(MoveEvent event) { + CalendarEvent ce = event.getCalendarEvent(); + if (eventCache.contains(ce)) { + int index; + if (ce instanceof ContainerCalendarEvent) { + index = ((ContainerCalendarEvent) ce).getContainerIndex(); + } else { + index = container.indexOfId(ce); + } + + long eventLength = ce.getEnd().getTime() - ce.getStart().getTime(); + Date newEnd = new Date(event.getNewStart().getTime() + eventLength); + + ignoreContainerEvents(); + Item item = container.getItem(container.getIdByIndex(index)); + item.getItemProperty(startDateProperty).setValue( + event.getNewStart()); + item.getItemProperty(endDateProperty).setValue(newEnd); + listenToContainerEvents(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeHandler + * #eventResize + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResize) + */ + public void eventResize(EventResize event) { + CalendarEvent ce = event.getCalendarEvent(); + if (eventCache.contains(ce)) { + int index; + if (ce instanceof ContainerCalendarEvent) { + index = ((ContainerCalendarEvent) ce).getContainerIndex(); + } else { + index = container.indexOfId(ce); + } + ignoreContainerEvents(); + Item item = container.getItem(container.getIdByIndex(index)); + item.getItemProperty(startDateProperty).setValue( + event.getNewStart()); + item.getItemProperty(endDateProperty).setValue(event.getNewEnd()); + listenToContainerEvents(); + } + } + + /** + * If you are reusing the container which previously have been attached to + * this ContainerEventProvider call this method to remove this event + * providers container listeners before attaching it to an other + * ContainerEventProvider + */ + public void detachContainerDataSource() { + ignoreContainerEvents(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#addEvent + * (com.vaadin.addon.calendar.event.CalendarEvent) + */ + public void addEvent(CalendarEvent event) { + Item item; + try { + item = container.addItem(event); + } catch (UnsupportedOperationException uop) { + // Thrown if container does not support adding items with custom + // ids. JPAContainer for example. + item = container.getItem(container.addItem()); + } + if (item != null) { + item.getItemProperty(getCaptionProperty()).setValue( + event.getCaption()); + item.getItemProperty(getStartDateProperty()).setValue( + event.getStart()); + item.getItemProperty(getEndDateProperty()).setValue(event.getEnd()); + item.getItemProperty(getStyleNameProperty()).setValue( + event.getStyleName()); + item.getItemProperty(getDescriptionProperty()).setValue( + event.getDescription()); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#removeEvent + * (com.vaadin.addon.calendar.event.CalendarEvent) + */ + public void removeEvent(CalendarEvent event) { + container.removeItem(event); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/event/BasicEvent.java b/server/src/com/vaadin/ui/components/calendar/event/BasicEvent.java new file mode 100644 index 0000000000..ab342dfabf --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/event/BasicEvent.java @@ -0,0 +1,251 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.event; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeNotifier; + +/** + * Simple implementation of + * {@link com.vaadin.addon.calendar.event.CalendarEvent CalendarEvent}. Has + * setters for all required fields and fires events when this event is changed. + * + * @since 7.1.0 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class BasicEvent implements EditableCalendarEvent, EventChangeNotifier { + + private String caption; + private String description; + private Date end; + private Date start; + private String styleName; + private transient List<EventChangeListener> listeners = new ArrayList<EventChangeListener>(); + + private boolean isAllDay; + + /** + * Default constructor + */ + public BasicEvent() { + + } + + /** + * Constructor for creating an event with the same start and end date + * + * @param caption + * The caption for the event + * @param description + * The description for the event + * @param date + * The date the event occurred + */ + public BasicEvent(String caption, String description, Date date) { + this.caption = caption; + this.description = description; + start = date; + end = date; + } + + /** + * Constructor for creating an event with a start date and an end date. + * Start date should be before the end date + * + * @param caption + * The caption for the event + * @param description + * The description for the event + * @param startDate + * The start date of the event + * @param endDate + * The end date of the event + */ + public BasicEvent(String caption, String description, Date startDate, + Date endDate) { + this.caption = caption; + this.description = description; + start = startDate; + end = endDate; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.addon.calendar.event.CalendarEvent#getCaption() + */ + public String getCaption() { + return caption; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.addon.calendar.event.CalendarEvent#getDescription() + */ + public String getDescription() { + return description; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.addon.calendar.event.CalendarEvent#getEnd() + */ + public Date getEnd() { + return end; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.addon.calendar.event.CalendarEvent#getStart() + */ + public Date getStart() { + return start; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.addon.calendar.event.CalendarEvent#getStyleName() + */ + public String getStyleName() { + return styleName; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.addon.calendar.event.CalendarEvent#isAllDay() + */ + public boolean isAllDay() { + return isAllDay; + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventEditor#setCaption(java.lang + * .String) + */ + public void setCaption(String caption) { + this.caption = caption; + fireEventChange(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventEditor#setDescription(java + * .lang.String) + */ + public void setDescription(String description) { + this.description = description; + fireEventChange(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventEditor#setEnd(java.util. + * Date) + */ + public void setEnd(Date end) { + this.end = end; + fireEventChange(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventEditor#setStart(java.util + * .Date) + */ + public void setStart(Date start) { + this.start = start; + fireEventChange(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventEditor#setStyleName(java + * .lang.String) + */ + public void setStyleName(String styleName) { + this.styleName = styleName; + fireEventChange(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventEditor#setAllDay(boolean) + */ + public void setAllDay(boolean isAllDay) { + this.isAllDay = isAllDay; + fireEventChange(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeListener + * ) + */ + public void addEventChangeListener(EventChangeListener listener) { + listeners.add(listener); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeNotifier + * #removeListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeListener + * ) + */ + public void removeEventChangeListener(EventChangeListener listener) { + listeners.remove(listener); + } + + /** + * Fires an event change event to the listeners. Should be triggered when + * some property of the event changes. + */ + protected void fireEventChange() { + EventChangeEvent event = new EventChangeEvent(this); + + for (EventChangeListener listener : listeners) { + listener.eventChange(event); + } + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/event/BasicEventProvider.java b/server/src/com/vaadin/ui/components/calendar/event/BasicEventProvider.java new file mode 100644 index 0000000000..0314652245 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/event/BasicEventProvider.java @@ -0,0 +1,173 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.event; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeEvent; +import com.vaadin.ui.components.calendar.event.CalendarEventProvider.EventSetChangeNotifier; + +/** + * <p> + * Simple implementation of + * {@link com.vaadin.addon.calendar.event.CalendarEventProvider + * CalendarEventProvider}. Use {@link #addEvent(CalendarEvent)} and + * {@link #removeEvent(CalendarEvent)} to add / remove events. + * </p> + * + * <p> + * {@link com.vaadin.addon.calendar.event.CalendarEventProvider.EventSetChangeNotifier + * EventSetChangeNotifier} and + * {@link com.vaadin.addon.calendar.event.CalendarEvent.EventChangeListener + * EventChangeListener} are also implemented, so the Calendar is notified when + * an event is added, changed or removed. + * </p> + * + * @since 7.1.0 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class BasicEventProvider implements CalendarEditableEventProvider, + EventSetChangeNotifier, CalendarEvent.EventChangeListener { + + protected List<CalendarEvent> eventList = new ArrayList<CalendarEvent>(); + + private List<EventSetChangeListener> listeners = new ArrayList<EventSetChangeListener>(); + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEventProvider#getEvents(java. + * util.Date, java.util.Date) + */ + public List<CalendarEvent> getEvents(Date startDate, Date endDate) { + ArrayList<CalendarEvent> activeEvents = new ArrayList<CalendarEvent>(); + + for (CalendarEvent ev : eventList) { + long from = startDate.getTime(); + long to = endDate.getTime(); + + if (ev.getStart() != null && ev.getEnd() != null) { + long f = ev.getStart().getTime(); + long t = ev.getEnd().getTime(); + // Select only events that overlaps with startDate and + // endDate. + if ((f <= to && f >= from) || (t >= from && t <= to) + || (f <= from && t >= to)) { + activeEvents.add(ev); + } + } + } + + return activeEvents; + } + + /** + * Does this event provider container this event + * + * @param event + * The event to check for + * @return If this provider has the event then true is returned, else false + */ + public boolean containsEvent(BasicEvent event) { + return eventList.contains(event); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChangeNotifier + * #addListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChangeListener + * ) + */ + public void addEventSetChangeListener(EventSetChangeListener listener) { + listeners.add(listener); + + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChangeNotifier + * #removeListener + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChangeListener + * ) + */ + public void removeEventSetChangeListener(EventSetChangeListener listener) { + listeners.remove(listener); + } + + /** + * Fires a eventsetchange event. The event is fired when either an event is + * added or removed to the event provider + */ + protected void fireEventSetChange() { + EventSetChangeEvent event = new EventSetChangeEvent(this); + + for (EventSetChangeListener listener : listeners) { + listener.eventSetChange(event); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeListener + * #eventChange + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChange) + */ + public void eventChange(EventChangeEvent changeEvent) { + // naive implementation + fireEventSetChange(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#addEvent + * (com.vaadin.addon.calendar.event.CalendarEvent) + */ + public void addEvent(CalendarEvent event) { + eventList.add(event); + if (event instanceof BasicEvent) { + ((BasicEvent) event).addEventChangeListener(this); + } + fireEventSetChange(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#removeEvent + * (com.vaadin.addon.calendar.event.CalendarEvent) + */ + public void removeEvent(CalendarEvent event) { + eventList.remove(event); + if (event instanceof BasicEvent) { + ((BasicEvent) event).removeEventChangeListener(this); + } + fireEventSetChange(); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/event/CalendarEditableEventProvider.java b/server/src/com/vaadin/ui/components/calendar/event/CalendarEditableEventProvider.java new file mode 100644 index 0000000000..145d2b4aa4 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/event/CalendarEditableEventProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */package com.vaadin.ui.components.calendar.event; + +/** + * An event provider which allows adding and removing events + * + * @since 7.1.0 + * @author Vaadin Ltd. + */ +public interface CalendarEditableEventProvider extends CalendarEventProvider { + + /** + * Adds an event to the event provider + * + * @param event + * The event to add + */ + void addEvent(CalendarEvent event); + + /** + * Removes an event from the event provider + * + * @param event + * The event + */ + void removeEvent(CalendarEvent event); +} diff --git a/server/src/com/vaadin/ui/components/calendar/event/CalendarEvent.java b/server/src/com/vaadin/ui/components/calendar/event/CalendarEvent.java new file mode 100644 index 0000000000..531ee72c7f --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/event/CalendarEvent.java @@ -0,0 +1,146 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.event; + +import java.io.Serializable; +import java.util.Date; + +/** + * <p> + * Event in the calendar. Customize your own event by implementing this + * interface. + * </p> + * + * <li>Start and end fields are mandatory.</li> + * + * <li>In "allDay" events longer than one day, starting and ending clock times + * are omitted in UI and only dates are shown.</li> + * + * @since 7.1.0 + * @author Vaadin Ltd. + * + */ +public interface CalendarEvent extends Serializable { + + /** + * Gets start date of event. + * + * @return Start date. + */ + public Date getStart(); + + /** + * Get end date of event. + * + * @return End date; + */ + public Date getEnd(); + + /** + * Gets caption of event. + * + * @return Caption text + */ + public String getCaption(); + + /** + * Gets description of event. Shown as a tooltip over the event. + * + * @return Description text. + */ + public String getDescription(); + + /** + * <p> + * Gets style name of event. In the client, style name will be set to the + * event's element class name and can be styled by CSS + * </p> + * Styling example:</br> <code>Java code: </br> + * event.setStyleName("color1"); + * </br></br> + * CSS:</br> + * .v-calendar-event-color1 {</br> + * background-color: #9effae;</br>}</code> + * + * @return Style name. + */ + public String getStyleName(); + + /** + * An all-day event typically does not occur at a specific time but targets + * a whole day or days. The rendering of all-day events differs from normal + * events. + * + * @return true if this event is an all-day event, false otherwise + */ + public boolean isAllDay(); + + /** + * Event to signal that an event has changed. + */ + @SuppressWarnings("serial") + public class EventChangeEvent implements Serializable { + + private CalendarEvent source; + + public EventChangeEvent(CalendarEvent source) { + this.source = source; + } + + /** + * @return the {@link com.vaadin.addon.calendar.event.CalendarEvent + * CalendarEvent} that has changed + */ + public CalendarEvent getCalendarEvent() { + return source; + } + } + + /** + * Listener for EventSetChange events. + */ + public interface EventChangeListener extends Serializable { + + /** + * Called when an Event has changed. + */ + public void eventChange(EventChangeEvent eventChangeEvent); + } + + /** + * Notifier interface for EventChange events. + */ + public interface EventChangeNotifier extends Serializable { + + /** + * Add a listener to listen for EventChangeEvents. These events are + * fired when a events properties are changed. + * + * @param listener + * The listener to add + */ + void addEventChangeListener(EventChangeListener listener); + + /** + * Remove a listener from the event provider. + * + * @param listener + * The listener to remove + */ + void removeEventChangeListener(EventChangeListener listener); + } + +} diff --git a/server/src/com/vaadin/ui/components/calendar/event/CalendarEventProvider.java b/server/src/com/vaadin/ui/components/calendar/event/CalendarEventProvider.java new file mode 100644 index 0000000000..fefb2ca9b6 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/event/CalendarEventProvider.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.event; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * Interface for querying events. The Vaadin Calendar always has a + * CalendarEventProvider set. + * + * @since 7.1.0 + * @author Vaadin Ltd. + */ +public interface CalendarEventProvider extends Serializable { + /** + * <p> + * Gets all available events in the target date range between startDate and + * endDate. The Vaadin Calendar queries the events from the range that is + * shown, which is not guaranteed to be the same as the date range that is + * set. + * </p> + * + * <p> + * For example, if you set the date range to be monday 22.2.2010 - wednesday + * 24.2.2000, the used Event Provider will be queried for events between + * monday 22.2.2010 00:00 and sunday 28.2.2010 23:59. Generally you can + * expect the date range to be expanded to whole days and whole weeks. + * </p> + * + * @param startDate + * Start date + * @param endDate + * End date + * @return List of events + */ + public List<CalendarEvent> getEvents(Date startDate, Date endDate); + + /** + * Event to signal that the set of events has changed and the calendar + * should refresh its view from the + * {@link com.vaadin.addon.calendar.event.CalendarEventProvider + * CalendarEventProvider} . + * + */ + @SuppressWarnings("serial") + public class EventSetChangeEvent implements Serializable { + + private CalendarEventProvider source; + + public EventSetChangeEvent(CalendarEventProvider source) { + this.source = source; + } + + /** + * @return the + * {@link com.vaadin.addon.calendar.event.CalendarEventProvider + * CalendarEventProvider} that has changed + */ + public CalendarEventProvider getProvider() { + return source; + } + } + + /** + * Listener for EventSetChange events. + */ + public interface EventSetChangeListener extends Serializable { + + /** + * Called when the set of Events has changed. + */ + public void eventSetChange(EventSetChangeEvent changeEvent); + } + + /** + * Notifier interface for EventSetChange events. + */ + public interface EventSetChangeNotifier extends Serializable { + + /** + * Add a listener for listening to when new events are adding or removed + * from the event provider. + * + * @param listener + * The listener to add + */ + void addEventSetChangeListener(EventSetChangeListener listener); + + /** + * Remove a listener which listens to {@link EventSetChangeEvent}-events + * + * @param listener + * The listener to remove + */ + void removeEventSetChangeListener(EventSetChangeListener listener); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/event/EditableCalendarEvent.java b/server/src/com/vaadin/ui/components/calendar/event/EditableCalendarEvent.java new file mode 100644 index 0000000000..e8a27ad50f --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/event/EditableCalendarEvent.java @@ -0,0 +1,91 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.event; + +import java.util.Date; + +/** + * <p> + * Extension to the basic {@link com.vaadin.addon.calendar.event.CalendarEvent + * CalendarEvent}. This interface provides setters (and thus editing + * capabilities) for all {@link com.vaadin.addon.calendar.event.CalendarEvent + * CalendarEvent} fields. For descriptions on the fields, refer to the extended + * interface. + * </p> + * + * <p> + * This interface is used by some of the basic Calendar event handlers in the + * <code>com.vaadin.addon.calendar.ui.handler</code> package to determine + * whether an event can be edited. + * </p> + * + * @since 7.1 + * @author Vaadin Ltd. + */ +public interface EditableCalendarEvent extends CalendarEvent { + + /** + * Set the visible text in the calendar for the event. + * + * @param caption + * The text to show in the calendar + */ + void setCaption(String caption); + + /** + * Set the description of the event. This is shown in the calendar when + * hoovering over the event. + * + * @param description + * The text which describes the event + */ + void setDescription(String description); + + /** + * Set the end date of the event. Must be after the start date. + * + * @param end + * The end date to set + */ + void setEnd(Date end); + + /** + * Set the start date for the event. Must be before the end date + * + * @param start + * The start date of the event + */ + void setStart(Date start); + + /** + * Set the style name for the event used for styling the event cells + * + * @param styleName + * The stylename to use + * + */ + void setStyleName(String styleName); + + /** + * Does the event span the whole day. If so then set this to true + * + * @param isAllDay + * True if the event spans the whole day. In this case the start + * and end times are ignored. + */ + void setAllDay(boolean isAllDay); + +} diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java new file mode 100644 index 0000000000..fc2bfd6df4 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.handler; + +import java.util.Calendar; +import java.util.Date; + +import com.vaadin.shared.ui.calendar.DateConstants; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardEvent; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardHandler; + +/** + * Implements basic functionality needed to enable backwards navigation. + * + * @since 7.1 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class BasicBackwardHandler implements BackwardHandler { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.BackwardHandler# + * backward + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.BackwardEvent) + */ + public void backward(BackwardEvent event) { + Date start = event.getComponent().getStartDate(); + Date end = event.getComponent().getEndDate(); + + // calculate amount to move back + int durationInDays = (int) (((end.getTime()) - start.getTime()) / DateConstants.DAYINMILLIS); + durationInDays++; + durationInDays = -durationInDays; + + // set new start and end times + Calendar javaCalendar = event.getComponent().getInternalCalendar(); + javaCalendar.setTime(start); + javaCalendar.add(java.util.Calendar.DATE, durationInDays); + Date newStart = javaCalendar.getTime(); + + javaCalendar.setTime(end); + javaCalendar.add(java.util.Calendar.DATE, durationInDays); + Date newEnd = javaCalendar.getTime(); + + setDates(event, newStart, newEnd); + } + + /** + * Set the start and end dates for the event + * + * @param event + * The event that the start and end dates should be set + * @param start + * The start date + * @param end + * The end date + */ + protected void setDates(BackwardEvent event, Date start, Date end) { + event.getComponent().setStartDate(start); + event.getComponent().setEndDate(end); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicDateClickHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicDateClickHandler.java new file mode 100644 index 0000000000..c91a238b86 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicDateClickHandler.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.handler; + +import java.util.Calendar; +import java.util.Date; + +import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickEvent; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickHandler; + +/** + * Implements basic functionality needed to switch to day view when a single day + * is clicked. + * + * @since 7.1 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class BasicDateClickHandler implements DateClickHandler { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.DateClickHandler + * #dateClick + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.DateClickEvent) + */ + public void dateClick(DateClickEvent event) { + Date clickedDate = event.getDate(); + + Calendar javaCalendar = event.getComponent().getInternalCalendar(); + javaCalendar.setTime(clickedDate); + + // as times are expanded, this is all that is needed to show one day + Date start = javaCalendar.getTime(); + Date end = javaCalendar.getTime(); + + setDates(event, start, end); + } + + /** + * Set the start and end dates for the event + * + * @param event + * The event that the start and end dates should be set + * @param start + * The start date + * @param end + * The end date + */ + protected void setDates(DateClickEvent event, Date start, Date end) { + event.getComponent().setStartDate(start); + event.getComponent().setEndDate(end); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicEventMoveHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicEventMoveHandler.java new file mode 100644 index 0000000000..139837f339 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicEventMoveHandler.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.handler; + +import java.util.Date; + +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventMoveHandler; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.MoveEvent; +import com.vaadin.ui.components.calendar.event.CalendarEvent; +import com.vaadin.ui.components.calendar.event.EditableCalendarEvent; + +/** + * Implements basic functionality needed to enable moving events. + * + * @since 7.1 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class BasicEventMoveHandler implements EventMoveHandler { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveHandler + * #eventMove + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.MoveEvent) + */ + public void eventMove(MoveEvent event) { + CalendarEvent calendarEvent = event.getCalendarEvent(); + + if (calendarEvent instanceof EditableCalendarEvent) { + + EditableCalendarEvent editableEvent = (EditableCalendarEvent) calendarEvent; + + Date newFromTime = event.getNewStart(); + + // Update event dates + long length = editableEvent.getEnd().getTime() + - editableEvent.getStart().getTime(); + setDates(editableEvent, newFromTime, new Date(newFromTime.getTime() + + length)); + } + } + + /** + * Set the start and end dates for the event + * + * @param event + * The event that the start and end dates should be set + * @param start + * The start date + * @param end + * The end date + */ + protected void setDates(EditableCalendarEvent event, Date start, Date end) { + event.setStart(start); + event.setEnd(end); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicEventResizeHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicEventResizeHandler.java new file mode 100644 index 0000000000..c052d0d77b --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicEventResizeHandler.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.handler; + +import java.util.Date; + +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResize; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResizeHandler; +import com.vaadin.ui.components.calendar.event.CalendarEvent; +import com.vaadin.ui.components.calendar.event.EditableCalendarEvent; + +/** + * Implements basic functionality needed to enable event resizing. + * + * @since 7.1 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class BasicEventResizeHandler implements EventResizeHandler { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeHandler + * #eventResize + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResize) + */ + public void eventResize(EventResize event) { + CalendarEvent calendarEvent = event.getCalendarEvent(); + + if (calendarEvent instanceof EditableCalendarEvent) { + Date newStartTime = event.getNewStart(); + Date newEndTime = event.getNewEnd(); + + EditableCalendarEvent editableEvent = (EditableCalendarEvent) calendarEvent; + + setDates(editableEvent, newStartTime, newEndTime); + } + } + + /** + * Set the start and end dates for the event + * + * @param event + * The event that the start and end dates should be set + * @param start + * The start date + * @param end + * The end date + */ + protected void setDates(EditableCalendarEvent event, Date start, Date end) { + event.setStart(start); + event.setEnd(end); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java new file mode 100644 index 0000000000..a5307ffd5c --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java @@ -0,0 +1,76 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.handler; + +import java.util.Calendar; +import java.util.Date; + +import com.vaadin.shared.ui.calendar.DateConstants; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardEvent; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardHandler; + +/** + * Implements basic functionality needed to enable forward navigation. + * + * @since 7.1 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class BasicForwardHandler implements ForwardHandler { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.ForwardHandler#forward + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.ForwardEvent) + */ + public void forward(ForwardEvent event) { + Date start = event.getComponent().getStartDate(); + Date end = event.getComponent().getEndDate(); + + // calculate amount to move forward + int durationInDays = (int) (((end.getTime()) - start.getTime()) / DateConstants.DAYINMILLIS); + durationInDays++; + + // set new start and end times + Calendar javaCalendar = Calendar.getInstance(); + javaCalendar.setTime(start); + javaCalendar.add(java.util.Calendar.DATE, durationInDays); + Date newStart = javaCalendar.getTime(); + + javaCalendar.setTime(end); + javaCalendar.add(java.util.Calendar.DATE, durationInDays); + Date newEnd = javaCalendar.getTime(); + + setDates(event, newStart, newEnd); + } + + /** + * Set the start and end dates for the event + * + * @param event + * The event that the start and end dates should be set + * @param start + * The start date + * @param end + * The end date + */ + protected void setDates(ForwardEvent event, Date start, Date end) { + event.getComponent().setStartDate(start); + event.getComponent().setEndDate(end); + } +} diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicWeekClickHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicWeekClickHandler.java new file mode 100644 index 0000000000..49efe49e48 --- /dev/null +++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicWeekClickHandler.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui.components.calendar.handler; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClick; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClickHandler; + +/** + * Implements basic functionality needed to change to week view when a week + * number is clicked. + * + * @since 7.1 + * @author Vaadin Ltd. + */ +@SuppressWarnings("serial") +public class BasicWeekClickHandler implements WeekClickHandler { + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.addon.calendar.ui.CalendarComponentEvents.WeekClickHandler + * #weekClick + * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.WeekClick) + */ + public void weekClick(WeekClick event) { + int week = event.getWeek(); + int year = event.getYear(); + + // set correct year and month + Calendar javaCalendar = event.getComponent().getInternalCalendar(); + javaCalendar.set(GregorianCalendar.YEAR, year); + javaCalendar.set(GregorianCalendar.WEEK_OF_YEAR, week); + + // starting at the beginning of the week + javaCalendar.set(GregorianCalendar.DAY_OF_WEEK, + javaCalendar.getFirstDayOfWeek()); + Date start = javaCalendar.getTime(); + + // ending at the end of the week + javaCalendar.add(GregorianCalendar.DATE, 6); + Date end = javaCalendar.getTime(); + + setDates(event, start, end); + + // times are automatically expanded, no need to worry about them + } + + /** + * Set the start and end dates for the event + * + * @param event + * The event that the start and end dates should be set + * @param start + * The start date + * @param end + * The end date + */ + protected void setDates(WeekClick event, Date start, Date end) { + event.getComponent().setStartDate(start); + event.getComponent().setEndDate(end); + } + +} |