summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java2
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VDateField.java39
-rw-r--r--client/src/main/java/com/vaadin/client/ui/datefield/AbstractDateFieldConnector.java20
-rw-r--r--server/src/main/java/com/vaadin/ui/AbstractDateField.java115
-rwxr-xr-xuitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValue.java34
-rwxr-xr-xuitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValueTest.java46
6 files changed, 235 insertions, 21 deletions
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 a8c356a07c..9d9862ceae 100644
--- a/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java
+++ b/client/src/main/java/com/vaadin/client/ui/VAbstractPopupCalendar.java
@@ -391,6 +391,8 @@ public abstract class VAbstractPopupCalendar<PANEL extends VAbstractCalendarPane
if (getCurrentDate() != null) {
calendar.setDate((Date) getCurrentDate().clone());
+ } else if (getDefaultDate() != null) {
+ calendar.setDate(getDefaultDate());
} else {
calendar.setDate(new Date());
}
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 40fc9a8f8c..772f72c897 100644
--- a/client/src/main/java/com/vaadin/client/ui/VDateField.java
+++ b/client/src/main/java/com/vaadin/client/ui/VDateField.java
@@ -54,6 +54,12 @@ public abstract class VDateField<R extends Enum<R>> extends FlowPanel
protected boolean enabled;
/**
+ * The date that is displayed the date field before a value is selected. If
+ * null, display the current date.
+ */
+ private Date defaultDate = null;
+
+ /**
* The date that is selected in the date field. Null if an invalid date is
* specified.
*/
@@ -95,6 +101,18 @@ public abstract class VDateField<R extends Enum<R>> extends FlowPanel
}
/**
+ * Set the default date to open popup when no date is selected.
+ *
+ * @param date
+ * default date to show as the initial (non-selected) value when
+ * opening a popup with no value selected
+ * @since 8.1.2
+ */
+ public void setDefaultDate(Date date) {
+ this.defaultDate = date;
+ }
+
+ /**
* Set the current date using a map with date values.
* <p>
* The map contains integer representation of values per resolution. The
@@ -108,6 +126,27 @@ public abstract class VDateField<R extends Enum<R>> extends FlowPanel
setCurrentDate(getDate(dateValues));
}
+ /**
+ * Set the default date using a map with date values.
+ *
+ * @see #setCurrentDate(Map)
+ * @param defaultValues
+ * @since 8.1.2
+ */
+ public void setDefaultDate(Map<R, Integer> defaultValues) {
+ setDefaultDate(getDate(defaultValues));
+ }
+
+ /**
+ * Sets the default date when no date is selected.
+ *
+ * @return the default date
+ * @since 8.1.2
+ */
+ public Date getDefaultDate() {
+ return defaultDate;
+ }
+
public boolean isReadonly() {
return readonly;
}
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 c851c13679..21e85773de 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
@@ -77,6 +77,7 @@ public abstract class AbstractDateFieldConnector<R extends Enum<R>>
+ getWidget().resolutionAsString(), true);
getWidget().setCurrentDate(getTimeValues(uidl));
+ getWidget().setDefaultDate(getDefaultValues(uidl));
}
private void updateResolution(UIDL uidl) {
@@ -98,6 +99,25 @@ public abstract class AbstractDateFieldConnector<R extends Enum<R>>
: -1));
}
+ /**
+ * 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
+ */
+ protected Map<R, Integer> getDefaultValues(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("default-"
+ + getWidget().getResolutionVariable(res))
+ : -1));
+ }
+
@SuppressWarnings("unchecked")
@Override
public VDateField<R> getWidget() {
diff --git a/server/src/main/java/com/vaadin/ui/AbstractDateField.java b/server/src/main/java/com/vaadin/ui/AbstractDateField.java
index 9d063af5ec..2ad976a7fe 100644
--- a/server/src/main/java/com/vaadin/ui/AbstractDateField.java
+++ b/server/src/main/java/com/vaadin/ui/AbstractDateField.java
@@ -80,6 +80,12 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
private T value;
/**
+ * Default value of the field, displayed when nothing has been selected.
+ *
+ * @since 8.1.2
+ */
+ private T defaultValue = null;
+ /**
* Specified smallest modifiable unit for the date field.
*/
private R resolution;
@@ -187,7 +193,15 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
if (currentDate != null) {
value = getDatePart(currentDate, res);
}
- target.addVariable(this, getResolutionVariable(res), value);
+ 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);
+ }
}
}
@@ -227,8 +241,8 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
newDate = reconstructDateFromFields(variables, oldDate);
}
- hasChanges |= !Objects.equals(dateString, newDateString) ||
- !Objects.equals(oldDate, newDate);
+ hasChanges |= !Objects.equals(dateString, newDateString)
+ || !Objects.equals(oldDate, newDate);
if (hasChanges) {
dateString = newDateString;
@@ -239,18 +253,21 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
setComponentError(null);
} else {
if (variables.get("lastInvalidDateString") != null) {
- Result<T> parsedDate = handleUnparsableDateString(dateString);
- parsedDate.ifOk(v-> {
+ Result<T> parsedDate = handleUnparsableDateString(
+ dateString);
+ parsedDate.ifOk(v -> {
uiHasValidDateString = true;
currentParseErrorMessage = null;
- setValue(v,true);
+ setValue(v, true);
});
if (parsedDate.isError()) {
dateString = null;
uiHasValidDateString = false;
- currentParseErrorMessage = parsedDate.getMessage().orElse("Parsing error");
- setComponentError(new UserError(getParseErrorMessage()));
- setValue(null,true);
+ currentParseErrorMessage = parsedDate.getMessage()
+ .orElse("Parsing error");
+ setComponentError(
+ new UserError(getParseErrorMessage()));
+ setValue(null, true);
}
} else {
uiHasValidDateString = true;
@@ -272,16 +289,16 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
}
/**
- * Construct a date object from the individual field values received from the
- * client.
+ * Construct a date object from the individual field values received from
+ * the client.
*
* @since 8.1.1
*/
- protected T reconstructDateFromFields(Map<String, Object> variables, T oldDate) {
+ protected T reconstructDateFromFields(Map<String, Object> variables,
+ T oldDate) {
Map<R, Integer> calendarFields = new HashMap<>();
- for (R resolution : getResolutionsHigherOrEqualTo(
- getResolution())) {
+ for (R resolution : getResolutionsHigherOrEqualTo(getResolution())) {
// Only handle what the client is allowed to send. The same
// resolutions that are painted
String variableName = getResolutionVariable(resolution);
@@ -290,7 +307,8 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
if (newValue != null && newValue >= 0) {
calendarFields.put(resolution, newValue);
} else {
- calendarFields.put(resolution, getDatePart(oldDate, resolution));
+ calendarFields.put(resolution,
+ getDatePart(oldDate, resolution));
}
}
return buildDate(calendarFields);
@@ -460,6 +478,57 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
}
/**
+ * Returns the current default value.
+ *
+ * @see #setDefaultValue(Temporal)
+ * @return the default value
+ * @since 8.1.2
+ */
+ public T getDefaultValue() {
+ return defaultValue;
+ }
+
+ /**
+ * Sets the default value for the field. The default value is the starting
+ * point for the date field when nothing has been selected yet. If no
+ * default value is set, current date/time is used.
+ *
+ * @param defaultValue
+ * @since 8.1.2
+ */
+ public void setDefaultValue(T defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ /**
+ * Sets the value of this object. If the new value is not equal to
+ * {@code getValue()}, fires a {@link ValueChangeEvent} .
+ *
+ * @param value
+ * the new value, may be {@code null}
+ */
+ @Override
+ public void setValue(T value) {
+ /*
+ * First handle special case when the client side component have a date
+ * string but value is null (e.g. unparsable date string typed in by the
+ * user). No value changes should happen, but we need to do some
+ * internal housekeeping.
+ */
+ if (value == null && !uiHasValidDateString) {
+ /*
+ * Side-effects of doSetValue clears possible previous strings and
+ * flags about invalid input.
+ */
+ doSetValue(null);
+
+ markAsDirty();
+ return;
+ }
+ super.setValue(value);
+ }
+
+ /**
* Checks whether ISO 8601 week numbers are shown in the date selector.
*
* @return true if week numbers are shown, false otherwise.
@@ -545,17 +614,19 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
} else {
throw new RuntimeException("Cannot detect resoluton type "
+ Optional.ofNullable(dateType).map(Type::getTypeName)
- .orElse(null));
+ .orElse(null));
}
}
}
/**
- * Formats date according to the components locale.
- * To be reimplemented in subclasses.
+ * Formats date according to the components locale. To be reimplemented in
+ * subclasses.
*
- * @param value the date or {@code null}
- * @return textual representation of the date or empty string for {@code null}
+ * @param value
+ * the date or {@code null}
+ * @return textual representation of the date or empty string for
+ * {@code null}
* @since 8.1.1
*/
protected String formatDate(T value) {
@@ -610,7 +681,9 @@ public abstract class AbstractDateField<T extends Temporal & TemporalAdjuster &
} else {
dateString = formatDate(getEmptyValue());
}
- RangeValidator<T> validator = getRangeValidator();// TODO move range check to internal validator?
+ RangeValidator<T> validator = getRangeValidator();// TODO move range
+ // check to internal
+ // validator?
ValidationResult result = validator.apply(value,
new ValueContext(this, this));
if (result.isError()) {
diff --git a/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValue.java b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValue.java
new file mode 100755
index 0000000000..e422fc991e
--- /dev/null
+++ b/uitest/src/main/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValue.java
@@ -0,0 +1,34 @@
+package com.vaadin.tests.components.datefield;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.DateField;
+
+@Widgetset("com.vaadin.DefaultWidgetSet")
+public class DateFieldWithDefaultValue extends AbstractTestUI {
+
+ static final String DATEFIELD_HAS_DEFAULT = "hasdefault";
+
+ static final String DATEFIELD_REGULAR = "regular";
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ DateField dfWithDefault = new DateField(
+ "Date field with default value 2010-10-01");
+ dfWithDefault.setId(DATEFIELD_HAS_DEFAULT);
+ LocalDate defaultValue = LocalDate.parse("2010-10-01",
+ DateTimeFormatter.ISO_DATE);
+ dfWithDefault.setDefaultValue(defaultValue);
+ addComponent(dfWithDefault);
+
+ DateField regularDF = new DateField("Regular datefield");
+ regularDF.setId(DATEFIELD_REGULAR);
+ addComponent(regularDF);
+
+ }
+
+}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValueTest.java b/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValueTest.java
new file mode 100755
index 0000000000..964b6bbecb
--- /dev/null
+++ b/uitest/src/test/java/com/vaadin/tests/components/datefield/DateFieldWithDefaultValueTest.java
@@ -0,0 +1,46 @@
+package com.vaadin.tests.components.datefield;
+
+import static com.vaadin.tests.components.datefield.DateFieldWithDefaultValue.DATEFIELD_HAS_DEFAULT;
+import static com.vaadin.tests.components.datefield.DateFieldWithDefaultValue.DATEFIELD_REGULAR;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.elements.DateFieldElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class DateFieldWithDefaultValueTest extends MultiBrowserTest {
+
+ @Test
+ public void testDateFieldDefaultValue() {
+ openTestURL();
+ String datePickerId = DATEFIELD_HAS_DEFAULT;
+ getDateFieldElement(datePickerId).openPopup();
+ WebElement monthSpanElement = getMonthSpanFromVisibleCalendarPanel();
+ // Can't check for "October 2010", since IE11 translates October ->
+ // lokakuu
+ assert (monthSpanElement.getText().contains("2010"));
+ }
+
+ @Test
+ public void testDateFieldWithNoDefault() {
+ openTestURL();
+ String datePickerId = DATEFIELD_REGULAR;
+ getDateFieldElement(datePickerId).openPopup();
+ WebElement monthSpanElement = getMonthSpanFromVisibleCalendarPanel();
+ assert (!monthSpanElement.getText().contains("2010"));
+ }
+
+ private WebElement getMonthSpanFromVisibleCalendarPanel() {
+ return getDriver()
+ .findElements(
+ By.cssSelector(".v-datefield-calendarpanel-month"))
+ .get(0);
+ }
+
+ private DateFieldElement getDateFieldElement(String id) {
+ return $(DateFieldElement.class).id(id);
+ }
+
+}