]> source.dussan.org Git - vaadin-framework.git/commitdiff
Add method to auto scale calendar time range (#17715)
authorSteven Spungin <steven@spungin.tv>
Fri, 1 May 2015 15:44:42 +0000 (11:44 -0400)
committerPekka Hyvönen <pekka@vaadin.com>
Fri, 4 Nov 2016 14:03:53 +0000 (16:03 +0200)
Backported from master branch (Vaadin 8).

Change-Id: I363c9798de0d238a5a4aa4b4e839a31da460434f

server/src/main/java/com/vaadin/ui/Calendar.java
server/src/test/java/com/vaadin/tests/server/component/calendar/ContainerDataSourceTest.java

index 741e2bb45ac639473d2c51cd55884a6a8776b834..4870cc73f28755d0185622b6bb08ecae45c24b1c 100644 (file)
@@ -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<CalendarState.Event> calendarStateEvents = new ArrayList<CalendarState.Event>();
         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 <code>null</code>.
+     */
+    private void cacheMinMaxTimeOfDay(List<CalendarEvent> 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().
+     * <p>
+     * If no events exist, nothing happens.
+     * <p>
+     * <b>NOTE: triggering this method only does this once for the current
+     * events - events that are not in the current visible range, are
+     * ignored!</b>
+     *
+     * @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<Action> actionSet = new LinkedHashSet<Action>(
-                    Arrays.asList(actions));
+            Set<Action> actionSet = new LinkedHashSet<Action>(Arrays.asList(actions));
             actionMap.put(range, actionSet);
         }
     }
@@ -820,19 +902,19 @@ public class Calendar extends AbstractComponent
     }
 
     /**
-     * <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>
+     * <p>
+     * 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
     }
 
     /**
-     * <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>
+     * <p>
+     * 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<CalendarEvent> getEvents(Date startDate, Date endDate) {
-        return getEventProvider().getEvents(startDate, endDate);
+        List<CalendarEvent> 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<Action.Handler>();
+                actionHandlers = new LinkedList<Handler>();
                 actionMapper = new KeyMapper<Action>();
             }
             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()));
index 1c8f76cc2763edb335f04c55ff38ba37a2d42c6c..baefb22f42293ec2e4b9877d1f9f5ae4f79e506c 100644 (file)
@@ -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<CalendarEvent> container = new BeanItemContainer<CalendarEvent>(
+                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<CalendarEvent> eventContainer = new BeanItemContainer<CalendarEvent>(
                 CalendarEvent.class);