summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtur Signell <artur.signell@itmill.com>2010-03-22 11:34:39 +0000
committerArtur Signell <artur.signell@itmill.com>2010-03-22 11:34:39 +0000
commit5abcfae71f8c32d5209f1d9cc6870f50b69dd6fa (patch)
treec60e54e437ef9c60407b48ea260a07b9418277f8
parenta77594d16f1bdb951a2c0247214e44aadd6d9a78 (diff)
downloadvaadin-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.java31
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java187
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VDateField.java24
-rw-r--r--src/com/vaadin/ui/DateField.java31
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, "&nbsp;");
}
}
@@ -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();
+ }
+
}