diff options
23 files changed, 691 insertions, 602 deletions
diff --git a/all/src/main/templates/release-notes.html b/all/src/main/templates/release-notes.html index f2c9a6523e..d9d006d23f 100644 --- a/all/src/main/templates/release-notes.html +++ b/all/src/main/templates/release-notes.html @@ -123,6 +123,7 @@ <li><tt>Notification</tt> method <tt>show</tt> returns <tt>Notification</tt>, instead of <tt>void</tt>.</li> <li><tt>SharedState</tt> field <tt>registeredEventListeners</tt> is a <tt>Map</tt> instead of <tt>Set</tt>.</li> <li>The client side <tt>SelectionModel</tt> interface has a new method <tt>isMultiSelectionAllowed</tt>.</li> + <li><tt>AbstractDateField</tt> is not a <tt>LegacyComponent</tt> anymore.</li> <h2>For incompatible or behavior-altering changes in 8.1, please see <a href="https://vaadin.com/download/release/8.1/8.1.0/release-notes.html#incompatible">8.1 release notes</a></h2> diff --git a/client/src/main/java/com/vaadin/client/ApplicationConnection.java b/client/src/main/java/com/vaadin/client/ApplicationConnection.java index 15a36315b0..79432fb0a2 100644 --- a/client/src/main/java/com/vaadin/client/ApplicationConnection.java +++ b/client/src/main/java/com/vaadin/client/ApplicationConnection.java @@ -1358,8 +1358,7 @@ public class ApplicationConnection implements HasHandlers { return false; } - return hasEventListeners(getConnectorMap().getConnector(widget), - eventIdentifier); + return hasEventListeners(connector, eventIdentifier); } LayoutManager getLayoutManager() { diff --git a/client/src/main/java/com/vaadin/client/DateTimeService.java b/client/src/main/java/com/vaadin/client/DateTimeService.java index 577b079ce2..c1f6d70815 100644 --- a/client/src/main/java/com/vaadin/client/DateTimeService.java +++ b/client/src/main/java/com/vaadin/client/DateTimeService.java @@ -35,7 +35,7 @@ import com.vaadin.shared.ui.datefield.DateResolution; @SuppressWarnings("deprecation") public class DateTimeService { - private String currentLocale; + private String locale; private static int[] maxDaysInMonth = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; @@ -44,7 +44,7 @@ public class DateTimeService { * Creates a new date time service with the application default locale. */ public DateTimeService() { - currentLocale = LocaleService.getDefaultLocale(); + locale = LocaleService.getDefaultLocale(); } /** @@ -59,20 +59,19 @@ public class DateTimeService { } public void setLocale(String locale) throws LocaleNotLoadedException { - if (LocaleService.getAvailableLocales().contains(locale)) { - currentLocale = locale; - } else { + if (!LocaleService.getAvailableLocales().contains(locale)) { throw new LocaleNotLoadedException(locale); } + this.locale = locale; } public String getLocale() { - return currentLocale; + return locale; } public String getMonth(int month) { try { - return LocaleService.getMonthNames(currentLocale)[month]; + return LocaleService.getMonthNames(locale)[month]; } catch (final LocaleNotLoadedException e) { getLogger().log(Level.SEVERE, "Error in getMonth", e); return null; @@ -81,7 +80,7 @@ public class DateTimeService { public String getShortMonth(int month) { try { - return LocaleService.getShortMonthNames(currentLocale)[month]; + return LocaleService.getShortMonthNames(locale)[month]; } catch (final LocaleNotLoadedException e) { getLogger().log(Level.SEVERE, "Error in getShortMonth", e); return null; @@ -90,7 +89,7 @@ public class DateTimeService { public String getDay(int day) { try { - return LocaleService.getDayNames(currentLocale)[day]; + return LocaleService.getDayNames(locale)[day]; } catch (final LocaleNotLoadedException e) { getLogger().log(Level.SEVERE, "Error in getDay", e); return null; @@ -99,7 +98,7 @@ public class DateTimeService { public String getShortDay(int day) { try { - return LocaleService.getShortDayNames(currentLocale)[day]; + return LocaleService.getShortDayNames(locale)[day]; } catch (final LocaleNotLoadedException e) { getLogger().log(Level.SEVERE, "Error in getShortDay", e); return null; @@ -108,7 +107,7 @@ public class DateTimeService { public int getFirstDayOfWeek() { try { - return LocaleService.getFirstDayOfWeek(currentLocale); + return LocaleService.getFirstDayOfWeek(locale); } catch (final LocaleNotLoadedException e) { getLogger().log(Level.SEVERE, "Error in getFirstDayOfWeek", e); return 0; @@ -117,7 +116,7 @@ public class DateTimeService { public boolean isTwelveHourClock() { try { - return LocaleService.isTwelveHourClock(currentLocale); + return LocaleService.isTwelveHourClock(locale); } catch (final LocaleNotLoadedException e) { getLogger().log(Level.SEVERE, "Error in isTwelveHourClock", e); return false; @@ -126,7 +125,7 @@ public class DateTimeService { public String getClockDelimeter() { try { - return LocaleService.getClockDelimiter(currentLocale); + return LocaleService.getClockDelimiter(locale); } catch (final LocaleNotLoadedException e) { getLogger().log(Level.SEVERE, "Error in getClockDelimiter", e); return ":"; @@ -137,7 +136,7 @@ public class DateTimeService { public String[] getAmPmStrings() { try { - return LocaleService.getAmPmStrings(currentLocale); + return LocaleService.getAmPmStrings(locale); } catch (final LocaleNotLoadedException e) { // TODO can this practically even happen? Should die instead? getLogger().log(Level.SEVERE, @@ -151,7 +150,7 @@ public class DateTimeService { date.getMonth(), 1); int firstDay; try { - firstDay = LocaleService.getFirstDayOfWeek(currentLocale); + firstDay = LocaleService.getFirstDayOfWeek(locale); } catch (final LocaleNotLoadedException e) { getLogger().log(Level.SEVERE, "Locale not loaded, using fallback 0", e); diff --git a/client/src/main/java/com/vaadin/client/LocaleService.java b/client/src/main/java/com/vaadin/client/LocaleService.java index b877bca7c5..88d07ee836 100644 --- a/client/src/main/java/com/vaadin/client/LocaleService.java +++ b/client/src/main/java/com/vaadin/client/LocaleService.java @@ -42,7 +42,7 @@ public class LocaleService { if (cache.containsKey(key)) { cache.remove(key); } - getLogger().fine("Received locale data for " + localeData.name); + getLogger().fine("Received locale data for " + key); cache.put(key, localeData); if (cache.size() == 1) { setDefaultLocale(key); diff --git a/client/src/main/java/com/vaadin/client/ui/CalendarEntry.java b/client/src/main/java/com/vaadin/client/ui/CalendarEntry.java index 16e3a15a97..d7bea84758 100644 --- a/client/src/main/java/com/vaadin/client/ui/CalendarEntry.java +++ b/client/src/main/java/com/vaadin/client/ui/CalendarEntry.java @@ -113,10 +113,10 @@ public class CalendarEntry { + "." + start.getDate() + " "; } int i = start.getHours(); - s += (i < 10 ? "0" : "") + i; + s += asTwoDigits(i); s += ":"; i = start.getMinutes(); - s += (i < 10 ? "0" : "") + i; + s += asTwoDigits(i); if (!start.equals(end)) { s += " - "; if (!DateTimeService.isSameDay(start, end)) { @@ -124,10 +124,10 @@ public class CalendarEntry { + "." + end.getDate() + " "; } i = end.getHours(); - s += (i < 10 ? "0" : "") + i; + s += asTwoDigits(i); s += ":"; i = end.getMinutes(); - s += (i < 10 ? "0" : "") + i; + s += asTwoDigits(i); } s += " "; } @@ -137,4 +137,8 @@ public class CalendarEntry { return s; } + private static String asTwoDigits(int i) { + return (i < 10 ? "0" : "") + i; + } + } diff --git a/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java b/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java index 383d67ce70..7ac882f9e4 100644 --- a/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java +++ b/client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java @@ -1153,9 +1153,6 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>> * * @param sender * The component that was clicked - * @param updateVariable - * Should the value field be updated - * */ private void processClickEvent(Widget sender) { if (!isEnabled() || isReadonly()) { diff --git a/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java b/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java index 69da64a86c..85594484b3 100644 --- a/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java +++ b/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java @@ -79,16 +79,16 @@ public abstract class VAbstractPopupCalendar<PANEL extends VAbstractCalendarPane /** For internal use only. May be removed or replaced in the future. */ public boolean parsable = true; - private boolean open = false; + private boolean open; /* * #14857: If calendarToggle button is clicked when calendar popup is * already open we should prevent calling openCalendarPanel() in onClick, * since we don't want to reopen it again right after it closes. */ - private boolean preventOpenPopupCalendar = false; - private boolean cursorOverCalendarToggleButton = false; - private boolean toggleButtonClosesWithGuarantee = false; + private boolean preventOpenPopupCalendar; + private boolean cursorOverCalendarToggleButton; + private boolean toggleButtonClosesWithGuarantee; private boolean textFieldEnabled = true; @@ -217,25 +217,31 @@ public abstract class VAbstractPopupCalendar<PANEL extends VAbstractCalendarPane closeCalendarPanel(); } + /** + * Changes the current date, and updates the + * {@link VDateField#bufferedResolutions}, possibly + * {@link VDateField#sendBufferedValues()} to the server if needed + * + * @param newDate + * the new {@code Date} to update + */ @SuppressWarnings("deprecation") public void updateValue(Date newDate) { Date currentDate = getCurrentDate(); + R resolution = getCurrentResolution(); if (currentDate == null || newDate.getTime() != currentDate.getTime()) { setCurrentDate((Date) newDate.clone()); - getClient().updateVariable(getId(), - getResolutionVariable( - calendar.getResolution(calendar::isYear)), - newDate.getYear() + 1900, false); - if (!calendar.isYear(getCurrentResolution())) { - getClient().updateVariable(getId(), - getResolutionVariable( - calendar.getResolution(calendar::isMonth)), - newDate.getMonth() + 1, false); - if (!calendar.isMonth(getCurrentResolution())) { - getClient().updateVariable(getId(), - getResolutionVariable( - calendar.getResolution(calendar::isDay)), - newDate.getDate(), false); + bufferedResolutions.put( + calendar.getResolution(calendar::isYear).name(), + newDate.getYear() + 1900); + if (!calendar.isYear(resolution)) { + bufferedResolutions.put( + calendar.getResolution(calendar::isMonth).name(), + newDate.getMonth() + 1); + if (!calendar.isMonth(resolution)) { + bufferedResolutions.put( + calendar.getResolution(calendar::isDay).name(), + newDate.getDate()); } } } diff --git a/client/src/main/java/com/vaadin/client/ui/VAbstractTextualDate.java b/client/src/main/java/com/vaadin/client/ui/VAbstractTextualDate.java index d466677419..edbc863188 100644 --- a/client/src/main/java/com/vaadin/client/ui/VAbstractTextualDate.java +++ b/client/src/main/java/com/vaadin/client/ui/VAbstractTextualDate.java @@ -66,7 +66,7 @@ public abstract class VAbstractTextualDate<R extends Enum<R>> /** For internal use only. May be removed or replaced in the future. */ public boolean lenient; - private final String TEXTFIELD_ID = "field"; + private static final String TEXTFIELD_ID = "field"; /** For internal use only. May be removed or replaced in the future. */ private String formatStr; @@ -104,7 +104,7 @@ public abstract class VAbstractTextualDate<R extends Enum<R>> * * @return the format string */ - protected String getFormatString() { + public String getFormatString() { if (formatStr == null) { setFormatString(createFormatString()); } @@ -138,8 +138,8 @@ public abstract class VAbstractTextualDate<R extends Enum<R>> * Sets the date format string to use for the text field. * * @param formatString - * the format string to use, or null to force re-creating the - * format string from the locale the next time it is needed + * the format string to use, or {@code null} to force re-creating + * the format string from the locale the next time it is needed * @since 8.1 */ public void setFormatString(String formatString) { @@ -244,8 +244,7 @@ public abstract class VAbstractTextualDate<R extends Enum<R>> addStyleName(getStylePrimaryName() + PARSE_ERROR_CLASSNAME); // this is a hack that may eventually be removed - getClient().updateVariable(getId(), "lastInvalidDateString", - text.getText(), false); + bufferedInvalidDateString = true; setDate(null); } } else { @@ -253,10 +252,9 @@ public abstract class VAbstractTextualDate<R extends Enum<R>> // remove possibly added invalid value indication removeStyleName(getStylePrimaryName() + PARSE_ERROR_CLASSNAME); } - // always send the date string - getClient().updateVariable(getId(), "dateString", text.getText(), - false); + // always send the date string + bufferedDateString = text.getText(); updateDateVariables(); } @@ -266,17 +264,20 @@ public abstract class VAbstractTextualDate<R extends Enum<R>> * The method can be overridden by subclasses to provide a custom logic for * date variables to avoid overriding the {@link #onChange(ChangeEvent)} * method. + * + * @since */ protected void updateDateVariables() { // Update variables // (only the smallest defining resolution needs to be // immediate) Date currentDate = getDate(); - getClient().updateVariable(getId(), - getResolutionVariable(getResolutions().filter(this::isYear) - .findFirst().get()), - currentDate != null ? currentDate.getYear() + 1900 : -1, - isYear(getCurrentResolution())); + bufferedResolutions.put( + getResolutions().filter(this::isYear).findFirst().get().name(), + currentDate != null ? currentDate.getYear() + 1900 : null); + if (isYear(getCurrentResolution())) { + sendBufferedValues(); + } } /** @@ -390,7 +391,14 @@ public abstract class VAbstractTextualDate<R extends Enum<R>> } if (getClient() != null && getClient() .hasEventListeners(VAbstractTextualDate.this, eventId)) { - getClient().updateVariable(getId(), eventId, "", true); + // may excessively send events if if focus went to another + // sub-component + if (EventId.FOCUS.equals(eventId)) { + rpc.focus(); + } else { + rpc.blur(); + } + sendBufferedValues(); } // Needed for tooltip event handling diff --git a/client/src/main/java/com/vaadin/client/ui/VDateField.java b/client/src/main/java/com/vaadin/client/ui/VDateField.java index 772f72c897..558ddaa494 100644 --- a/client/src/main/java/com/vaadin/client/ui/VDateField.java +++ b/client/src/main/java/com/vaadin/client/ui/VDateField.java @@ -17,6 +17,7 @@ package com.vaadin.client.ui; import java.util.Date; +import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.stream.Stream; @@ -25,6 +26,7 @@ import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HasEnabled; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.DateTimeService; +import com.vaadin.shared.ui.datefield.AbstractDateFieldServerRpc; /** * A very base widget class for a date field. @@ -54,21 +56,56 @@ public abstract class VDateField<R extends Enum<R>> extends FlowPanel protected boolean enabled; /** + * The RPC send calls to the server. + * + * @since + */ + public AbstractDateFieldServerRpc rpc; + + /** + * A temporary holder of the time units (resolutions), which would be sent + * to the server through {@link #sendBufferedValues()}. + * + * The key is the resolution name e.g. "HOUR", "MINUTE". + * + * The value can be {@code null}. + * + * @since + */ + protected Map<String, Integer> bufferedResolutions = new HashMap<>(); + + /** + * A temporary holder of the date string, which would be sent to the server + * through {@link #sendBufferedValues()}. + * + * @since + */ + protected String bufferedDateString; + + /** + * A temporary holder of whether the date string was invalid or not, which + * would be sent to the server through {@link #sendBufferedValues()}. + * + * @since + */ + protected boolean bufferedInvalidDateString; + + /** * The date that is displayed the date field before a value is selected. If * null, display the current date. */ - private Date defaultDate = null; + private Date defaultDate; /** * The date that is selected in the date field. Null if an invalid date is * specified. */ - private Date date = null; + private Date date; /** For internal use only. May be removed or replaced in the future. */ public DateTimeService dts; - protected boolean showISOWeekNumbers = false; + protected boolean showISOWeekNumbers; public VDateField(R resolution) { setStyleName(CLASSNAME); @@ -232,6 +269,20 @@ public abstract class VDateField<R extends Enum<R>> extends FlowPanel } /** + * Sends the {@link #bufferedDateString}, {@link #bufferedInvalidDateString} + * and {@link #bufferedResolutions} to the server, and clears their values. + * + * @since + */ + public void sendBufferedValues() { + rpc.update(bufferedDateString, bufferedInvalidDateString, + new HashMap<>(bufferedResolutions)); + bufferedDateString = null; + bufferedInvalidDateString = false; + bufferedResolutions.clear(); + } + + /** * Returns all available resolutions for the field in the ascending order * (which is the same as order of enumeration ordinals). * <p> diff --git a/client/src/main/java/com/vaadin/client/ui/VDateFieldCalendar.java b/client/src/main/java/com/vaadin/client/ui/VDateFieldCalendar.java index ada512c8b1..69e6d923ce 100644 --- a/client/src/main/java/com/vaadin/client/ui/VDateFieldCalendar.java +++ b/client/src/main/java/com/vaadin/client/ui/VDateFieldCalendar.java @@ -50,25 +50,22 @@ public class VDateFieldCalendar Date date2 = calendarPanel.getDate(); Date currentDate = getCurrentDate(); + DateResolution resolution = getCurrentResolution(); if (currentDate == null || date2.getTime() != currentDate.getTime()) { setCurrentDate((Date) date2.clone()); - getClient().updateVariable(getId(), - getResolutionVariable(DateResolution.YEAR), + bufferedResolutions.put(DateResolution.YEAR.name(), // Java Date uses the year aligned to 1900 (no to zero). // So we should add 1900 to get a correct year aligned to 0. - date2.getYear() + 1900, false); - if (getCurrentResolution().compareTo(DateResolution.YEAR) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateResolution.MONTH), - date2.getMonth() + 1, false); - if (getCurrentResolution() - .compareTo(DateResolution.MONTH) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateResolution.DAY), - date2.getDate(), false); + date2.getYear() + 1900); + if (resolution.compareTo(DateResolution.YEAR) < 0) { + bufferedResolutions.put(DateResolution.MONTH.name(), + date2.getMonth() + 1); + if (resolution.compareTo(DateResolution.MONTH) < 0) { + bufferedResolutions.put(DateResolution.DAY.name(), + date2.getDate()); } } - getClient().sendPendingVariableChanges(); + sendBufferedValues(); } } diff --git a/client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java b/client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java index 55922e4825..8f27c920cc 100644 --- a/client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java +++ b/client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java @@ -91,11 +91,11 @@ public class VDateTimeCalendarPanel if (getDateTimeService().isTwelveHourClock()) { hours.addItem("12"); for (int i = 1; i < 12; i++) { - hours.addItem((i < 10) ? "0" + i : "" + i); + hours.addItem(asTwoDigits(i)); } } else { for (int i = 0; i < 24; i++) { - hours.addItem((i < 10) ? "0" + i : "" + i); + hours.addItem(asTwoDigits(i)); } } @@ -111,14 +111,14 @@ public class VDateTimeCalendarPanel if (getResolution().compareTo(DateTimeResolution.MINUTE) <= 0) { mins = createListBox(); for (int i = 0; i < 60; i++) { - mins.addItem((i < 10) ? "0" + i : "" + i); + mins.addItem(asTwoDigits(i)); } mins.addChangeHandler(this); } if (getResolution().compareTo(DateTimeResolution.SECOND) <= 0) { sec = createListBox(); for (int i = 0; i < 60; i++) { - sec.addItem((i < 10) ? "0" + i : "" + i); + sec.addItem(asTwoDigits(i)); } sec.addChangeHandler(this); } @@ -132,7 +132,7 @@ public class VDateTimeCalendarPanel if (getDateTimeService().isTwelveHourClock()) { h -= h < 12 ? 0 : 12; } - add(new VLabel(h < 10 ? "0" + h : "" + h)); + add(new VLabel(asTwoDigits(h))); } else { add(hours); } @@ -141,7 +141,7 @@ public class VDateTimeCalendarPanel add(new VLabel(delimiter)); if (isReadonly()) { final int m = mins.getSelectedIndex(); - add(new VLabel(m < 10 ? "0" + m : "" + m)); + add(new VLabel(asTwoDigits(m))); } else { add(mins); } @@ -150,7 +150,7 @@ public class VDateTimeCalendarPanel add(new VLabel(delimiter)); if (isReadonly()) { final int s = sec.getSelectedIndex(); - add(new VLabel(s < 10 ? "0" + s : "" + s)); + add(new VLabel(asTwoDigits(s))); } else { add(sec); } @@ -193,7 +193,6 @@ public class VDateTimeCalendarPanel } } }); - } private ListBox getLastDropDown() { @@ -243,14 +242,16 @@ public class VDateTimeCalendarPanel if (ampm != null) { ampm.setEnabled(isEnabled()); } - } private DateTimeService getDateTimeService() { - if (VDateTimeCalendarPanel.this.getDateTimeService() == null) { - setDateTimeService(new DateTimeService()); + DateTimeService dts = VDateTimeCalendarPanel.this + .getDateTimeService(); + if (dts == null) { + dts = new DateTimeService(); + setDateTimeService(dts); } - return VDateTimeCalendarPanel.this.getDateTimeService(); + return dts; } /* @@ -312,7 +313,10 @@ public class VDateTimeCalendarPanel event.stopPropagation(); } } + } + private static String asTwoDigits(int i) { + return (i < 10 ? "0" : "") + i; } /** diff --git a/client/src/main/java/com/vaadin/client/ui/VDateTimeFieldCalendar.java b/client/src/main/java/com/vaadin/client/ui/VDateTimeFieldCalendar.java index 3d2b13becb..6e74bf45e7 100644 --- a/client/src/main/java/com/vaadin/client/ui/VDateTimeFieldCalendar.java +++ b/client/src/main/java/com/vaadin/client/ui/VDateTimeFieldCalendar.java @@ -46,46 +46,41 @@ public class VDateTimeFieldCalendar extends Date date2 = calendarPanel.getDate(); Date currentDate = getCurrentDate(); + DateTimeResolution resolution = getCurrentResolution(); if (currentDate == null || date2.getTime() != currentDate.getTime()) { setCurrentDate((Date) date2.clone()); - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.YEAR), - date2.getYear() + 1900, false); - if (getCurrentResolution().compareTo(DateTimeResolution.YEAR) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.MONTH), - date2.getMonth() + 1, false); - if (getCurrentResolution() - .compareTo(DateTimeResolution.MONTH) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.DAY), - date2.getDate(), false); - if (getCurrentResolution() - .compareTo(DateTimeResolution.DAY) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.HOUR), - date2.getHours(), false); - if (getCurrentResolution() - .compareTo(DateTimeResolution.HOUR) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable( - DateTimeResolution.MINUTE), - date2.getMinutes(), false); - if (getCurrentResolution() + addBufferedResolution(DateTimeResolution.YEAR, + date2.getYear() + 1900); + if (resolution.compareTo(DateTimeResolution.YEAR) < 0) { + addBufferedResolution(DateTimeResolution.MONTH, + date2.getMonth() + 1); + if (resolution.compareTo(DateTimeResolution.MONTH) < 0) { + addBufferedResolution(DateTimeResolution.DAY, + date2.getDate()); + if (resolution.compareTo(DateTimeResolution.DAY) < 0) { + addBufferedResolution(DateTimeResolution.HOUR, + date2.getHours()); + if (resolution.compareTo(DateTimeResolution.HOUR) < 0) { + addBufferedResolution(DateTimeResolution.MINUTE, + date2.getMinutes()); + if (resolution .compareTo(DateTimeResolution.MINUTE) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable( - DateTimeResolution.SECOND), - date2.getSeconds(), false); + addBufferedResolution(DateTimeResolution.SECOND, + date2.getSeconds()); } } } } } - getClient().sendPendingVariableChanges(); + sendBufferedValues(); } } + private void addBufferedResolution(DateTimeResolution resolution, + Integer value) { + bufferedResolutions.put(resolution.name(), value); + } + @Override public String resolutionAsString() { if (getCurrentResolution().compareTo(DateTimeResolution.DAY) >= 0) { diff --git a/client/src/main/java/com/vaadin/client/ui/VPopupCalendar.java b/client/src/main/java/com/vaadin/client/ui/VPopupCalendar.java index 9237014423..65c47f8c6c 100644 --- a/client/src/main/java/com/vaadin/client/ui/VPopupCalendar.java +++ b/client/src/main/java/com/vaadin/client/ui/VPopupCalendar.java @@ -52,20 +52,20 @@ public class VPopupCalendar } public static Date makeDate(Map<DateResolution, Integer> dateValues) { - if (dateValues.get(DateResolution.YEAR) == -1) { + if (dateValues.get(DateResolution.YEAR) == null) { return null; } Date date = new Date(2000 - 1900, 0, 1); - int year = dateValues.get(DateResolution.YEAR); - if (year >= 0) { + Integer year = dateValues.get(DateResolution.YEAR); + if (year != null) { date.setYear(year - 1900); } - int month = dateValues.get(DateResolution.MONTH); - if (month >= 0) { + Integer month = dateValues.get(DateResolution.MONTH); + if (month != null) { date.setMonth(month - 1); } - int day = dateValues.get(DateResolution.DAY); - if (day >= 0) { + Integer day = dateValues.get(DateResolution.DAY); + if (day != null) { date.setDate(day); } return date; @@ -84,22 +84,20 @@ public class VPopupCalendar @Override protected void updateDateVariables() { super.updateDateVariables(); + DateResolution resolution = getCurrentResolution(); // Update variables // (only the smallest defining resolution needs to be // immediate) Date currentDate = getDate(); - if (getCurrentResolution().compareTo(DateResolution.MONTH) <= 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateResolution.MONTH), - currentDate != null ? currentDate.getMonth() + 1 : -1, - getCurrentResolution() == DateResolution.MONTH); + if (resolution.compareTo(DateResolution.MONTH) <= 0) { + bufferedResolutions.put(DateResolution.MONTH.name(), + currentDate != null ? currentDate.getMonth() + 1 : null); } - if (getCurrentResolution().compareTo(DateResolution.DAY) <= 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateResolution.DAY), - currentDate != null ? currentDate.getDate() : -1, - getCurrentResolution() == DateResolution.DAY); + if (resolution.compareTo(DateResolution.DAY) <= 0) { + bufferedResolutions.put(DateResolution.DAY.name(), + currentDate != null ? currentDate.getDate() : null); } + sendBufferedValues(); } @Override diff --git a/client/src/main/java/com/vaadin/client/ui/VPopupTimeCalendar.java b/client/src/main/java/com/vaadin/client/ui/VPopupTimeCalendar.java index 2805a4e7a6..ff740efbca 100644 --- a/client/src/main/java/com/vaadin/client/ui/VPopupTimeCalendar.java +++ b/client/src/main/java/com/vaadin/client/ui/VPopupTimeCalendar.java @@ -61,32 +61,32 @@ public class VPopupTimeCalendar extends } public static Date makeDate(Map<DateTimeResolution, Integer> dateValues) { - if (dateValues.get(DateTimeResolution.YEAR) == -1) { + if (dateValues.get(DateTimeResolution.YEAR) == null) { return null; } Date date = new Date(2000 - 1900, 0, 1); - int year = dateValues.get(DateTimeResolution.YEAR); - if (year >= 0) { + Integer year = dateValues.get(DateTimeResolution.YEAR); + if (year != null) { date.setYear(year - 1900); } - int month = dateValues.get(DateTimeResolution.MONTH); - if (month >= 0) { + Integer month = dateValues.get(DateTimeResolution.MONTH); + if (month != null) { date.setMonth(month - 1); } - int day = dateValues.get(DateTimeResolution.DAY); - if (day >= 0) { + Integer day = dateValues.get(DateTimeResolution.DAY); + if (day != null) { date.setDate(day); } - int hour = dateValues.get(DateTimeResolution.HOUR); - if (hour >= 0) { + Integer hour = dateValues.get(DateTimeResolution.HOUR); + if (hour != null) { date.setHours(hour); } - int minute = dateValues.get(DateTimeResolution.MINUTE); - if (minute >= 0) { + Integer minute = dateValues.get(DateTimeResolution.MINUTE); + if (minute != null) { date.setMinutes(minute); } - int second = dateValues.get(DateTimeResolution.SECOND); - if (second >= 0) { + Integer second = dateValues.get(DateTimeResolution.SECOND); + if (second != null) { date.setSeconds(second); } return date; @@ -105,40 +105,36 @@ public class VPopupTimeCalendar extends @Override protected void updateDateVariables() { super.updateDateVariables(); - // Update variables + DateTimeResolution resolution = getCurrentResolution(); // (only the smallest defining resolution needs to be // immediate) Date currentDate = getDate(); - if (getCurrentResolution().compareTo(DateTimeResolution.MONTH) <= 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.MONTH), - currentDate != null ? currentDate.getMonth() + 1 : -1, - getCurrentResolution() == DateTimeResolution.MONTH); - } - if (getCurrentResolution().compareTo(DateTimeResolution.DAY) <= 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.DAY), - currentDate != null ? currentDate.getDate() : -1, - getCurrentResolution() == DateTimeResolution.DAY); - } - if (getCurrentResolution().compareTo(DateTimeResolution.HOUR) <= 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.HOUR), - currentDate != null ? currentDate.getHours() : -1, - getCurrentResolution() == DateTimeResolution.HOUR); - } - if (getCurrentResolution().compareTo(DateTimeResolution.MINUTE) <= 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.MINUTE), - currentDate != null ? currentDate.getMinutes() : -1, - getCurrentResolution() == DateTimeResolution.MINUTE); - } - if (getCurrentResolution().compareTo(DateTimeResolution.SECOND) <= 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.SECOND), - currentDate != null ? currentDate.getSeconds() : -1, - getCurrentResolution() == DateTimeResolution.SECOND); + if (resolution.compareTo(DateTimeResolution.MONTH) <= 0) { + addBufferedResolution(DateTimeResolution.MONTH, + currentDate != null ? currentDate.getMonth() + 1 : null); } + if (resolution.compareTo(DateTimeResolution.DAY) <= 0) { + addBufferedResolution(DateTimeResolution.DAY, + currentDate != null ? currentDate.getDate() : null); + } + if (resolution.compareTo(DateTimeResolution.HOUR) <= 0) { + addBufferedResolution(DateTimeResolution.HOUR, + currentDate != null ? currentDate.getHours() : null); + } + if (resolution.compareTo(DateTimeResolution.MINUTE) <= 0) { + addBufferedResolution(DateTimeResolution.MINUTE, + currentDate != null ? currentDate.getMinutes() : null); + } + if (resolution.compareTo(DateTimeResolution.SECOND) <= 0) { + addBufferedResolution(DateTimeResolution.SECOND, + currentDate != null ? currentDate.getSeconds() : null); + } + sendBufferedValues(); + } + + private void addBufferedResolution(DateTimeResolution resolutionToAdd, + Integer value) { + bufferedResolutions.put(resolutionToAdd.name(), value); } @Override @@ -146,22 +142,18 @@ public class VPopupTimeCalendar extends public void updateValue(Date newDate) { Date currentDate = getCurrentDate(); super.updateValue(newDate); + DateTimeResolution resolution = getCurrentResolution(); if (currentDate == null || newDate.getTime() != currentDate.getTime()) { - if (getCurrentResolution().compareTo(DateTimeResolution.DAY) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.HOUR), - newDate.getHours(), false); - if (getCurrentResolution() - .compareTo(DateTimeResolution.HOUR) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable(DateTimeResolution.MINUTE), - newDate.getMinutes(), false); - if (getCurrentResolution() - .compareTo(DateTimeResolution.MINUTE) < 0) { - getClient().updateVariable(getId(), - getResolutionVariable( - DateTimeResolution.SECOND), - newDate.getSeconds(), false); + if (resolution.compareTo(DateTimeResolution.DAY) < 0) { + bufferedResolutions.put(DateTimeResolution.HOUR.name(), + newDate.getHours()); + if (resolution.compareTo(DateTimeResolution.HOUR) < 0) { + bufferedResolutions.put(DateTimeResolution.MINUTE.name(), + newDate.getMinutes()); + if (resolution.compareTo(DateTimeResolution.MINUTE) < 0) { + bufferedResolutions.put( + DateTimeResolution.SECOND.name(), + newDate.getSeconds()); } } } @@ -197,7 +189,6 @@ public class VPopupTimeCalendar extends if (dts.isTwelveHourClock()) { frmString += " aaa"; } - } return frmString; diff --git a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractDateFieldConnector.java b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractDateFieldConnector.java index 21e85773de..2aad416343 100644 --- a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractDateFieldConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractDateFieldConnector.java @@ -21,101 +21,61 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import com.vaadin.client.ApplicationConnection; import com.vaadin.client.LocaleNotLoadedException; -import com.vaadin.client.Paintable; -import com.vaadin.client.UIDL; import com.vaadin.client.VConsole; +import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.VDateField; -import com.vaadin.shared.ui.datefield.DateFieldConstants; +import com.vaadin.shared.ui.datefield.AbstractDateFieldServerRpc; +import com.vaadin.shared.ui.datefield.AbstractDateFieldState; public abstract class AbstractDateFieldConnector<R extends Enum<R>> - extends AbstractFieldConnector implements Paintable { + extends AbstractFieldConnector { @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - if (!isRealUpdate(uidl)) { - return; - } - - // Save details - getWidget().client = client; - getWidget().paintableId = uidl.getId(); - - getWidget().setReadonly(isReadOnly()); - getWidget().setEnabled(isEnabled()); - - if (uidl.hasAttribute("locale")) { - final String locale = uidl.getStringAttribute("locale"); - try { - getWidget().dts.setLocale(locale); - getWidget().setCurrentLocale(locale); - } catch (final LocaleNotLoadedException e) { - getWidget().setCurrentLocale(getWidget().dts.getLocale()); - VConsole.error("Tried to use an unloaded locale \"" + locale - + "\". Using default locale (" - + getWidget().getCurrentLocale() + ")."); - VConsole.error(e); - } - } - - // We show week numbers only if the week starts with Monday, as ISO 8601 - // specifies - getWidget().setShowISOWeekNumbers( - uidl.getBooleanAttribute(DateFieldConstants.ATTR_WEEK_NUMBERS) - && getWidget().dts.getFirstDayOfWeek() == 1); - - // Remove old stylename that indicates current resolution - setWidgetStyleName(getWidget().getStylePrimaryName() + "-" - + getWidget().resolutionAsString(), false); - - updateResolution(uidl); - - // Add stylename that indicates current resolution - setWidgetStyleName(getWidget().getStylePrimaryName() + "-" - + getWidget().resolutionAsString(), true); - - getWidget().setCurrentDate(getTimeValues(uidl)); - getWidget().setDefaultDate(getDefaultValues(uidl)); + protected void init() { + super.init(); + getWidget().rpc = getRpcProxy(AbstractDateFieldServerRpc.class); } - private void updateResolution(UIDL uidl) { - Optional<R> newResolution = getWidget().getResolutions().filter( - res -> uidl.hasVariable(getWidget().getResolutionVariable(res))) + private void updateResolution() { + VDateField<R> widget = getWidget(); + Map<String, Integer> stateResolutions = getState().resolutions; + Optional<R> newResolution = widget.getResolutions() + .filter(res -> stateResolutions.containsKey(res.name())) .findFirst(); - getWidget().setCurrentResolution(newResolution.orElse(null)); + widget.setCurrentResolution(newResolution.orElse(null)); } - protected Map<R, Integer> getTimeValues(UIDL uidl) { - Stream<R> resolutions = getWidget().getResolutions(); - R resolution = getWidget().getCurrentResolution(); - return resolutions - .collect(Collectors.toMap(Function.identity(), - res -> (resolution.compareTo(res) <= 0) - ? uidl.getIntVariable( - getWidget().getResolutionVariable(res)) - : -1)); + private Map<R, Integer> getTimeValues() { + VDateField<R> widget = getWidget(); + Map<String, Integer> stateResolutions = getState().resolutions; + Stream<R> resolutions = widget.getResolutions(); + R resolution = widget.getCurrentResolution(); + return resolutions.collect(Collectors.toMap(Function.identity(), + res -> res == null ? null + : (resolution.compareTo(res) <= 0) + ? stateResolutions.get(res.name()) + : null)); } /** * Returns the default date (when no date is selected) components as a map * from Resolution to the corresponding value. * - * @param uidl - * UIDL with corresponding variables * @return default date component map - * @since 8.1.2 + * @since */ - protected Map<R, Integer> getDefaultValues(UIDL uidl) { + protected Map<R, Integer> getDefaultValues() { + Map<String, Integer> stateResolutions = getState().resolutions; Stream<R> resolutions = getWidget().getResolutions(); R resolution = getWidget().getCurrentResolution(); return resolutions.collect(Collectors.toMap(Function.identity(), - res -> (resolution.compareTo(res) <= 0) - ? uidl.getIntVariable("default-" - + getWidget().getResolutionVariable(res)) - : -1)); + res -> res == null ? null + : (resolution.compareTo(res) <= 0) + ? stateResolutions.get("default-" + res.name()) + : null)); } @SuppressWarnings("unchecked") @@ -124,4 +84,51 @@ public abstract class AbstractDateFieldConnector<R extends Enum<R>> return (VDateField<R>) super.getWidget(); } + @Override + public AbstractDateFieldState getState() { + return (AbstractDateFieldState) super.getState(); + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + VDateField<R> widget = getWidget(); + + // Save details + widget.client = getConnection(); + widget.paintableId = getConnectorId(); + + widget.setReadonly(isReadOnly()); + widget.setEnabled(isEnabled()); + + final String locale = getState().locale; + try { + widget.dts.setLocale(locale); + widget.setCurrentLocale(locale); + } catch (final LocaleNotLoadedException e) { + widget.setCurrentLocale(widget.dts.getLocale()); + VConsole.error("Tried to use an unloaded locale \"" + locale + + "\". Using default locale (" + widget.getCurrentLocale() + + ")."); + VConsole.error(e); + } + + // We show week numbers only if the week starts with Monday, as ISO 8601 + // specifies + widget.setShowISOWeekNumbers(getState().showISOWeekNumbers + && widget.dts.getFirstDayOfWeek() == 1); + + // Remove old stylename that indicates current resolution + setWidgetStyleName(widget.getStylePrimaryName() + "-" + + widget.resolutionAsString(), false); + + updateResolution(); + + // Add stylename that indicates current resolution + setWidgetStyleName(widget.getStylePrimaryName() + "-" + + widget.resolutionAsString(), true); + + widget.setCurrentDate(getTimeValues()); + widget.setDefaultDate(getDefaultValues()); + } } diff --git a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java index 3d12956247..b98452966f 100644 --- a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractInlineDateFieldConnector.java @@ -39,33 +39,6 @@ import com.vaadin.shared.ui.datefield.InlineDateFieldState; public abstract class AbstractInlineDateFieldConnector<PANEL extends VAbstractCalendarPanel<R>, R extends Enum<R>> extends AbstractDateFieldConnector<R> { - @Override - @SuppressWarnings("deprecation") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - super.updateFromUIDL(uidl, client); - if (!isRealUpdate(uidl)) { - return; - } - - getWidget().calendarPanel - .setShowISOWeekNumbers(getWidget().isShowISOWeekNumbers()); - getWidget().calendarPanel - .setDateTimeService(getWidget().getDateTimeService()); - getWidget().calendarPanel - .setResolution(getWidget().getCurrentResolution()); - Date currentDate = getWidget().getCurrentDate(); - if (currentDate != null) { - getWidget().calendarPanel.setDate(new Date(currentDate.getTime())); - } else { - getWidget().calendarPanel.setDate(null); - } - - updateListeners(); - - // Update possible changes - getWidget().calendarPanel.renderCalendar(); - } - /** * Updates listeners registered (or register them) for the widget based on * the current resolution. @@ -108,6 +81,24 @@ public abstract class AbstractInlineDateFieldConnector<PANEL extends VAbstractCa getWidget().setTabIndex(getState().tabIndex); getWidget().calendarPanel.setRangeStart(getState().rangeStart); getWidget().calendarPanel.setRangeEnd(getState().rangeEnd); + + getWidget().calendarPanel + .setShowISOWeekNumbers(getWidget().isShowISOWeekNumbers()); + getWidget().calendarPanel + .setDateTimeService(getWidget().getDateTimeService()); + getWidget().calendarPanel + .setResolution(getWidget().getCurrentResolution()); + Date currentDate = getWidget().getCurrentDate(); + if (currentDate != null) { + getWidget().calendarPanel.setDate(new Date(currentDate.getTime())); + } else { + getWidget().calendarPanel.setDate(null); + } + + updateListeners(); + + // Update possible changes + getWidget().calendarPanel.renderCalendar(); } @Override diff --git a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractTextualDateConnector.java b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractTextualDateConnector.java index 81eea0e71e..856e9948a8 100644 --- a/client/src/main/java/com/vaadin/client/ui/datefield/AbstractTextualDateConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/datefield/AbstractTextualDateConnector.java @@ -18,9 +18,8 @@ package com.vaadin.client.ui.datefield; import com.google.gwt.i18n.client.TimeZone; import com.google.gwt.i18n.client.TimeZoneInfo; -import com.vaadin.client.ApplicationConnection; -import com.vaadin.client.UIDL; import com.vaadin.client.annotations.OnStateChange; +import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.VAbstractTextualDate; import com.vaadin.shared.ui.datefield.AbstractTextualDateFieldState; @@ -37,34 +36,6 @@ public abstract class AbstractTextualDateConnector<R extends Enum<R>> extends AbstractDateFieldConnector<R> { @Override - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - R origRes = getWidget().getCurrentResolution(); - String oldLocale = getWidget().getCurrentLocale(); - super.updateFromUIDL(uidl, client); - if (origRes != getWidget().getCurrentResolution() - || oldLocale != getWidget().getCurrentLocale()) { - // force recreating format string - getWidget().setFormatString(null); - } - if (uidl.hasAttribute("format")) { - getWidget().setFormatString(uidl.getStringAttribute("format")); - } - - getWidget().lenient = !uidl.getBooleanAttribute("strict"); - - getWidget().buildDate(); - // not a FocusWidget -> needs own tabindex handling - getWidget().text.setTabIndex(getState().tabIndex); - - if (getWidget().isReadonly()) { - getWidget().text.addStyleDependentName("readonly"); - } else { - getWidget().text.removeStyleDependentName("readonly"); - } - - } - - @Override public VAbstractTextualDate<R> getWidget() { return (VAbstractTextualDate<R>) super.getWidget(); } @@ -88,4 +59,36 @@ public abstract class AbstractTextualDateConnector<R extends Enum<R>> getWidget().setTimeZone(timeZone); } + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + VAbstractTextualDate<R> widget = getWidget(); + AbstractTextualDateFieldState state = getState(); + + R origRes = widget.getCurrentResolution(); + String oldLocale = widget.getCurrentLocale(); + + super.onStateChanged(stateChangeEvent); + + if (origRes != widget.getCurrentResolution() + || oldLocale != widget.getCurrentLocale()) { + // force recreating format string + widget.setFormatString(null); + } + if (state.format != widget.getFormatString()) { + widget.setFormatString(state.format); + } + + widget.lenient = state.lenient; + + // may be excessively called on every state change + widget.buildDate(); + // not a FocusWidget -> needs own tabindex handling + widget.text.setTabIndex(state.tabIndex); + + if (widget.isReadonly()) { + widget.text.addStyleDependentName("readonly"); + } else { + widget.text.removeStyleDependentName("readonly"); + } + } } diff --git a/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java b/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java index 0c61f3860e..f2957efc3e 100644 --- a/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java @@ -48,6 +48,7 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel< @Override protected void init() { + super.init(); getWidget().popup.addCloseHandler(new CloseHandler<PopupPanel>() { @Override @@ -55,28 +56,77 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel< /* * FIXME This is a hack so we do not have to rewrite half of the * datefield so values are not sent while selecting a date - * (#6252). + * (#1399). * - * The datefield will now only set the date UIDL variables while - * the user is selecting year/month/date/time and not send them + * The datefield will now only set the date variables while the + * user is selecting year/month/date/time and not send them * directly. Only when the user closes the popup (by clicking on * a day/enter/clicking outside of popup) then the new value is * communicated to the server. */ - getConnection().getServerRpcQueue().flush(); + getWidget().sendBufferedValues(); } }); } + /** + * Updates listeners registered (or register them) for the widget based on + * the current resolution. + * <p> + * Subclasses may override this method to keep the common logic inside the + * {@link #updateFromUIDL(UIDL, ApplicationConnection)} method as is and + * customizing only listeners logic. + */ + protected void updateListeners() { + FocusChangeListener listener; + if (isResolutionMonthOrHigher()) { + listener = new FocusChangeListener() { + @Override + public void focusChanged(Date date) { + if (isResolutionMonthOrHigher()) { + getWidget().updateValue(date); + getWidget().buildDate(); + Date date2 = getWidget().calendar.getDate(); + date2.setYear(date.getYear()); + date2.setMonth(date.getMonth()); + } + } + }; + } else { + listener = null; + } + getWidget().calendar.setFocusChangeListener(listener); + } + + /** + * Returns {@code true} is the current resolution of the widget is month or + * less specific (e.g. month, year, quarter, etc). + * + * @return {@code true} if the current resolution is above month + */ + protected abstract boolean isResolutionMonthOrHigher(); + + @Override + public VAbstractPopupCalendar<PANEL, R> getWidget() { + return (VAbstractPopupCalendar<PANEL, R>) super.getWidget(); + } + @Override - @SuppressWarnings("deprecation") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + public TextualDateFieldState getState() { + return (TextualDateFieldState) super.getState(); + } + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { String oldLocale = getWidget().getCurrentLocale(); - getWidget().parsable = uidl.getBooleanAttribute("parsable"); + getWidget().parsable = getState().parsable; - super.updateFromUIDL(uidl, client); + super.onStateChanged(stateChangeEvent); + + getWidget().setTextFieldEnabled(getState().textFieldEnabled); + getWidget().setRangeStart(nullSafeDateClone(getState().rangeStart)); + getWidget().setRangeEnd(nullSafeDateClone(getState().rangeEnd)); getWidget().calendar .setDateTimeService(getWidget().getDateTimeService()); @@ -118,66 +168,11 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel< getWidget().setTextFieldTabIndex(); } - /** - * Updates listeners registered (or register them) for the widget based on - * the current resolution. - * <p> - * Subclasses may override this method to keep the common logic inside the - * {@link #updateFromUIDL(UIDL, ApplicationConnection)} method as is and - * customizing only listeners logic. - */ - protected void updateListeners() { - if (isResolutionMonthOrHigher()) { - getWidget().calendar - .setFocusChangeListener(new FocusChangeListener() { - @Override - public void focusChanged(Date date) { - if (isResolutionMonthOrHigher()) { - getWidget().updateValue(date); - getWidget().buildDate(); - Date date2 = getWidget().calendar.getDate(); - date2.setYear(date.getYear()); - date2.setMonth(date.getMonth()); - } - } - }); - } else { - getWidget().calendar.setFocusChangeListener(null); - } - } - - /** - * Returns {@code true} is the current resolution of the widget is month or - * less specific (e.g. month, year, quarter, etc). - * - * @return {@code true} if the current resolution is above month - */ - protected abstract boolean isResolutionMonthOrHigher(); - - @Override - public VAbstractPopupCalendar<PANEL, R> getWidget() { - return (VAbstractPopupCalendar<PANEL, R>) super.getWidget(); - } - - @Override - public TextualDateFieldState getState() { - return (TextualDateFieldState) super.getState(); - } - - @Override - public void onStateChanged(StateChangeEvent stateChangeEvent) { - super.onStateChanged(stateChangeEvent); - getWidget().setTextFieldEnabled(getState().textFieldEnabled); - getWidget().setRangeStart(nullSafeDateClone(getState().rangeStart)); - getWidget().setRangeEnd(nullSafeDateClone(getState().rangeEnd)); - } - private Date nullSafeDateClone(Date date) { - if (date == null) { - return null; - } else { + if (date != null) { return (Date) date.clone(); } + return null; } @Override @@ -196,14 +191,10 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel< // update the style change to popup calendar widget with the correct // prefix if (!styleName.startsWith("-")) { - getWidget().popup.setStyleName( - getWidget().getStylePrimaryName() + "-popup-" + styleName, - add); - } else { - getWidget().popup.setStyleName( - getWidget().getStylePrimaryName() + "-popup" + styleName, - add); + styleName = "-" + styleName; } + getWidget().popup.setStyleName( + getWidget().getStylePrimaryName() + "-popup" + styleName, add); } } diff --git a/server/src/main/java/com/vaadin/ui/AbstractDateField.java b/server/src/main/java/com/vaadin/ui/AbstractDateField.java index b5f11f7122..bfe3119f26 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractDateField.java +++ b/server/src/main/java/com/vaadin/ui/AbstractDateField.java @@ -48,12 +48,10 @@ import com.vaadin.event.FieldEvents.BlurNotifier; import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.event.FieldEvents.FocusNotifier; -import com.vaadin.server.PaintException; -import com.vaadin.server.PaintTarget; import com.vaadin.server.UserError; import com.vaadin.shared.Registration; +import com.vaadin.shared.ui.datefield.AbstractDateFieldServerRpc; import com.vaadin.shared.ui.datefield.AbstractDateFieldState; -import com.vaadin.shared.ui.datefield.DateFieldConstants; import com.vaadin.shared.ui.datefield.DateResolution; import com.vaadin.ui.declarative.DesignAttributeHandler; import com.vaadin.ui.declarative.DesignContext; @@ -73,8 +71,86 @@ import com.vaadin.util.TimeZoneUtil; * */ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & Serializable & Comparable<? super T>, R extends Enum<R>> - extends AbstractField<T> - implements LegacyComponent, FocusNotifier, BlurNotifier { + extends AbstractField<T> implements FocusNotifier, BlurNotifier { + + private AbstractDateFieldServerRpc rpc = new AbstractDateFieldServerRpc() { + + @Override + public void update(String newDateString, boolean invalidDateString, + Map<String, Integer> resolutions) { + Set<String> resolutionNames = getResolutions() + .map(AbstractDateField.this::getResolutionVariable) + .collect(Collectors.toSet()); + resolutionNames.retainAll(resolutions.keySet()); + if (!isReadOnly() + && (!resolutionNames.isEmpty() || newDateString != null)) { + + // Old and new dates + final T oldDate = getValue(); + + T newDate; + + boolean hasChanges = false; + + if ("".equals(newDateString)) { + + newDate = null; + // TODO check if the following 3 lines are necessary + hasChanges = !getState(false).parsable; + getState().parsable = true; + currentParseErrorMessage = null; + } else { + newDate = reconstructDateFromFields(resolutions, oldDate); + } + + hasChanges |= !Objects.equals(dateString, newDateString) + || !Objects.equals(oldDate, newDate); + + if (hasChanges) { + dateString = newDateString; + if (newDateString == null || newDateString.isEmpty()) { + getState().parsable = true; + currentParseErrorMessage = null; + setComponentError(null); + setValue(newDate, true); + } else { + if (invalidDateString) { + Result<T> parsedDate = handleUnparsableDateString( + dateString); + parsedDate.ifOk(v -> { + getState().parsable = true; + currentParseErrorMessage = null; + setValue(v, true); + }); + if (parsedDate.isError()) { + dateString = null; + getState().parsable = false; + currentParseErrorMessage = parsedDate + .getMessage().orElse("Parsing error"); + setComponentError( + new UserError(getParseErrorMessage())); + setValue(null, true); + } + } else { + getState().parsable = true; + currentParseErrorMessage = null; + setValue(newDate, true); + } + } + } + } + } + + @Override + public void focus() { + fireEvent(new FocusEvent(AbstractDateField.this)); + } + + @Override + public void blur() { + fireEvent(new BlurEvent(AbstractDateField.this)); + } + }; /** * Value of the field. @@ -86,36 +162,19 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & * * @since 8.1.2 */ - private T defaultValue = null; + private T defaultValue; + /** * Specified smallest modifiable unit for the date field. */ private R resolution; - /** - * Overridden format string - */ - private String dateFormat; - private ZoneId zoneId; - private boolean lenient = false; - private String dateString = ""; private String currentParseErrorMessage; - /** - * Was the last entered string parsable? If this flag is false, datefields - * internal validator does not pass. - */ - private boolean uiHasValidDateString = true; - - /** - * Determines if week numbers are shown in the date selector. - */ - private boolean showISOWeekNumbers = false; - private String defaultParseErrorMessage = "Date format not recognized"; private String dateOutOfRangeMessage = "Date is out of allowed range"; @@ -127,10 +186,11 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & * specified {@code resolution}. * * @param resolution - * initial resolution for the field + * initial resolution for the field, not {@code null} */ public AbstractDateField(R resolution) { - this.resolution = resolution; + registerRpc(rpc); + setResolution(resolution); } /** @@ -139,7 +199,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & * @param caption * the caption of the datefield. * @param resolution - * initial resolution for the field + * initial resolution for the field, not {@code null} */ public AbstractDateField(String caption, R resolution) { this(resolution); @@ -155,7 +215,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & * @param value * the date/time value. * @param resolution - * initial resolution for the field + * initial resolution for the field, not {@code null} */ public AbstractDateField(String caption, T value, R resolution) { this(caption, resolution); @@ -164,141 +224,21 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & /* Component basic features */ - /* - * Paints this component. Don't add a JavaDoc comment here, we use the - * default documentation from implemented interface. - */ @Override - public void paintContent(PaintTarget target) throws PaintException { + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); - // Adds the locale as attribute - final Locale l = getLocale(); - if (l != null) { - target.addAttribute("locale", l.toString()); - } - - if (getDateFormat() != null) { - target.addAttribute("format", getDateFormat()); - } - - if (!isLenient()) { - target.addAttribute("strict", true); - } - - target.addAttribute(DateFieldConstants.ATTR_WEEK_NUMBERS, - isShowISOWeekNumbers()); - target.addAttribute("parsable", uiHasValidDateString); - final T currentDate = getValue(); - - // Only paint variables for the resolution and up, e.g. Resolution DAY - // paints DAY,MONTH,YEAR - for (R res : getResolutionsHigherOrEqualTo(getResolution())) { - int value = -1; - if (currentDate != null) { - value = getDatePart(currentDate, res); - } - String variableName = getResolutionVariable(res); - target.addVariable(this, variableName, value); - if (defaultValue != null) { - int defaultValuePart = getDatePart(defaultValue, res); - target.addVariable(this, "default-" + variableName, - defaultValuePart); - } else { - target.addVariable(this, "default-" + variableName, -1); - } - } - } - - /* - * Invoked when a variable of the component changes. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - Set<String> resolutionNames = getResolutions() - .map(this::getResolutionVariable).collect(Collectors.toSet()); - resolutionNames.retainAll(variables.keySet()); - if (!isReadOnly() && (!resolutionNames.isEmpty() - || variables.containsKey("dateString"))) { - - // Old and new dates - final T oldDate = getValue(); - - // this enables analyzing invalid input on the server - // this variable is null if the date was chosen with popup calendar - // or contains user-typed string - final String newDateString = (String) variables.get("dateString"); - - T newDate; - - boolean hasChanges = false; - - if ("".equals(newDateString)) { - - newDate = null; - // TODO check if the following 3 lines are necessary - hasChanges = !uiHasValidDateString; - uiHasValidDateString = true; - currentParseErrorMessage = null; - } else { - newDate = reconstructDateFromFields(variables, oldDate); - } - - hasChanges |= !Objects.equals(dateString, newDateString) - || !Objects.equals(oldDate, newDate); - - if (hasChanges) { - dateString = newDateString; - if (newDateString == null || newDateString.isEmpty()) { - uiHasValidDateString = true; - currentParseErrorMessage = null; - setComponentError(null); - setValue(newDate, true); - } else { - if (variables.get("lastInvalidDateString") != null) { - Result<T> parsedDate = handleUnparsableDateString( - dateString); - parsedDate.ifOk(v -> { - uiHasValidDateString = true; - currentParseErrorMessage = null; - setValue(v, true); - }); - if (parsedDate.isError()) { - dateString = null; - uiHasValidDateString = false; - currentParseErrorMessage = parsedDate.getMessage() - .orElse("Parsing error"); - setComponentError( - new UserError(getParseErrorMessage())); - setValue(null, true); - } - } else { - uiHasValidDateString = true; - currentParseErrorMessage = null; - setValue(newDate, true); - } - } - markAsDirty(); - } - } - - if (variables.containsKey(FocusEvent.EVENT_ID)) { - fireEvent(new FocusEvent(this)); - } - - if (variables.containsKey(BlurEvent.EVENT_ID)) { - fireEvent(new BlurEvent(this)); - } + Locale locale = getLocale(); + getState().locale = locale == null ? null : locale.toString(); } /** * Construct a date object from the individual field values received from * the client. * - * @since 8.1.1 + * @since */ - protected T reconstructDateFromFields(Map<String, Object> variables, + protected T reconstructDateFromFields(Map<String, Integer> variables, T oldDate) { Map<R, Integer> calendarFields = new HashMap<>(); @@ -307,8 +247,8 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & // resolutions that are painted String variableName = getResolutionVariable(resolution); - Integer newValue = (Integer) variables.get(variableName); - if (newValue != null && newValue >= 0) { + Integer newValue = variables.get(variableName); + if (newValue != null) { calendarFields.put(resolution, newValue); } else { calendarFields.put(resolution, @@ -378,7 +318,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & */ public void setResolution(R resolution) { this.resolution = resolution; - markAsDirty(); + updateResolutions(); } /** @@ -429,23 +369,23 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & * override formatting. See Vaadin issue #2200. * * @param dateFormat - * the dateFormat to set + * the dateFormat to set, can be {@code null} * * @see com.vaadin.ui.AbstractComponent#setLocale(Locale)) */ public void setDateFormat(String dateFormat) { - this.dateFormat = dateFormat; - markAsDirty(); + getState().format = dateFormat; } /** - * Returns a format string used to format date value on client side or null - * if default formatting from {@link Component#getLocale()} is used. + * Returns a format string used to format date value on client side or + * {@code null} if default formatting from {@link Component#getLocale()} is + * used. * * @return the dateFormat */ public String getDateFormat() { - return dateFormat; + return getState(false).format; } /** @@ -484,6 +424,32 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & super.setLocale(locale); } + private void updateResolutions() { + final T currentDate = getValue(); + + Map<String, Integer> resolutions = getState().resolutions; + resolutions.clear(); + + // Only paint variables for the resolution and up, e.g. Resolution DAY + // paints DAY,MONTH,YEAR + for (R res : getResolutionsHigherOrEqualTo(getResolution())) { + String variableName = getResolutionVariable(res); + + Integer value = getValuePart(currentDate, res); + resolutions.put(variableName, value); + + Integer defaultValuePart = getValuePart(defaultValue, res); + resolutions.put("default-" + variableName, defaultValuePart); + } + } + + private Integer getValuePart(T date, R resolution) { + if (date == null) { + return null; + } + return getDatePart(date, resolution); + } + /** * Returns the {@link ZoneId}, which is used when {@code z} is included * inside the {@link #setDateFormat(String)}. @@ -507,20 +473,19 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & * be turned off. */ public void setLenient(boolean lenient) { - this.lenient = lenient; - markAsDirty(); + getState().lenient = lenient; } /** - * Returns whether date/time interpretation is to be lenient. + * Returns whether date/time interpretation is lenient. * * @see #setLenient(boolean) * - * @return true if the interpretation mode of this calendar is lenient; - * false otherwise. + * @return {@code true} if the interpretation mode of this calendar is + * lenient; {@code false} otherwise. */ public boolean isLenient() { - return lenient; + return getState(false).lenient; } @Override @@ -549,6 +514,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & */ public void setDefaultValue(T defaultValue) { this.defaultValue = defaultValue; + updateResolutions(); } /** @@ -566,7 +532,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & * user). No value changes should happen, but we need to do some * internal housekeeping. */ - if (value == null && !uiHasValidDateString) { + if (value == null && !getState(false).parsable) { /* * Side-effects of doSetValue clears possible previous strings and * flags about invalid input. @@ -585,7 +551,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & * @return true if week numbers are shown, false otherwise. */ public boolean isShowISOWeekNumbers() { - return showISOWeekNumbers; + return getState(false).showISOWeekNumbers; } /** @@ -597,8 +563,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & * true if week numbers should be shown, false otherwise. */ public void setShowISOWeekNumbers(boolean showWeekNumbers) { - showISOWeekNumbers = showWeekNumbers; - markAsDirty(); + getState().showISOWeekNumbers = showWeekNumbers; } /** @@ -745,6 +710,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & } else { setComponentError(new UserError(currentParseErrorMessage)); } + updateResolutions(); } /** @@ -800,7 +766,7 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster & protected abstract Date convertToDate(T date); private String getResolutionVariable(R resolution) { - return resolution.name().toLowerCase(Locale.ENGLISH); + return resolution.name(); } @SuppressWarnings("unchecked") diff --git a/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java b/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java index cab1addf58..4edc2a30df 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java @@ -1,8 +1,6 @@ package com.vaadin.tests.server.component.datefield; -import java.io.Serializable; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalAdjuster; +import java.time.LocalDateTime; import java.util.Date; import java.util.Map; @@ -13,43 +11,45 @@ import com.vaadin.event.FieldEvents.BlurEvent; import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.event.FieldEvents.FocusListener; +import com.vaadin.shared.ui.datefield.DateTimeResolution; import com.vaadin.tests.server.component.AbstractListenerMethodsTestBase; import com.vaadin.ui.AbstractDateField; public class DateFieldListenersTest extends AbstractListenerMethodsTestBase { - public static class TestDateField<T extends Temporal & TemporalAdjuster & Serializable & Comparable<? super T>, R extends Enum<R>> - extends AbstractDateField<T, R> { + public static class TestDateField + extends AbstractDateField<LocalDateTime, DateTimeResolution> { public TestDateField() { - super(null); + super(DateTimeResolution.DAY); } @Override - protected int getDatePart(T date, R resolution) { + protected int getDatePart(LocalDateTime date, + DateTimeResolution resolution) { return 0; } @Override - protected T buildDate(Map<R, Integer> resolutionValues) { + protected LocalDateTime buildDate( + Map<DateTimeResolution, Integer> resolutionValues) { return null; } @Override - protected RangeValidator<T> getRangeValidator() { + protected RangeValidator<LocalDateTime> getRangeValidator() { return null; } @Override - protected T convertFromDate(Date date) { + protected LocalDateTime convertFromDate(Date date) { return null; } @Override - protected Date convertToDate(T date) { + protected Date convertToDate(LocalDateTime date) { return null; } - } @Test diff --git a/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldServerRpc.java b/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldServerRpc.java new file mode 100644 index 0000000000..2ef8993fb6 --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldServerRpc.java @@ -0,0 +1,55 @@ +/* + * Copyright 2000-2016 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.shared.ui.datefield; + +import java.util.Map; + +import com.vaadin.shared.communication.ServerRpc; + +/** + * RPC interface for calls from client to server. + * + * @since + */ +public interface AbstractDateFieldServerRpc extends ServerRpc { + + /** + * Updates the typed data string and resolution names and values. + * + * @param newDateString + * the value of the text field part. It enables analyzing invalid + * input on the server. {@code null} if the date was chosen with + * popup calendar or contains user-typed string + * @param invalidDateString + * Whether the last date string is invalid or not + * @param resolutions + * map of time unit (resolution) name and value, name is the + * lower-case resolution name e.g. "hour", "minute", and value + * can be {@code null} + */ + void update(String newDateString, boolean invalidDateString, + Map<String, Integer> resolutions); + + /** + * Indicates to the server that the client-side has lost focus. + */ + void blur(); + + /** + * Indicates to the server that the client-side has acquired focus. + */ + void focus(); +} diff --git a/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java b/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java index 5bd920389e..cd1791464c 100644 --- a/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java +++ b/shared/src/main/java/com/vaadin/shared/ui/datefield/AbstractDateFieldState.java @@ -16,6 +16,8 @@ package com.vaadin.shared.ui.datefield; import java.util.Date; +import java.util.HashMap; +import java.util.Map; import com.vaadin.shared.AbstractFieldState; import com.vaadin.shared.annotations.NoLayout; @@ -54,4 +56,54 @@ public class AbstractDateFieldState extends AbstractFieldState { * @since 8.2 */ public String timeZoneJSON; + + /** + * The used Locale, can be {@code null}. + * + * @since + */ + public String locale; + + /** + * Overridden date format string, can be {@code null} if default formatting + * of the components locale is used. + * + * @since + */ + public String format; + + /** + * Whether the date/time interpretation is lenient. + * + * @since + */ + public boolean lenient; + + /** + * The map of {@code Resolution}s which are currently used by the component. + * + * The key is the resolution name e.g. "HOUR", "MINUTE", with possibly + * prefixed by "default-". + * + * The value can be {@code null} + * + * @since + */ + public Map<String, Integer> resolutions = new HashMap<>(); + + /** + * Determines if week numbers are shown in the date selector. + * + * @since + */ + public boolean showISOWeekNumbers; + + /** + * Was the last entered string parsable? If this flag is false, datefields + * internal validator does not pass. + * + * @since + */ + public boolean parsable = true; + } diff --git a/shared/src/main/java/com/vaadin/shared/ui/datefield/DateFieldConstants.java b/shared/src/main/java/com/vaadin/shared/ui/datefield/DateFieldConstants.java deleted file mode 100644 index b9cc88d708..0000000000 --- a/shared/src/main/java/com/vaadin/shared/ui/datefield/DateFieldConstants.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2000-2016 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.shared.ui.datefield; - -import java.io.Serializable; - -@Deprecated -public class DateFieldConstants implements Serializable { - - @Deprecated - public static final String ATTR_WEEK_NUMBERS = "wn"; - -} |