diff options
author | Artur Signell <artur.signell@itmill.com> | 2010-03-22 11:34:39 +0000 |
---|---|---|
committer | Artur Signell <artur.signell@itmill.com> | 2010-03-22 11:34:39 +0000 |
commit | 5abcfae71f8c32d5209f1d9cc6870f50b69dd6fa (patch) | |
tree | c60e54e437ef9c60407b48ea260a07b9418277f8 | |
parent | a77594d16f1bdb951a2c0247214e44aadd6d9a78 (diff) | |
download | vaadin-framework-5abcfae71f8c32d5209f1d9cc6870f50b69dd6fa.tar.gz vaadin-framework-5abcfae71f8c32d5209f1d9cc6870f50b69dd6fa.zip |
Fix for #3492 - DateField should have an option to show week numbers
svn changeset:12004/svn branch:6.3
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/DateTimeService.java | 31 | ||||
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java | 187 | ||||
-rw-r--r-- | src/com/vaadin/terminal/gwt/client/ui/VDateField.java | 24 | ||||
-rw-r--r-- | src/com/vaadin/ui/DateField.java | 31 |
4 files changed, 213 insertions, 60 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/DateTimeService.java b/src/com/vaadin/terminal/gwt/client/DateTimeService.java index e16d9b078d..7bc8e8eba4 100644 --- a/src/com/vaadin/terminal/gwt/client/DateTimeService.java +++ b/src/com/vaadin/terminal/gwt/client/DateTimeService.java @@ -234,4 +234,35 @@ public class DateTimeService { return ((y + 1900) * 10000 + m * 100 + d) * 1000000000;
}
+ /**
+ * Returns the ISO-8601 week number of the given date.
+ *
+ * @param date
+ * The date for which the week number should be resolved
+ * @return The ISO-8601 week number for {@literal date}
+ */
+ public static int getISOWeekNumber(Date date) {
+ final long MILLISECONDS_PER_DAY = 24 * 3600 * 1000;
+ int dayOfWeek = date.getDay(); // 0 == sunday
+
+ // ISO 8601 use weeks that start on monday so we use
+ // mon=1,tue=2,...sun=7;
+ if (dayOfWeek == 0) {
+ dayOfWeek = 7;
+ }
+ // Find nearest thursday (defines the week in ISO 8601). The week number
+ // for the nearest thursday is the same as for the target date.
+ int nearestThursdayDiff = 4 - dayOfWeek; // 4 is thursday
+ Date nearestThursday = new Date(date.getTime() + nearestThursdayDiff
+ * MILLISECONDS_PER_DAY);
+
+ Date firstOfJanuary = new Date(nearestThursday.getYear(), 0, 1);
+ long timeDiff = nearestThursday.getTime() - firstOfJanuary.getTime();
+ int daysSinceFirstOfJanuary = (int) (timeDiff / MILLISECONDS_PER_DAY);
+
+ int weekNumber = (daysSinceFirstOfJanuary) / 7 + 1;
+
+ return weekNumber;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java index 74c1a683e2..34c596ac20 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java @@ -83,8 +83,12 @@ public class VCalendarPanel extends FlexTable implements MouseListener { private void clearCalendarBody(boolean remove) {
if (!remove) {
+ // Leave the cells in place but clear their contents
+
+ // This has the side effect of ensuring that the calendar always
+ // contain 7 rows.
for (int row = 1; row < 7; row++) {
- for (int col = 0; col < 7; col++) {
+ for (int col = 0; col < 8; col++) {
days.setHTML(row, col, " ");
}
}
@@ -157,16 +161,30 @@ public class VCalendarPanel extends FlexTable implements MouseListener { private void buildCalendarBody() {
+ final boolean showISOWeekNumbers = datefield.isShowISOWeekNumbers();
+ final int columns = 1 + 5;
+ final int weekColumn = 0;
+ final int firstWeekdayColumn = 1;
+ final int headerRow = 0;
+
setWidget(1, 0, days);
setCellPadding(0);
setCellSpacing(0);
- getFlexCellFormatter().setColSpan(1, 0, 5);
+ getFlexCellFormatter().setColSpan(1, 0, columns);
getFlexCellFormatter().setStyleName(1, 0,
VDateField.CLASSNAME + "-calendarpanel-body");
- days.getFlexCellFormatter().setStyleName(0, 0, "v-first");
- days.getFlexCellFormatter().setStyleName(0, 6, "v-last");
- days.getRowFormatter().setStyleName(0,
+ days.getFlexCellFormatter().setStyleName(headerRow, weekColumn,
+ "v-week");
+ // Hide the week column if week numbers are not to be displayed.
+ days.getFlexCellFormatter().setVisible(headerRow, weekColumn,
+ showISOWeekNumbers);
+
+ days.getFlexCellFormatter().setStyleName(headerRow, firstWeekdayColumn,
+ "v-first");
+ days.getFlexCellFormatter().setStyleName(headerRow,
+ firstWeekdayColumn + 6, "v-last");
+ days.getRowFormatter().setStyleName(headerRow,
VDateField.CLASSNAME + "-calendarpanel-weekdays");
// Print weekday names
@@ -177,78 +195,129 @@ public class VCalendarPanel extends FlexTable implements MouseListener { day = 0;
}
if (datefield.getCurrentResolution() > VDateField.RESOLUTION_MONTH) {
- days.setHTML(0, i, "<strong>"
+ days.setHTML(headerRow, firstWeekdayColumn + i, "<strong>"
+ datefield.getDateTimeService().getShortDay(day)
+ "</strong>");
} else {
- days.setHTML(0, i, "");
+ days.setHTML(headerRow, firstWeekdayColumn + i, "");
}
}
// date actually selected?
- Date currentDate = datefield.getCurrentDate();
+ Date selectedDate = datefield.getCurrentDate();
+ // Showing is the date (year/month+year) that is currently shown in the
+ // panel
Date showing = datefield.getShowingDate();
- boolean selected = (currentDate != null
- && currentDate.getMonth() == showing.getMonth() && currentDate
- .getYear() == showing.getYear());
+
+ // The day of month that is selected, -1 if no day of this month is
+ // selected (i.e, showing another month/year than selected or nothing is
+ // selected)
+ int dayOfMonthSelected = -1;
+ // The day of month that is today, -1 if no day of this month is today
+ // (i.e., showing another month/year than current)
+ int dayOfMonthToday = -1;
+
+ // Find out a day this month is selected
+ if (selectedDate != null
+ && selectedDate.getMonth() == showing.getMonth()
+ && selectedDate.getYear() == showing.getYear()) {
+ dayOfMonthSelected = selectedDate.getDate();
+ }
+
+ // Find out if today is in this month
+ final Date today = new Date();
+ if (today.getMonth() == showing.getMonth()
+ && today.getYear() == showing.getYear()) {
+ dayOfMonthToday = today.getDate();
+ }
final int startWeekDay = datefield.getDateTimeService()
- .getStartWeekDay(datefield.getShowingDate());
- final int numDays = DateTimeService.getNumberOfDaysInMonth(datefield
- .getShowingDate());
+ .getStartWeekDay(showing);
+ final int daysInMonth = DateTimeService.getNumberOfDaysInMonth(showing);
+
int dayCount = 0;
- final Date today = new Date();
- final Date curr = new Date(datefield.getShowingDate().getTime());
- for (int row = 1; row < 7; row++) {
- for (int col = 0; col < 7; col++) {
- if (!(row == 1 && col < startWeekDay)) {
- if (dayCount < numDays) {
- final int selectedDate = ++dayCount;
- String title = "";
- if (entrySource != null) {
- curr.setDate(dayCount);
- final List entries = entrySource.getEntries(curr,
- VDateField.RESOLUTION_DAY);
- if (entries != null) {
- for (final Iterator it = entries.iterator(); it
- .hasNext();) {
- final CalendarEntry entry = (CalendarEntry) it
- .next();
- title += (title.length() > 0 ? ", " : "")
- + entry.getStringForDate(curr);
- }
+ final Date curr = new Date(showing.getTime());
+
+ // No month has more than 6 weeks so 6 is a safe maximum for rows.
+ for (int weekOfMonth = 1; weekOfMonth < 7; weekOfMonth++) {
+ boolean weekNumberProcessed[] = new boolean[] { false, false,
+ false, false, false, false, false };
+
+ for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
+ if (!(weekOfMonth == 1 && dayOfWeek < startWeekDay)) {
+
+ if (dayCount >= daysInMonth) {
+ // All days printed and we are done
+ break;
+ }
+
+ final int dayOfMonth = ++dayCount;
+ final String baseclass = VDateField.CLASSNAME
+ + "-calendarpanel-day";
+
+ String title = "";
+ curr.setDate(dayCount);
+
+ if (entrySource != null) {
+ final List entries = entrySource.getEntries(curr,
+ VDateField.RESOLUTION_DAY);
+ if (entries != null) {
+ for (final Iterator it = entries.iterator(); it
+ .hasNext();) {
+ final CalendarEntry entry = (CalendarEntry) it
+ .next();
+ title += (title.length() > 0 ? ", " : "")
+ + entry.getStringForDate(curr);
}
}
- final String baseclass = VDateField.CLASSNAME
- + "-calendarpanel-day";
- String cssClass = baseclass;
- if (!isEnabledDate(curr)) {
- cssClass += " " + baseclass + "-disabled";
- }
- if (selected
- && datefield.getShowingDate().getDate() == dayCount) {
- cssClass += " " + baseclass + "-selected";
- }
- if (today.getDate() == dayCount
- && today.getMonth() == datefield
- .getShowingDate().getMonth()
- && today.getYear() == datefield
- .getShowingDate().getYear()) {
- cssClass += " " + baseclass + "-today";
- }
- if (title.length() > 0) {
- cssClass += " " + baseclass + "-entry";
- }
- days.setHTML(row, col, "<span title=\"" + title
- + "\" class=\"" + cssClass + "\">"
- + selectedDate + "</span>");
- } else {
- break;
}
+ // Add CSS classes according to state
+ String cssClass = baseclass;
+
+ if (!isEnabledDate(curr)) {
+ cssClass += " " + baseclass + "-disabled";
+ }
+
+ if (dayOfMonthSelected == dayOfMonth) {
+ cssClass += " " + baseclass + "-selected";
+ }
+
+ if (dayOfMonthToday == dayOfMonth) {
+ cssClass += " " + baseclass + "-today";
+ }
+ if (title.length() > 0) {
+ cssClass += " " + baseclass + "-entry";
+ }
+
+ // Actually write the day of month
+ days.setHTML(weekOfMonth, firstWeekdayColumn + dayOfWeek,
+ "<span title=\"" + title + "\" class=\"" + cssClass
+ + "\">" + dayOfMonth + "</span>");
+
+ // ISO week numbers if requested
+ if (!weekNumberProcessed[weekOfMonth]) {
+ days.getCellFormatter().setVisible(weekOfMonth,
+ weekColumn, showISOWeekNumbers);
+ if (showISOWeekNumbers) {
+ final String baseCssClass = VDateField.CLASSNAME
+ + "-calendarpanel-weeknumber";
+ String weekCssClass = baseCssClass;
+
+ int weekNumber = DateTimeService
+ .getISOWeekNumber(curr);
+
+ days.setHTML(weekOfMonth, 0, "<span class=\""
+ + weekCssClass + "\"" + ">" + weekNumber
+ + "</span>");
+ weekNumberProcessed[weekOfMonth] = true;
+ }
+
+ }
}
}
}
+
}
private void buildTime(boolean forceRedraw) {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateField.java b/src/com/vaadin/terminal/gwt/client/ui/VDateField.java index 1ce367e587..4afe0e31e2 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VDateField.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VDateField.java @@ -34,6 +34,8 @@ public class VDateField extends FlowPanel implements Paintable, Field { public static final int RESOLUTION_SEC = 5;
public static final int RESOLUTION_MSEC = 6;
+ public static final String WEEK_NUMBERS = "wn";
+
static String resolutionToString(int res) {
if (res > RESOLUTION_DAY) {
return "full";
@@ -55,12 +57,17 @@ public class VDateField extends FlowPanel implements Paintable, Field { protected boolean enabled;
+ /**
+ * The date that is selected in the date field.
+ */
protected Date date = null;
// e.g when paging a calendar, before actually selecting
protected Date showingDate = new Date();
protected DateTimeService dts;
+ private boolean showISOWeekNumbers = false;
+
public VDateField() {
setStyleName(CLASSNAME);
dts = new DateTimeService();
@@ -103,6 +110,11 @@ public class VDateField extends FlowPanel implements Paintable, Field { }
}
+ // We show week numbers only if the week starts with Monday, as ISO 8601
+ // specifies
+ showISOWeekNumbers = uidl.getBooleanAttribute(WEEK_NUMBERS)
+ && dts.getFirstDayOfWeek() == 1;
+
int newResolution;
if (uidl.hasVariable("msec")) {
newResolution = RESOLUTION_MSEC;
@@ -246,4 +258,16 @@ public class VDateField extends FlowPanel implements Paintable, Field { public ApplicationConnection getClient() {
return client;
}
+
+ /**
+ * Returns whether ISO 8601 week numbers should be shown in the date
+ * selector or not. ISO 8601 defines that a week always starts with a Monday
+ * so if the week starts with another day this will return false.
+ *
+ * @return true if week number should be shown, false otherwise
+ */
+ public boolean isShowISOWeekNumbers() {
+ return showISOWeekNumbers;
+ }
+
}
diff --git a/src/com/vaadin/ui/DateField.java b/src/com/vaadin/ui/DateField.java index 3c21630f0e..4f69b37de6 100644 --- a/src/com/vaadin/ui/DateField.java +++ b/src/com/vaadin/ui/DateField.java @@ -19,6 +19,7 @@ import com.vaadin.event.FieldEvents.FocusEvent; import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.terminal.PaintException; import com.vaadin.terminal.PaintTarget; +import com.vaadin.terminal.gwt.client.ui.VDateField; import com.vaadin.terminal.gwt.client.ui.VPopupCalendar; import com.vaadin.terminal.gwt.client.ui.VTextualDate; @@ -122,6 +123,11 @@ public class DateField extends AbstractField implements private boolean lenient = false; + /** + * Determines if week numbers are shown in the date selector. + */ + private boolean showISOWeekNumbers = false; + /* Constructors */ /** @@ -213,6 +219,7 @@ public class DateField extends AbstractField implements } target.addAttribute("type", type); + target.addAttribute(VDateField.WEEK_NUMBERS, isShowISOWeekNumbers()); // Gets the calendar final Calendar calendar = getCalendar(); @@ -557,7 +564,7 @@ public class DateField extends AbstractField implements } /** - * Specifies whether or not date/time interpretation is to be lenient. + * Returns whether date/time interpretation is to be lenient. Lenient * * @see #setLenient(boolean) * @@ -586,4 +593,26 @@ public class DateField extends AbstractField implements removeListener(BLUR_EVENT, BlurEvent.class, listener); } + /** + * Checks whether ISO 8601 week numbers are shown in the date selector. + * + * @return true if week numbers are shown, false otherwise. + */ + public boolean isShowISOWeekNumbers() { + return showISOWeekNumbers; + } + + /** + * Sets the visibility of ISO 8601 week numbers in the date selector. ISO + * 8601 defines that a week always starts with a Monday so the week numbers + * are only shown if this is the case. + * + * @param showWeekNumbers + * true if week numbers should be shown, false otherwise. + */ + public void setShowISOWeekNumbers(boolean showWeekNumbers) { + showISOWeekNumbers = showWeekNumbers; + requestRepaint(); + } + } |