From ba8d0866d0785e852d12ed81f6514c36f3e1544d Mon Sep 17 00:00:00 2001 From: Steven Spungin Date: Fri, 1 May 2015 11:44:42 -0400 Subject: [PATCH] Add method to auto scale calendar time range (#17715) Backported from master branch (Vaadin 8). Change-Id: I363c9798de0d238a5a4aa4b4e839a31da460434f --- .../src/main/java/com/vaadin/ui/Calendar.java | 128 +++++++++++++++--- .../calendar/ContainerDataSourceTest.java | 54 ++++++++ 2 files changed, 160 insertions(+), 22 deletions(-) diff --git a/server/src/main/java/com/vaadin/ui/Calendar.java b/server/src/main/java/com/vaadin/ui/Calendar.java index 741e2bb45a..4870cc73f2 100644 --- a/server/src/main/java/com/vaadin/ui/Calendar.java +++ b/server/src/main/java/com/vaadin/ui/Calendar.java @@ -220,6 +220,18 @@ public class Calendar extends AbstractComponent */ private CalendarServerRpcImpl rpc = new CalendarServerRpcImpl(); + /** + * The cached minimum minute shown when using + * {@link #autoScaleVisibleHoursOfDay()}. + */ + private Integer minTimeInMinutes; + + /** + * The cached maximum minute shown when using + * {@link #autoScaleVisibleHoursOfDay()}. + */ + private Integer maxTimeInMinutes; + private Integer customFirstDayOfWeek; /** @@ -436,7 +448,7 @@ public class Calendar extends AbstractComponent } private void setupCalendarEvents() { - int durationInDays = (int) (((endDate.getTime()) - startDate.getTime()) + int durationInDays = (int) ((endDate.getTime() - startDate.getTime()) / DateConstants.DAYINMILLIS); durationInDays++; if (durationInDays > 60) { @@ -449,6 +461,7 @@ public class Calendar extends AbstractComponent currentCalendar.setTime(firstDateToShow); events = getEventProvider().getEvents(firstDateToShow, lastDateToShow); + cacheMinMaxTimeOfDay(events); List calendarStateEvents = new ArrayList(); if (events != null) { @@ -472,6 +485,76 @@ public class Calendar extends AbstractComponent getState().events = calendarStateEvents; } + /** + * Stores the minimum and maximum time-of-day in minutes for the events. + * + * @param events + * A list of calendar events. Can be null. + */ + private void cacheMinMaxTimeOfDay(List events) { + minTimeInMinutes = null; + maxTimeInMinutes = null; + if (events != null) { + for (CalendarEvent event : events) { + int minuteOfDayStart = getMinuteOfDay(event.getStart()); + int minuteOfDayEnd = getMinuteOfDay(event.getEnd()); + if (minTimeInMinutes == null) { + minTimeInMinutes = minuteOfDayStart; + maxTimeInMinutes = minuteOfDayEnd; + } else { + if (minuteOfDayStart < minTimeInMinutes) { + minTimeInMinutes = minuteOfDayStart; + } + if (minuteOfDayEnd > maxTimeInMinutes) { + maxTimeInMinutes = minuteOfDayEnd; + } + } + } + } + } + + private static int getMinuteOfDay(Date date) { + java.util.Calendar calendar = java.util.Calendar.getInstance(); + calendar.setTime(date); + return calendar.get(java.util.Calendar.HOUR_OF_DAY) * 60 + + calendar.get(java.util.Calendar.MINUTE); + } + + /** + * Sets the displayed start and end time to fit all current events that were + * retrieved from the last call to getEvents(). + *

+ * If no events exist, nothing happens. + *

+ * NOTE: triggering this method only does this once for the current + * events - events that are not in the current visible range, are + * ignored! + * + * @see #setFirstVisibleHourOfDay(int) + * @see #setLastVisibleHourOfDay(int) + */ + public void autoScaleVisibleHoursOfDay() { + if (minTimeInMinutes != null) { + setFirstVisibleHourOfDay(minTimeInMinutes / 60); + // Do not show the final hour if last minute ends on it + setLastVisibleHourOfDay((maxTimeInMinutes - 1) / 60); + } + } + + /** + * Resets the {@link #setFirstVisibleHourOfDay(int)} and + * {@link #setLastVisibleHourOfDay(int)} to the default values, 0 and 23 + * respectively. + * + * @see #autoScaleVisibleHoursOfDay() + * @see #setFirstVisibleHourOfDay(int) + * @see #setLastVisibleHourOfDay(int) + */ + public void resetVisibleHoursOfDay() { + setFirstVisibleHourOfDay(0); + setLastVisibleHourOfDay(23); + } + private void setupDaysAndActions() { // Make sure we have a up-to-date locale initCalendarWithLocale(); @@ -499,7 +582,7 @@ public class Calendar extends AbstractComponent endDate = getEndDate(); } - int durationInDays = (int) (((endDate.getTime()) - startDate.getTime()) + int durationInDays = (int) ((endDate.getTime() - startDate.getTime()) / DateConstants.DAYINMILLIS); durationInDays++; if (durationInDays > 60) { @@ -520,7 +603,7 @@ public class Calendar extends AbstractComponent df_date.setTimeZone(currentCalendar.getTimeZone()); df_time.setTimeZone(currentCalendar.getTimeZone()); - state.now = (df_date.format(now) + " " + df_time.format(now)); + state.now = df_date.format(now) + " " + df_time.format(now); Date firstDateToShow = expandStartDate(startDate, durationInDays > 7); Date lastDateToShow = expandEndDate(endDate, durationInDays > 7); @@ -566,7 +649,7 @@ public class Calendar extends AbstractComponent cal.add(java.util.Calendar.SECOND, -1); Date end = cal.getTime(); - boolean monthView = (durationInDays > 7); + boolean monthView = durationInDays > 7; /** * If in day or week view add actions for each half-an-hour. @@ -632,8 +715,7 @@ public class Calendar extends AbstractComponent getTimeZone()); Action[] actions = actionHandler.getActions(range, this); if (actions != null) { - Set actionSet = new LinkedHashSet( - Arrays.asList(actions)); + Set actionSet = new LinkedHashSet(Arrays.asList(actions)); actionMap.put(range, actionSet); } } @@ -820,19 +902,19 @@ public class Calendar extends AbstractComponent } /** - *

* This method restricts the hours that are shown per day. This affects the * weekly view. The general contract is that firstHour < lastHour. - *

- * *

* Note that this only affects the rendering process. Events are still * requested by the dates set by {@link #setStartDate(Date)} and * {@link #setEndDate(Date)}. - *

+ *

+ * You can use {@link #autoScaleVisibleHoursOfDay()} for automatic scaling + * of the visible hours based on current events. * * @param firstHour * the first hour of the day to show, between 0 and 23 + * @see #autoScaleVisibleHoursOfDay() */ public void setFirstVisibleHourOfDay(int firstHour) { if (this.firstHour != firstHour && firstHour >= 0 && firstHour <= 23 @@ -852,19 +934,19 @@ public class Calendar extends AbstractComponent } /** - *

* This method restricts the hours that are shown per day. This affects the * weekly view. The general contract is that firstHour < lastHour. - *

- * *

* Note that this only affects the rendering process. Events are still * requested by the dates set by {@link #setStartDate(Date)} and * {@link #setEndDate(Date)}. - *

+ *

+ * You can use {@link #autoScaleVisibleHoursOfDay()} for automatic scaling + * of the visible hours based on current events. * * @param lastHour * the first hour of the day to show, between 0 and 23 + * @see #autoScaleVisibleHoursOfDay() */ public void setLastVisibleHourOfDay(int lastHour) { if (this.lastHour != lastHour && lastHour >= 0 && lastHour <= 23 @@ -900,9 +982,9 @@ public class Calendar extends AbstractComponent * The date caption pattern. */ public void setWeeklyCaptionFormat(String dateFormatPattern) { - if ((weeklyCaptionFormat == null && dateFormatPattern != null) - || (weeklyCaptionFormat != null - && !weeklyCaptionFormat.equals(dateFormatPattern))) { + if (weeklyCaptionFormat == null && dateFormatPattern != null + || weeklyCaptionFormat != null + && !weeklyCaptionFormat.equals(dateFormatPattern)) { weeklyCaptionFormat = dateFormatPattern; markAsDirty(); } @@ -929,7 +1011,7 @@ public class Calendar extends AbstractComponent // monday first if (calendar.getFirstDayOfWeek() == java.util.Calendar.MONDAY) { - fow = (fow == java.util.Calendar.SUNDAY) ? 7 : fow - 1; + fow = fow == java.util.Calendar.SUNDAY ? 7 : fow - 1; } return fow; @@ -1610,7 +1692,10 @@ public class Calendar extends AbstractComponent */ @Override public List getEvents(Date startDate, Date endDate) { - return getEventProvider().getEvents(startDate, endDate); + List events = getEventProvider().getEvents(startDate, + endDate); + cacheMinMaxTimeOfDay(events); + return events; } /* @@ -1687,7 +1772,7 @@ public class Calendar extends AbstractComponent public void addActionHandler(Handler actionHandler) { if (actionHandler != null) { if (actionHandlers == null) { - actionHandlers = new LinkedList(); + actionHandlers = new LinkedList(); actionMapper = new KeyMapper(); } if (!actionHandlers.contains(actionHandler)) { @@ -1982,8 +2067,7 @@ public class Calendar extends AbstractComponent if (currentTimeFormat != null) { design.attr("time-format", - (currentTimeFormat == TimeFormat.Format12H ? "12h" - : "24h")); + currentTimeFormat == TimeFormat.Format12H ? "12h" : "24h"); } if (startDate != null) { design.attr("start-date", df_date.format(getStartDate())); diff --git a/server/src/test/java/com/vaadin/tests/server/component/calendar/ContainerDataSourceTest.java b/server/src/test/java/com/vaadin/tests/server/component/calendar/ContainerDataSourceTest.java index 1c8f76cc27..baefb22f42 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/calendar/ContainerDataSourceTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/calendar/ContainerDataSourceTest.java @@ -20,7 +20,10 @@ import static org.junit.Assert.assertTrue; import java.util.Date; import java.util.List; +import java.util.Locale; +import java.util.TimeZone; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -361,6 +364,57 @@ public class ContainerDataSourceTest { } } + @Test + public void testAutomaticScaleVisibleHoursOfDay() { + BeanItemContainer container = new BeanItemContainer( + CalendarEvent.class); + java.util.Calendar start = java.util.Calendar.getInstance(); + java.util.Calendar end = java.util.Calendar.getInstance(); + + start.set(java.util.Calendar.HOUR_OF_DAY, 8); + start.set(java.util.Calendar.MINUTE, 10); + // same start and end time + container.addBean( + new BasicEvent("8:00", "Description 1", start.getTime())); + + start.set(java.util.Calendar.HOUR_OF_DAY, 16); + end.set(java.util.Calendar.HOUR_OF_DAY, 18); + end.set(java.util.Calendar.MINUTE, 10); + + container.addBean(new BasicEvent("16-18", "Description 2", + start.getTime(), end.getTime())); // 16-18 + + calendar.setContainerDataSource(container); + calendar.setTimeZone(TimeZone.getDefault()); + calendar.setLocale(Locale.getDefault()); + calendar.beforeClientResponse(true); // simulate adding to UI + + Assert.assertEquals(0, calendar.getFirstVisibleHourOfDay()); + Assert.assertEquals(23, calendar.getLastVisibleHourOfDay()); + + calendar.autoScaleVisibleHoursOfDay(); + Assert.assertEquals(8, calendar.getFirstVisibleHourOfDay()); + Assert.assertEquals(18, calendar.getLastVisibleHourOfDay()); + + // reset visible timing to something else, so that the added event is + // not filtered out + calendar.resetVisibleHoursOfDay(); + calendar.beforeClientResponse(false); // simulate being attached + + Assert.assertEquals(0, calendar.getFirstVisibleHourOfDay()); + Assert.assertEquals(23, calendar.getLastVisibleHourOfDay()); + + start.set(java.util.Calendar.HOUR_OF_DAY, 5); + end.set(java.util.Calendar.HOUR_OF_DAY, 21); + container.addBean(new BasicEvent("05-21", "Description 3", + start.getTime(), end.getTime())); // 05-21 + + calendar.beforeClientResponse(false); // simulate being attached + calendar.autoScaleVisibleHoursOfDay(); + Assert.assertEquals(5, calendar.getFirstVisibleHourOfDay()); + Assert.assertEquals(21, calendar.getLastVisibleHourOfDay()); + } + private static Indexed createTestBeanItemContainer() { BeanItemContainer eventContainer = new BeanItemContainer( CalendarEvent.class); -- 2.39.5