aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjohan <johan@vaadin.com>2013-04-08 11:55:44 +0300
committerjohan <johan@vaadin.com>2013-04-08 12:24:42 +0300
commit309e3de9152ae9958e6e723ed348712b4b39452e (patch)
treeb0b8d78e0aa5b3229eb6b5af2fb55639e5ecb77d
parent453099e29f5d6ca12f448eb9bb4264efd087ebf3 (diff)
downloadvaadin-framework-309e3de9152ae9958e6e723ed348712b4b39452e.tar.gz
vaadin-framework-309e3de9152ae9958e6e723ed348712b4b39452e.zip
Implement range for date field (#6241)
Change-Id: I34458f676fede39e1992316cbed8d62193ce8509
-rw-r--r--WebContent/VAADIN/themes/base/datefield/datefield.scss13
-rw-r--r--client/src/com/vaadin/client/ui/VCalendarPanel.java416
-rw-r--r--client/src/com/vaadin/client/ui/VPopupCalendar.java24
-rw-r--r--client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java2
-rw-r--r--client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java2
-rw-r--r--server/src/com/vaadin/ui/DateField.java175
-rw-r--r--shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java3
-rw-r--r--shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java14
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges.java270
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_ChangingRangeSoValueFallsOutsideRangeCausesOutOfRangeExceptionIfImmediateField.html251
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_EndRangeEarlierThanStartRangeCausesException.html91
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_InitialDatesOutsideRange.html121
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_MonthChangeMeansFocusDayRolledInsideRange.html100
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_NextYearClickableIfRangeAcceptsFractionOfNextYear.html191
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_PrevYearClickableIfRangeAcceptsFractionOfPrevYear.html146
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_SettingValueOutsideRangeCausesException.html136
16 files changed, 1915 insertions, 40 deletions
diff --git a/WebContent/VAADIN/themes/base/datefield/datefield.scss b/WebContent/VAADIN/themes/base/datefield/datefield.scss
index 1d3d408ed2..cbba9b46f3 100644
--- a/WebContent/VAADIN/themes/base/datefield/datefield.scss
+++ b/WebContent/VAADIN/themes/base/datefield/datefield.scss
@@ -59,10 +59,21 @@
.v-disabled .#{$primaryStyleName}-calendarpanel-day-today {
cursor: default;
}
-.#{$primaryStyleName}-calendarpanel-day-disabled {
+.#{$primaryStyleName}-calendarpanel-day-disabled,
+.#{$primaryStyleName}-calendarpanel-day-outside-range {
cursor: default;
opacity: .5;
}
+
+.#{$primaryStyleName}-calendarpanel-prevyear,
+.#{$primaryStyleName}-calendarpanel-nextyear,
+.#{$primaryStyleName}-calendarpanel-prevmonth,
+.#{$primaryStyleName}-calendarpanel-nextmonth {
+ button.outside-range{
+ opacity: .5;
+ }
+}
+
.#{$primaryStyleName}-calendarpanel-day-selected {
cursor: default;
background: #333;
diff --git a/client/src/com/vaadin/client/ui/VCalendarPanel.java b/client/src/com/vaadin/client/ui/VCalendarPanel.java
index 3e81ec734b..311932b819 100644
--- a/client/src/com/vaadin/client/ui/VCalendarPanel.java
+++ b/client/src/com/vaadin/client/ui/VCalendarPanel.java
@@ -121,6 +121,8 @@ public class VCalendarPanel extends FocusableFlexTable implements
private static final String CN_OFFMONTH = "offmonth";
+ private static final String CN_OUTSIDE_RANGE = "outside-range";
+
/**
* Represents a click handler for when a user selects a value by using the
* mouse
@@ -136,6 +138,9 @@ public class VCalendarPanel extends FocusableFlexTable implements
@Override
public void onClick(ClickEvent event) {
Date newDate = ((Day) event.getSource()).getDate();
+ if (!isDateInsideRange(newDate, Resolution.DAY)) {
+ return;
+ }
if (newDate.getMonth() != displayedMonth.getMonth()
|| newDate.getYear() != displayedMonth.getYear()) {
// If an off-month date was clicked, we must change the
@@ -298,7 +303,7 @@ public class VCalendarPanel extends FocusableFlexTable implements
* Updates year, month, day from focusedDate to value
*/
private void selectFocused() {
- if (focusedDate != null) {
+ if (focusedDate != null && isDateInsideRange(focusedDate, resolution)) {
if (value == null) {
// No previously selected value (set to null on server side).
// Create a new date using current date and time
@@ -405,10 +410,13 @@ public class VCalendarPanel extends FocusableFlexTable implements
prevMonth = new VEventButton();
prevMonth.setHTML("&lsaquo;");
prevMonth.setStyleName("v-button-prevmonth");
+
prevMonth.setTabIndex(-1);
+
nextMonth = new VEventButton();
nextMonth.setHTML("&rsaquo;");
nextMonth.setStyleName("v-button-nextmonth");
+
nextMonth.setTabIndex(-1);
setWidget(0, 3, nextMonth);
@@ -422,18 +430,23 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
if (prevYear == null) {
+
prevYear = new VEventButton();
prevYear.setHTML("&laquo;");
prevYear.setStyleName("v-button-prevyear");
+
prevYear.setTabIndex(-1);
nextYear = new VEventButton();
nextYear.setHTML("&raquo;");
nextYear.setStyleName("v-button-nextyear");
+
nextYear.setTabIndex(-1);
setWidget(0, 0, prevYear);
setWidget(0, 4, nextYear);
}
+ updateControlButtonRangeStyles(needsMonth);
+
final String monthName = needsMonth ? getDateTimeService().getMonth(
displayedMonth.getMonth()) : "";
final int year = displayedMonth.getYear() + 1900;
@@ -454,6 +467,48 @@ public class VCalendarPanel extends FocusableFlexTable implements
+ "</span>");
}
+ private void updateControlButtonRangeStyles(boolean needsMonth) {
+
+ if (focusedDate == null) {
+ return;
+ }
+
+ if (needsMonth) {
+ Date prevMonthDate = (Date) focusedDate.clone();
+ removeOneMonth(prevMonthDate);
+
+ if (!isDateInsideRange(prevMonthDate, Resolution.MONTH)) {
+ prevMonth.addStyleName(CN_OUTSIDE_RANGE);
+ } else {
+ prevMonth.removeStyleName(CN_OUTSIDE_RANGE);
+ }
+ Date nextMonthDate = (Date) focusedDate.clone();
+ addOneMonth(nextMonthDate);
+ if (!isDateInsideRange(nextMonthDate, Resolution.MONTH)) {
+ nextMonth.addStyleName(CN_OUTSIDE_RANGE);
+ } else {
+ nextMonth.removeStyleName(CN_OUTSIDE_RANGE);
+ }
+ }
+
+ Date prevYearDate = (Date) focusedDate.clone();
+ prevYearDate.setYear(prevYearDate.getYear() - 1);
+ if (!isDateInsideRange(prevYearDate, Resolution.YEAR)) {
+ prevYear.addStyleName(CN_OUTSIDE_RANGE);
+ } else {
+ prevYear.removeStyleName(CN_OUTSIDE_RANGE);
+ }
+
+ Date nextYearDate = (Date) focusedDate.clone();
+ nextYearDate.setYear(nextYearDate.getYear() + 1);
+ if (!isDateInsideRange(nextYearDate, Resolution.YEAR)) {
+ nextYear.addStyleName(CN_OUTSIDE_RANGE);
+ } else {
+ nextYear.removeStyleName(CN_OUTSIDE_RANGE);
+ }
+
+ }
+
private DateTimeService getDateTimeService() {
return dateTimeService;
}
@@ -478,6 +533,107 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
/**
+ * Checks inclusively whether a date is inside a range of dates or not.
+ *
+ * @param date
+ * @return
+ */
+ private boolean isDateInsideRange(Date date, Resolution minResolution) {
+ assert (date != null);
+
+ return isAcceptedByRangeEnd(date, minResolution)
+ && isAcceptedByRangeStart(date, minResolution);
+ }
+
+ /**
+ * Accepts dates greater than or equal to rangeStart, depending on the
+ * resolution. If the resolution is set to DAY, the range will compare on a
+ * day-basis. If the resolution is set to YEAR, only years are compared. So
+ * even if the range is set to one millisecond in next year, also next year
+ * will be included.
+ *
+ * @param date
+ * @param minResolution
+ * @return
+ */
+ private boolean isAcceptedByRangeStart(Date date, Resolution minResolution) {
+ assert (date != null);
+
+ // rangeStart == null means that we accept all values below rangeEnd
+ if (rangeStart == null) {
+ return true;
+ }
+
+ Date valueDuplicate = (Date) date.clone();
+ Date rangeStartDuplicate = (Date) rangeStart.clone();
+
+ if (minResolution == Resolution.YEAR) {
+ return valueDuplicate.getYear() >= rangeStartDuplicate.getYear();
+ }
+ if (minResolution == Resolution.MONTH) {
+ valueDuplicate = clearDateBelowMonth(valueDuplicate);
+ rangeStartDuplicate = clearDateBelowMonth(rangeStartDuplicate);
+ } else {
+ valueDuplicate = clearDateBelowDay(valueDuplicate);
+ rangeStartDuplicate = clearDateBelowDay(rangeStartDuplicate);
+ }
+
+ return !rangeStartDuplicate.after(valueDuplicate);
+ }
+
+ /**
+ * Accepts dates earlier than or equal to rangeStart, depending on the
+ * resolution. If the resolution is set to DAY, the range will compare on a
+ * day-basis. If the resolution is set to YEAR, only years are compared. So
+ * even if the range is set to one millisecond in next year, also next year
+ * will be included.
+ *
+ * @param date
+ * @param minResolution
+ * @return
+ */
+ private boolean isAcceptedByRangeEnd(Date date, Resolution minResolution) {
+ assert (date != null);
+
+ // rangeEnd == null means that we accept all values above rangeStart
+ if (rangeEnd == null) {
+ return true;
+ }
+
+ Date valueDuplicate = (Date) date.clone();
+ Date rangeEndDuplicate = (Date) rangeEnd.clone();
+
+ if (minResolution == Resolution.YEAR) {
+ return valueDuplicate.getYear() <= rangeEndDuplicate.getYear();
+ }
+ if (minResolution == Resolution.MONTH) {
+ valueDuplicate = clearDateBelowMonth(valueDuplicate);
+ rangeEndDuplicate = clearDateBelowMonth(rangeEndDuplicate);
+ } else {
+ valueDuplicate = clearDateBelowDay(valueDuplicate);
+ rangeEndDuplicate = clearDateBelowDay(rangeEndDuplicate);
+ }
+
+ return !rangeEndDuplicate.before(valueDuplicate);
+
+ }
+
+ private static Date clearDateBelowMonth(Date date) {
+ date.setDate(1);
+ return clearDateBelowDay(date);
+ }
+
+ private static Date clearDateBelowDay(Date date) {
+ date.setHours(0);
+ date.setMinutes(0);
+ date.setSeconds(0);
+ // Clearing milliseconds
+ long time = date.getTime() / 1000;
+ date = new Date(time * 1000);
+ return date;
+ }
+
+ /**
* Builds the day and time selectors of the calendar.
*/
private void buildCalendarBody() {
@@ -563,10 +719,16 @@ public class VCalendarPanel extends FocusableFlexTable implements
for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
// Actually write the day of month
- Day day = new Day((Date) curr.clone());
+ Date dayDate = (Date) curr.clone();
+ Day day = new Day(dayDate);
+
day.setStyleName(parent.getStylePrimaryName()
+ "-calendarpanel-day");
+ if (!isDateInsideRange(dayDate, Resolution.DAY)) {
+ day.addStyleDependentName(CN_OUTSIDE_RANGE);
+ }
+
if (curr.equals(selectedDate)) {
day.addStyleDependentName(CN_SELECTED);
Roles.getGridcellRole().setAriaSelectedState(
@@ -672,6 +834,17 @@ public class VCalendarPanel extends FocusableFlexTable implements
* Moves the focus forward the given number of days.
*/
private void focusNextDay(int days) {
+ if (focusedDate == null) {
+ return;
+ }
+
+ Date focusCopy = ((Date) focusedDate.clone());
+ focusCopy.setDate(focusedDate.getDate() + days);
+ if (!isDateInsideRange(focusCopy, resolution)) {
+ // If not inside allowed range, then do not move anything
+ return;
+ }
+
int oldMonth = focusedDate.getMonth();
int oldYear = focusedDate.getYear();
focusedDate.setDate(focusedDate.getDate() + days);
@@ -681,6 +854,7 @@ public class VCalendarPanel extends FocusableFlexTable implements
// Month did not change, only move the selection
focusDay(focusedDate);
} else {
+
// If the month changed we need to re-render the calendar
displayedMonth.setMonth(focusedDate.getMonth());
displayedMonth.setYear(focusedDate.getYear());
@@ -700,38 +874,83 @@ public class VCalendarPanel extends FocusableFlexTable implements
*/
private void focusNextMonth() {
- int currentMonth = focusedDate.getMonth();
- focusedDate.setMonth(currentMonth + 1);
+ if (focusedDate == null) {
+ return;
+ }
+ // Trying to request next month
+ Date requestedNextMonthDate = (Date) focusedDate.clone();
+ addOneMonth(requestedNextMonthDate);
+
+ if (!isDateInsideRange(requestedNextMonthDate, Resolution.MONTH)) {
+ return;
+ }
+
+ // Now also checking whether the day is inside the range or not. If not
+ // inside,
+ // correct it
+ if (!isDateInsideRange(requestedNextMonthDate, Resolution.DAY)) {
+ requestedNextMonthDate = adjustDateToFitInsideRange(requestedNextMonthDate);
+ }
+ focusedDate.setYear(requestedNextMonthDate.getYear());
+ focusedDate.setMonth(requestedNextMonthDate.getMonth());
+ focusedDate.setDate(requestedNextMonthDate.getDate());
+ displayedMonth.setMonth(displayedMonth.getMonth() + 1);
+
+ renderCalendar();
+ }
+
+ private static void addOneMonth(Date date) {
+ int currentMonth = date.getMonth();
int requestedMonth = (currentMonth + 1) % 12;
+ date.setMonth(date.getMonth() + 1);
+
/*
* If the selected value was e.g. 31.3 the new value would be 31.4 but
* this value is invalid so the new value will be 1.5. This is taken
* care of by decreasing the value until we have the correct month.
*/
- while (focusedDate.getMonth() != requestedMonth) {
- focusedDate.setDate(focusedDate.getDate() - 1);
+ while (date.getMonth() != requestedMonth) {
+ date.setDate(date.getDate() - 1);
}
- displayedMonth.setMonth(displayedMonth.getMonth() + 1);
-
- renderCalendar();
}
- /**
- * Selects the previous month
- */
- private void focusPreviousMonth() {
- int currentMonth = focusedDate.getMonth();
- focusedDate.setMonth(currentMonth - 1);
+ private static void removeOneMonth(Date date) {
+ int currentMonth = date.getMonth();
+
+ date.setMonth(date.getMonth() - 1);
/*
* If the selected value was e.g. 31.12 the new value would be 31.11 but
* this value is invalid so the new value will be 1.12. This is taken
* care of by decreasing the value until we have the correct month.
*/
- while (focusedDate.getMonth() == currentMonth) {
- focusedDate.setDate(focusedDate.getDate() - 1);
+ while (date.getMonth() == currentMonth) {
+ date.setDate(date.getDate() - 1);
}
+ }
+
+ /**
+ * Selects the previous month
+ */
+ private void focusPreviousMonth() {
+
+ if (focusedDate == null) {
+ return;
+ }
+ Date requestedPreviousMonthDate = (Date) focusedDate.clone();
+ removeOneMonth(requestedPreviousMonthDate);
+
+ if (!isDateInsideRange(requestedPreviousMonthDate, Resolution.MONTH)) {
+ return;
+ }
+
+ if (!isDateInsideRange(requestedPreviousMonthDate, Resolution.DAY)) {
+ requestedPreviousMonthDate = adjustDateToFitInsideRange(requestedPreviousMonthDate);
+ }
+ focusedDate.setYear(requestedPreviousMonthDate.getYear());
+ focusedDate.setMonth(requestedPreviousMonthDate.getMonth());
+ focusedDate.setDate(requestedPreviousMonthDate.getDate());
displayedMonth.setMonth(displayedMonth.getMonth() - 1);
renderCalendar();
@@ -741,16 +960,41 @@ public class VCalendarPanel extends FocusableFlexTable implements
* Selects the previous year
*/
private void focusPreviousYear(int years) {
- int currentMonth = focusedDate.getMonth();
- focusedDate.setYear(focusedDate.getYear() - years);
- displayedMonth.setYear(displayedMonth.getYear() - years);
- /*
- * If the focused date was a leap day (Feb 29), the new date becomes Mar
- * 1 if the new year is not also a leap year. Set it to Feb 28 instead.
- */
- if (focusedDate.getMonth() != currentMonth) {
- focusedDate.setDate(0);
+
+ if (focusedDate == null) {
+ return;
}
+ Date previousYearDate = (Date) focusedDate.clone();
+ previousYearDate.setYear(previousYearDate.getYear() - years);
+ // Do not focus if not inside range
+ if (!isDateInsideRange(previousYearDate, Resolution.YEAR)) {
+ return;
+ }
+ // If we remove one year, but have to roll back a bit, fit it
+ // into the calendar. Also the months have to be changed
+ if (!isDateInsideRange(previousYearDate, Resolution.DAY)) {
+ previousYearDate = adjustDateToFitInsideRange(previousYearDate);
+
+ focusedDate.setYear(previousYearDate.getYear());
+ focusedDate.setMonth(previousYearDate.getMonth());
+ focusedDate.setDate(previousYearDate.getDate());
+ displayedMonth.setYear(previousYearDate.getYear());
+ displayedMonth.setMonth(previousYearDate.getMonth());
+ } else {
+
+ int currentMonth = focusedDate.getMonth();
+ focusedDate.setYear(focusedDate.getYear() - years);
+ displayedMonth.setYear(displayedMonth.getYear() - years);
+ /*
+ * If the focused date was a leap day (Feb 29), the new date becomes
+ * Mar 1 if the new year is not also a leap year. Set it to Feb 28
+ * instead.
+ */
+ if (focusedDate.getMonth() != currentMonth) {
+ focusedDate.setDate(0);
+ }
+ }
+
renderCalendar();
}
@@ -758,16 +1002,41 @@ public class VCalendarPanel extends FocusableFlexTable implements
* Selects the next year
*/
private void focusNextYear(int years) {
- int currentMonth = focusedDate.getMonth();
- focusedDate.setYear(focusedDate.getYear() + years);
- displayedMonth.setYear(displayedMonth.getYear() + years);
- /*
- * If the focused date was a leap day (Feb 29), the new date becomes Mar
- * 1 if the new year is not also a leap year. Set it to Feb 28 instead.
- */
- if (focusedDate.getMonth() != currentMonth) {
- focusedDate.setDate(0);
+
+ if (focusedDate == null) {
+ return;
+ }
+ Date nextYearDate = (Date) focusedDate.clone();
+ nextYearDate.setYear(nextYearDate.getYear() + years);
+ // Do not focus if not inside range
+ if (!isDateInsideRange(nextYearDate, Resolution.YEAR)) {
+ return;
}
+ // If we add one year, but have to roll back a bit, fit it
+ // into the calendar. Also the months have to be changed
+ if (!isDateInsideRange(nextYearDate, Resolution.DAY)) {
+ nextYearDate = adjustDateToFitInsideRange(nextYearDate);
+
+ focusedDate.setYear(nextYearDate.getYear());
+ focusedDate.setMonth(nextYearDate.getMonth());
+ focusedDate.setDate(nextYearDate.getDate());
+ displayedMonth.setYear(nextYearDate.getYear());
+ displayedMonth.setMonth(nextYearDate.getMonth());
+ } else {
+
+ int currentMonth = focusedDate.getMonth();
+ focusedDate.setYear(focusedDate.getYear() + years);
+ displayedMonth.setYear(displayedMonth.getYear() + years);
+ /*
+ * If the focused date was a leap day (Feb 29), the new date becomes
+ * Mar 1 if the new year is not also a leap year. Set it to Feb 28
+ * instead.
+ */
+ if (focusedDate.getMonth() != currentMonth) {
+ focusedDate.setDate(0);
+ }
+ }
+
renderCalendar();
}
@@ -1266,6 +1535,20 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
/**
+ * Adjusts a date to fit inside the range, only if outside
+ *
+ * @param date
+ */
+ private Date adjustDateToFitInsideRange(Date date) {
+ if (rangeStart != null && rangeStart.after(date)) {
+ date = (Date) rangeStart.clone();
+ } else if (rangeEnd != null && rangeEnd.before(date)) {
+ date = (Date) rangeEnd.clone();
+ }
+ return date;
+ }
+
+ /**
* Sets the data of the Panel.
*
* @param currentDate
@@ -1277,12 +1560,42 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (currentDate == value && currentDate != null) {
return;
}
+ boolean currentDateWasAdjusted = false;
+ // Check that selected date is inside the allowed range
+ if (currentDate != null && !isDateInsideRange(currentDate, resolution)) {
+ currentDate = adjustDateToFitInsideRange(currentDate);
+ currentDateWasAdjusted = true;
+ }
Date oldDisplayedMonth = displayedMonth;
value = currentDate;
- if (value == null) {
- focusedDate = displayedMonth = null;
+ // If current date was adjusted, we will not select any date,
+ // since that will look like a date is selected. Instead we
+ // only focus on the adjusted value
+ if (value == null || currentDateWasAdjusted) {
+ // If ranges enabled, we may need to focus on a different view to
+ // potentially not get stuck
+ if (rangeStart != null || rangeEnd != null) {
+ Date dateThatFitsInsideRange = adjustDateToFitInsideRange(new Date());
+ focusedDate = new FocusedDate(
+ dateThatFitsInsideRange.getYear(),
+ dateThatFitsInsideRange.getMonth(),
+ dateThatFitsInsideRange.getDate());
+ displayedMonth = new FocusedDate(
+ dateThatFitsInsideRange.getYear(),
+ dateThatFitsInsideRange.getMonth(), 1);
+ // value was adjusted. Set selected to null to not cause
+ // confusion, but this is only needed (and allowed) when we have
+ // a day
+ // resolution
+ if (getResolution().getCalendarField() >= Resolution.DAY
+ .getCalendarField()) {
+ value = null;
+ }
+ } else {
+ focusedDate = displayedMonth = null;
+ }
} else {
focusedDate = new FocusedDate(value.getYear(), value.getMonth(),
value.getDate());
@@ -1725,6 +2038,10 @@ public class VCalendarPanel extends FocusableFlexTable implements
private static final String SUBPART_DAY = "day";
private static final String SUBPART_MONTH_YEAR_HEADER = "header";
+ private Date rangeStart;
+
+ private Date rangeEnd;
+
@Override
public String getSubPartName(Element subElement) {
if (contains(nextMonth, subElement)) {
@@ -1888,4 +2205,29 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
}
}
+
+ /**
+ * Sets the start range for this component. The start range is inclusive,
+ * and it depends on the current resolution, what is considered inside the
+ * range.
+ *
+ * @param startDate
+ * - the allowed range's start date
+ */
+ public void setRangeStart(Date rangeStart) {
+ this.rangeStart = rangeStart;
+
+ }
+
+ /**
+ * Sets the end range for this component. The end range is inclusive, and it
+ * depends on the current resolution, what is considered inside the range.
+ *
+ * @param endDate
+ * - the allowed range's end date
+ */
+ public void setRangeEnd(Date rangeEnd) {
+ this.rangeEnd = rangeEnd;
+
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VPopupCalendar.java b/client/src/com/vaadin/client/ui/VPopupCalendar.java
index aa34a1b4e3..87dd4061a7 100644
--- a/client/src/com/vaadin/client/ui/VPopupCalendar.java
+++ b/client/src/com/vaadin/client/ui/VPopupCalendar.java
@@ -581,4 +581,28 @@ public class VPopupCalendar extends VTextualDate implements Field,
public String getDescriptionForAssistiveDevices() {
return descriptionForAssisitveDevicesElement.getInnerText();
}
+
+ /**
+ * Sets the start range for this component. The start range is inclusive,
+ * and it depends on the current resolution, what is considered inside the
+ * range.
+ *
+ * @param startDate
+ * - the allowed range's start date
+ */
+ public void setRangeStart(Date rangeStart) {
+ calendar.setRangeStart(rangeStart);
+ }
+
+ /**
+ * Sets the end range for this component. The end range is inclusive, and it
+ * depends on the current resolution, what is considered inside the range.
+ *
+ * @param endDate
+ * - the allowed range's end date
+ */
+ public void setRangeEnd(Date rangeEnd) {
+ calendar.setRangeEnd(rangeEnd);
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java b/client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java
index beff3eaa72..2fb40b3cdb 100644
--- a/client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java
+++ b/client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java
@@ -114,6 +114,8 @@ public class InlineDateFieldConnector extends AbstractDateFieldConnector {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
getWidget().setTabIndex(getState().tabIndex);
+ getWidget().calendarPanel.setRangeStart(getState().rangeStart);
+ getWidget().calendarPanel.setRangeEnd(getState().rangeEnd);
}
@Override
diff --git a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java
index f59ac713e8..b3bb481658 100644
--- a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java
+++ b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java
@@ -138,6 +138,8 @@ public class PopupDateFieldConnector extends TextualDateConnector {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
getWidget().setTextFieldEnabled(getState().textFieldEnabled);
+ getWidget().setRangeStart(getState().rangeStart);
+ getWidget().setRangeEnd(getState().rangeEnd);
}
@Override
diff --git a/server/src/com/vaadin/ui/DateField.java b/server/src/com/vaadin/ui/DateField.java
index 78c86ceb00..c1c3ffe0bf 100644
--- a/server/src/com/vaadin/ui/DateField.java
+++ b/server/src/com/vaadin/ui/DateField.java
@@ -29,6 +29,7 @@ import com.vaadin.data.Property;
import com.vaadin.data.Validator;
import com.vaadin.data.Validator.InvalidValueException;
import com.vaadin.data.util.converter.Converter;
+import com.vaadin.data.validator.DateRangeValidator;
import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
@@ -38,6 +39,7 @@ import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.shared.ui.datefield.DateFieldConstants;
import com.vaadin.shared.ui.datefield.Resolution;
+import com.vaadin.shared.ui.datefield.TextualDateFieldState;
/**
* <p>
@@ -146,6 +148,10 @@ public class DateField extends AbstractField<Date> implements
private TimeZone timeZone = null;
private static Map<Resolution, String> variableNameForResolution = new HashMap<Resolution, String>();
+
+ private String dateOutOfRangeMessage = "Date is out of allowed range";
+
+ private DateRangeValidator currentRangeValidator;
{
variableNameForResolution.put(Resolution.SECOND, "sec");
variableNameForResolution.put(Resolution.MINUTE, "min");
@@ -277,6 +283,174 @@ public class DateField extends AbstractField<Date> implements
return super.shouldHideErrors() && uiHasValidDateString;
}
+ @Override
+ protected TextualDateFieldState getState() {
+ return (TextualDateFieldState) super.getState();
+ }
+
+ @Override
+ protected TextualDateFieldState getState(boolean markAsDirty) {
+ return (TextualDateFieldState) super.getState(markAsDirty);
+ }
+
+ /**
+ * Sets the start range for this component. If the value is set before this
+ * date (taking the resolution into account), the component will not
+ * validate. If <code>startDate</code> is set to <code>null</code>, any
+ * value before <code>endDate</code> will be accepted by the range
+ *
+ * @param startDate
+ * - the allowed range's start date
+ */
+ public void setRangeStart(Date startDate) {
+ if (startDate != null && getState().rangeEnd != null
+ && startDate.after(getState().rangeEnd)) {
+ throw new IllegalStateException(
+ "startDate cannot be later than endDate");
+ }
+ getState().rangeStart = startDate;
+ // rangeStart = startDate;
+ // This has to be done to correct for the resolution
+ // updateRangeState();
+ updateRangeValidator();
+ }
+
+ /**
+ * Sets the current error message if the range validation fails.
+ *
+ * @param dateOutOfRangeMessage
+ * - Localizable message which is shown when value (the date) is
+ * set outside allowed range
+ */
+ public void setDateOutOfRangeMessage(String dateOutOfRangeMessage) {
+ this.dateOutOfRangeMessage = dateOutOfRangeMessage;
+ updateRangeValidator();
+ }
+
+ /**
+ * Gets the end range for a certain resolution. The range is inclusive, so
+ * if rangeEnd is set to zero milliseconds past year n and resolution is set
+ * to YEAR, any date in year n will be accepted. Resolutions lower than DAY
+ * will be interpreted on a DAY level. That is, everything below DATE is
+ * cleared
+ *
+ * @param forResolution
+ * - the range conforms to the resolution
+ * @return
+ */
+ private Date getRangeEnd(Resolution forResolution) {
+ // We need to set the correct resolution for the dates,
+ // otherwise the range validator will complain
+
+ Date rangeEnd = getState(false).rangeEnd;
+ if (rangeEnd == null) {
+ return null;
+ }
+
+ Calendar endCal = Calendar.getInstance();
+ endCal.setTime(rangeEnd);
+
+ if (forResolution == Resolution.YEAR) {
+ // Adding one year (minresolution) and clearing the rest.
+ endCal.set(endCal.get(Calendar.YEAR) + 1, 0, 1, 0, 0, 0);
+ } else if (forResolution == Resolution.MONTH) {
+ // Adding one month (minresolution) and clearing the rest.
+ endCal.set(endCal.get(Calendar.YEAR),
+ endCal.get(Calendar.MONTH) + 1, 1, 0, 0, 0);
+ } else {
+ endCal.set(endCal.get(Calendar.YEAR), endCal.get(Calendar.MONTH),
+ endCal.get(Calendar.DATE) + 1, 0, 0, 0);
+ }
+ // removing one millisecond will now get the endDate to return to
+ // current resolution's set time span (year or month)
+ endCal.set(Calendar.MILLISECOND, -1);
+ return endCal.getTime();
+ }
+
+ /**
+ * Gets the start range for a certain resolution. The range is inclusive, so
+ * if <code>rangeStart</code> is set to one millisecond before year n and
+ * resolution is set to YEAR, any date in year n - 1 will be accepted.
+ * Lowest supported resolution is DAY.
+ *
+ * @param forResolution
+ * - the range conforms to the resolution
+ * @return
+ */
+ private Date getRangeStart(Resolution forResolution) {
+ if (getState(false).rangeStart == null) {
+ return null;
+ }
+ Calendar startCal = Calendar.getInstance();
+ startCal.setTime(getState(false).rangeStart);
+
+ if (forResolution == Resolution.YEAR) {
+ startCal.set(startCal.get(Calendar.YEAR), 0, 1, 0, 0, 0);
+ } else if (forResolution == Resolution.MONTH) {
+ startCal.set(startCal.get(Calendar.YEAR),
+ startCal.get(Calendar.MONTH), 1, 0, 0, 0);
+ } else {
+ startCal.set(startCal.get(Calendar.YEAR),
+ startCal.get(Calendar.MONTH), startCal.get(Calendar.DATE),
+ 0, 0, 0);
+ }
+
+ startCal.set(Calendar.MILLISECOND, 0);
+ return startCal.getTime();
+ }
+
+ private void updateRangeValidator() {
+ if (currentRangeValidator != null) {
+ removeValidator(currentRangeValidator);
+ }
+
+ currentRangeValidator = new DateRangeValidator(dateOutOfRangeMessage,
+ getRangeStart(resolution), getRangeEnd(resolution), null);
+
+ addValidator(currentRangeValidator);
+
+ }
+
+ /**
+ * Sets the end range for this component. If the value is set after this
+ * date (taking the resolution into account), the component will not
+ * validate. If <code>endDate</code> is set to <code>null</code>, any value
+ * after <code>startDate</code> will be accepted by the range.
+ *
+ * @param endDate
+ * - the allowed range's end date (inclusive, based on the
+ * current resolution)
+ */
+ public void setRangeEnd(Date endDate) {
+ if (endDate != null && getState().rangeStart != null
+ && getState().rangeStart.after(endDate)) {
+ throw new IllegalStateException(
+ "endDate cannot be earlier than startDate");
+ }
+ // rangeEnd = endDate;
+ getState().rangeEnd = endDate;
+ updateRangeValidator();
+ }
+
+ /**
+ * Returns the precise rangeStart used.
+ *
+ * @param startDate
+ *
+ */
+ public Date getRangeStart() {
+ return getState(false).rangeStart;
+ }
+
+ /**
+ * Returns the precise rangeEnd used.
+ *
+ * @param startDate
+ */
+ public Date getRangeEnd() {
+ return getState(false).rangeEnd;
+ }
+
/*
* Invoked when a variable of the component changes. Don't add a JavaDoc
* comment here, we use the default documentation from implemented
@@ -572,6 +746,7 @@ public class DateField extends AbstractField<Date> implements
*/
public void setResolution(Resolution resolution) {
this.resolution = resolution;
+ updateRangeValidator();
markAsDirty();
}
diff --git a/shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java b/shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java
index 405f89d538..d15d8de100 100644
--- a/shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java
+++ b/shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java
@@ -15,9 +15,8 @@
*/
package com.vaadin.shared.ui.datefield;
-import com.vaadin.shared.AbstractFieldState;
-public class InlineDateFieldState extends AbstractFieldState {
+public class InlineDateFieldState extends TextualDateFieldState {
{
primaryStyleName = "v-inline-datefield";
}
diff --git a/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java b/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java
index c34f3d8eda..11ad4cdb59 100644
--- a/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java
+++ b/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java
@@ -15,10 +15,24 @@
*/
package com.vaadin.shared.ui.datefield;
+import java.util.Date;
+
import com.vaadin.shared.AbstractFieldState;
public class TextualDateFieldState extends AbstractFieldState {
{
primaryStyleName = "v-datefield";
}
+
+ /*
+ * Start range that has been cleared, depending on the resolution of the
+ * date field
+ */
+ public Date rangeStart = null;
+
+ /*
+ * End range that has been cleared, depending on the resolution of the date
+ * field
+ */
+ public Date rangeEnd = null;
}
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges.java
new file mode 100644
index 0000000000..2daa3e3f96
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges.java
@@ -0,0 +1,270 @@
+package com.vaadin.tests.components.datefield;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.MarginInfo;
+import com.vaadin.shared.ui.datefield.Resolution;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.VerticalLayout;
+
+public class DateFieldRanges extends AbstractTestUI {
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 6241;
+ }
+
+ private Label label = new Label();
+ private NativeSelect resoSelect = new NativeSelect("Resolution");
+ private DateField fromRange = new DateField("Range start");
+ private DateField toRange = new DateField("Range end");
+ private DateField valueDF = new DateField("Value");
+ private CheckBox immediateCB = new CheckBox("Immediate");
+ private Button recreate = new Button("Recreate static datefields");
+ private Button clearRangeButton = new Button("Clear range");
+
+ private GridLayout currentStaticContainer;
+
+ private DateField inlineDynamicDateField;
+ private DateField dynamicDateField;
+
+ private Calendar createCalendar() {
+ Calendar c = Calendar.getInstance();
+ c.set(2013, 3, 26, 6, 1, 12);
+ return c;
+ }
+
+ private Date newDate() {
+ return createCalendar().getTime();
+ }
+
+ private void initializeControlFields() {
+ resoSelect.addItem(Resolution.MINUTE);
+ resoSelect.addItem(Resolution.SECOND);
+ resoSelect.addItem(Resolution.HOUR);
+ resoSelect.addItem(Resolution.DAY);
+ resoSelect.addItem(Resolution.MONTH);
+ resoSelect.addItem(Resolution.YEAR);
+ resoSelect.setImmediate(true);
+ resoSelect.setValue(Resolution.DAY);
+ resoSelect.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ Resolution r = (Resolution) resoSelect.getValue();
+ inlineDynamicDateField.setResolution(r);
+ dynamicDateField.setResolution(r);
+
+ }
+ });
+
+ fromRange.setValue(null);
+ fromRange.setImmediate(true);
+ fromRange.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ inlineDynamicDateField.setRangeStart(fromRange.getValue());
+ dynamicDateField.setRangeStart(fromRange.getValue());
+
+ }
+ });
+
+ toRange.setValue(null);
+ toRange.setImmediate(true);
+ toRange.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ inlineDynamicDateField.setRangeEnd(toRange.getValue());
+ dynamicDateField.setRangeEnd(toRange.getValue());
+
+ }
+ });
+
+ valueDF.setValue(null);
+ valueDF.setImmediate(true);
+ valueDF.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ inlineDynamicDateField.setValue(valueDF.getValue());
+ dynamicDateField.setValue(valueDF.getValue());
+
+ }
+ });
+
+ immediateCB.setValue(true);
+ immediateCB.setImmediate(true);
+ immediateCB.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ inlineDynamicDateField.setImmediate(immediateCB.getValue());
+ dynamicDateField.setImmediate(immediateCB.getValue());
+
+ }
+ });
+
+ recreate.addClickListener(new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ GridLayout newContainer = createStaticFields();
+ replaceComponent(currentStaticContainer, newContainer);
+ currentStaticContainer = newContainer;
+ }
+ });
+
+ clearRangeButton.addClickListener(new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ fromRange.setValue(null);
+ toRange.setValue(null);
+ }
+ });
+
+ Calendar startCal = createCalendar();
+ Calendar endCal = createCalendar();
+ endCal.add(Calendar.DATE, 30);
+
+ dynamicDateField = createDateField(startCal.getTime(),
+ endCal.getTime(), null, Resolution.DAY, false);
+ inlineDynamicDateField = createDateField(startCal.getTime(),
+ endCal.getTime(), null, Resolution.DAY, true);
+
+ resoSelect.setId("resoSelect");
+ fromRange.setId("fromRange");
+ toRange.setId("toRange");
+ valueDF.setId("valueDF");
+ immediateCB.setId("immediateCB");
+ recreate.setId("recreate");
+ clearRangeButton.setId("clearRangeButton");
+ dynamicDateField.setId("dynamicDateField");
+ inlineDynamicDateField.setId("inlineDynamicDateField");
+
+ }
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ setLocale(new Locale("en", "US"));
+ getLayout().setWidth(100, Unit.PERCENTAGE);
+ getLayout().setHeight(null);
+ getLayout().setMargin(new MarginInfo(true, false, false, false));
+ getLayout().setSpacing(true);
+
+ initializeControlFields();
+
+ GridLayout gl = new GridLayout(2, 2);
+ gl.setSpacing(true);
+
+ gl.addComponent(dynamicDateField);
+ gl.addComponent(inlineDynamicDateField);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.setSpacing(true);
+ hl.addComponent(resoSelect);
+ hl.addComponent(fromRange);
+ hl.addComponent(toRange);
+ hl.addComponent(valueDF);
+ hl.addComponent(immediateCB);
+ hl.addComponent(recreate);
+ hl.addComponent(clearRangeButton);
+ addComponent(hl);
+ addComponent(new Label("Dynamic DateFields"));
+ addComponent(gl);
+ currentStaticContainer = createStaticFields();
+ addComponent(new Label("Static DateFields"));
+ addComponent(currentStaticContainer);
+
+ addComponent(label);
+
+ }
+
+ private GridLayout createStaticFields() {
+ Calendar startCal = createCalendar();
+ Calendar endCal = createCalendar();
+ endCal.add(Calendar.DATE, 30);
+ GridLayout gl = new GridLayout(2, 2);
+ gl.setSpacing(true);
+ DateField df = createDateField(startCal.getTime(), endCal.getTime(),
+ null, Resolution.DAY, false);
+ gl.addComponent(df);
+ DateField inline = createDateField(startCal.getTime(),
+ endCal.getTime(), null, Resolution.DAY, true);
+ gl.addComponent(inline);
+ inline.setId("staticInline");
+ VerticalLayout vl = new VerticalLayout();
+
+ return gl;
+ }
+
+ private DateField createDateField(Date rangeStart, Date rangeEnd,
+ Date value, Resolution resolution, boolean inline) {
+
+ DateField df = null;
+
+ if (inline) {
+ df = new InlineDateField();
+ } else {
+ df = new DateField();
+ }
+
+ final DateField gg = df;
+ updateValuesForDateField(df);
+
+ df.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ label.setValue((gg.getValue() == null ? "Nothing" : gg
+ .getValue().toString())
+ + " selected. isValid: "
+ + gg.isValid());
+ }
+ });
+ return df;
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Not defined yet";
+
+ }
+
+ private void updateValuesForDateField(DateField df) {
+ Date fromVal = fromRange.getValue();
+ Date toVal = toRange.getValue();
+ Date value = valueDF.getValue();
+ Resolution r = (Resolution) resoSelect.getValue();
+ boolean immediate = immediateCB.getValue();
+
+ df.setValue(value);
+ df.setResolution(r);
+ df.setRangeStart(fromVal);
+ df.setRangeEnd(toVal);
+ df.setImmediate(immediate);
+
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_ChangingRangeSoValueFallsOutsideRangeCausesOutOfRangeExceptionIfImmediateField.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_ChangingRangeSoValueFallsOutsideRangeCausesOutOfRangeExceptionIfImmediateField.html
new file mode 100644
index 0000000000..e6b498c6f7
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_ChangingRangeSoValueFallsOutsideRangeCausesOutOfRangeExceptionIfImmediateField.html
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>59,10</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4/4/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>36,13</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>2</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>2</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>2/2/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>48,13</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5/5/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>50,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>12,14</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>April 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#popupButton</td>
+ <td>14,15</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[15]</td>
+ <td>14,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[15]</td>
+ <td>14,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[4]/td[4]/span</td>
+ <td>18,12</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>March 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>April 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertTextNotPresent</td>
+ <td>April 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>15,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>15,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>14,14</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[12]</td>
+ <td>18,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[12]</td>
+ <td>12,10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[11]</td>
+ <td>17,14</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>February 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='staticInline']/table/tbody/tr[2]/td/table/tbody/tr[2]/td[5]/span</td>
+ <td>14,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='inlineDynamicDateField']/table/tbody/tr[2]/td/table/tbody/tr[2]/td[5]/span</td>
+ <td>15,6</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='staticInline']/table/tbody/tr[2]/td/table/tbody/tr[2]/td[8]/span</td>
+ <td>14,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='inlineDynamicDateField']/table/tbody/tr[2]/td/table/tbody/tr[2]/td[8]/span</td>
+ <td>19,4</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_EndRangeEarlierThanStartRangeCausesException.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_EndRangeEarlierThanStartRangeCausesException.html
new file mode 100644
index 0000000000..e0c5721c27
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_EndRangeEarlierThanStartRangeCausesException.html
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>44,6</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>4/4/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>41,14</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>3</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>3</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>3/3/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>33,9</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>//div[@id='gwt-uid-16']/span[2]</td>
+ <td>v-errorindicator</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_InitialDatesOutsideRange.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_InitialDatesOutsideRange.html
new file mode 100644
index 0000000000..eeeda5270b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_InitialDatesOutsideRange.html
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>39,14</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1/1/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>31,13</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>2</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1/2/11</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>111</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1/1/10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>52,12</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[5]/VButton[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_MonthChangeMeansFocusDayRolledInsideRange.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_MonthChangeMeansFocusDayRolledInsideRange.html
new file mode 100644
index 0000000000..6e1ca024cb
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_MonthChangeMeansFocusDayRolledInsideRange.html
@@ -0,0 +1,100 @@
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>27,11</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1/1/10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>47,10</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>2</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>2</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>2/2/10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>15,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VGridLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td>9,14</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>id=PID_VAADIN_POPUPCAL</td>
+ <td>left</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>id=PID_VAADIN_POPUPCAL</td>
+ <td>left</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr/td[3]/span</td>
+ <td>January 2010</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>id=PID_VAADIN_POPUPCAL</td>
+ <td>right</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr/td[3]/span</td>
+ <td>February 2010</td>
+</tr>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_NextYearClickableIfRangeAcceptsFractionOfNextYear.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_NextYearClickableIfRangeAcceptsFractionOfNextYear.html
new file mode 100644
index 0000000000..f5d7ee97ca
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_NextYearClickableIfRangeAcceptsFractionOfNextYear.html
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>37,13</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1/1/15</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>35,7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>12</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>12</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>12/12/14</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>40,10</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2014</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>11,8</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2015</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>13,10</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2015</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>6,7</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2015</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>15,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[5]</td>
+ <td>8,8</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>select</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::PID_SresoSelect/domChild[0]</td>
+ <td>label=MONTH</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>13,11</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2015</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>12,13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[5]</td>
+ <td>12,13</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>select</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::PID_SresoSelect/domChild[0]</td>
+ <td>label=YEAR</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>8,12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>8,12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>8,12</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>2015</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_PrevYearClickableIfRangeAcceptsFractionOfPrevYear.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_PrevYearClickableIfRangeAcceptsFractionOfPrevYear.html
new file mode 100644
index 0000000000..4c671b266d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_PrevYearClickableIfRangeAcceptsFractionOfPrevYear.html
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>33,10</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>12</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>12</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>12/12/10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>32,9</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>11</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>enter</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1/1/11</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2011</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[5]</td>
+ <td>13,12</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2010</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>9,7</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2010</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[5]</td>
+ <td>5,0</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2010</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>16,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>16,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>19,8</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>February 2012</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_SettingValueOutsideRangeCausesException.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_SettingValueOutsideRangeCausesException.html
new file mode 100644
index 0000000000..c3f7e021a8
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_SettingValueOutsideRangeCausesException.html
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>36,8</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4/4/12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>40,11</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>3</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>3</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>3/3/12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>40,5</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5/5/12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]</td>
+ <td>393,89</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#popupButton</td>
+ <td>10,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[17]</td>
+ <td>12,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[4]/td[5]/span</td>
+ <td>13,9</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>May 2012</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>