summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorAhmed Ashour <asashour@yahoo.com>2017-10-13 08:53:17 +0200
committerTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>2017-10-13 09:53:17 +0300
commitdd5597d9014032cc366d4b70405e007b1876c350 (patch)
treea408b26413b91db0a48a87a95dfa6304c3552205 /server
parent569072dccd09a018850abb3a7f9d39373c082d4f (diff)
downloadvaadin-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.java314
-rw-r--r--server/src/test/java/com/vaadin/tests/server/component/datefield/DateFieldListenersTest.java24
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