diff options
author | Ahmed Ashour <asashour@yahoo.com> | 2017-10-13 08:53:17 +0200 |
---|---|---|
committer | Teemu Suo-Anttila <tsuoanttila@users.noreply.github.com> | 2017-10-13 09:53:17 +0300 |
commit | dd5597d9014032cc366d4b70405e007b1876c350 (patch) | |
tree | a408b26413b91db0a48a87a95dfa6304c3552205 /server | |
parent | 569072dccd09a018850abb3a7f9d39373c082d4f (diff) | |
download | vaadin-framework-dd5597d9014032cc366d4b70405e007b1876c350.tar.gz vaadin-framework-dd5597d9014032cc366d4b70405e007b1876c350.zip |
Convert AbstractDateField not to be a LegacyComponent (#10148)
Diffstat (limited to 'server')
-rw-r--r-- | server/src/main/java/com/vaadin/ui/AbstractDateField.java | 314 | ||||
-rw-r--r-- | server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java | 24 |
2 files changed, 152 insertions, 186 deletions
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 |