@@ -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> | |||
@@ -1358,8 +1358,7 @@ public class ApplicationConnection implements HasHandlers { | |||
return false; | |||
} | |||
return hasEventListeners(getConnectorMap().getConnector(widget), | |||
eventIdentifier); | |||
return hasEventListeners(connector, eventIdentifier); | |||
} | |||
LayoutManager getLayoutManager() { |
@@ -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); |
@@ -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); |
@@ -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; | |||
} | |||
} |
@@ -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()) { |
@@ -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()); | |||
} | |||
} | |||
} |
@@ -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 |
@@ -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. | |||
@@ -53,22 +55,57 @@ 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); | |||
@@ -231,6 +268,20 @@ public abstract class VDateField<R extends Enum<R>> extends FlowPanel | |||
return resolution.name().toLowerCase(Locale.ENGLISH); | |||
} | |||
/** | |||
* 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). |
@@ -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(); | |||
} | |||
} | |||
@@ -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; | |||
} | |||
/** |
@@ -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) { |
@@ -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 |
@@ -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; |
@@ -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()); | |||
} | |||
} |
@@ -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 |
@@ -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; | |||
@@ -36,34 +35,6 @@ import com.vaadin.shared.ui.datefield.AbstractTextualDateFieldState; | |||
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"); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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") |
@@ -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 |
@@ -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(); | |||
} |
@@ -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; | |||
} |
@@ -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"; | |||
} |