Implement DatePickerCell and use it the MailRecipe demo Review at http://gwt-code-reviews.appspot.com/320803 Review by: jgw@google.com git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7923 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/bikeshed/src/com/google/gwt/bikeshed/cells/client/Cell.java b/bikeshed/src/com/google/gwt/bikeshed/cells/client/Cell.java index d26b299..32271d7 100644 --- a/bikeshed/src/com/google/gwt/bikeshed/cells/client/Cell.java +++ b/bikeshed/src/com/google/gwt/bikeshed/cells/client/Cell.java
@@ -45,7 +45,6 @@ * @param valueUpdater a {@link ValueUpdater}, or null * @return a view data object which may be the one passed in or a new object */ - @SuppressWarnings("unused") public V onBrowserEvent(Element parent, C value, V viewData, NativeEvent event, ValueUpdater<C, V> valueUpdater) { return null;
diff --git a/bikeshed/src/com/google/gwt/bikeshed/cells/client/DateCell.java b/bikeshed/src/com/google/gwt/bikeshed/cells/client/DateCell.java index 31dfe98..d9cef80 100644 --- a/bikeshed/src/com/google/gwt/bikeshed/cells/client/DateCell.java +++ b/bikeshed/src/com/google/gwt/bikeshed/cells/client/DateCell.java
@@ -40,5 +40,4 @@ sb.append(format.format(value)); } } - }
diff --git a/bikeshed/src/com/google/gwt/bikeshed/cells/client/DatePickerCell.java b/bikeshed/src/com/google/gwt/bikeshed/cells/client/DatePickerCell.java new file mode 100644 index 0000000..d1c302b --- /dev/null +++ b/bikeshed/src/com/google/gwt/bikeshed/cells/client/DatePickerCell.java
@@ -0,0 +1,118 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.bikeshed.cells.client; + +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.event.logical.shared.ValueChangeEvent; +import com.google.gwt.event.logical.shared.ValueChangeHandler; +import com.google.gwt.i18n.client.DateTimeFormat; +import com.google.gwt.user.client.ui.PopupPanel; +import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; +import com.google.gwt.user.datepicker.client.DatePicker; + +import java.util.Date; + +/** + * A {@link Cell} used to render and edit {@link Date}s. When a cell is selected + * by clicking on it, a {@link DatePicker} is popped up. When a date is selected + * using the DatePicker, the new date is passed to the + * {@link ValueUpdater#update update} method of the {@link ValueUpdater} that + * was passed to {@link #onBrowserEvent} for the click event. Note that this + * means that the call to ValueUpdater.update will occur after onBrowserEvent + * has returned. Pressing the 'escape' key dismisses the DatePicker popup + * without calling ValueUpdater.update. + * + * <p> + * Each DatePickerCell has a unique DatePicker popup associated with it; thus, + * if a single DatePickerCell is used as the cell for a column in a table, only + * one entry in that column will be editable at a given time. + * + * @param <V> the view data type + */ +public class DatePickerCell<V> extends Cell<Date, V> { + + private static final int ESCAPE = 27; + + private final DatePicker datePicker; + private final DateTimeFormat format; + private int offsetX = 10; + private int offsetY = 10; + private PopupPanel panel; + private ValueUpdater<Date, V> valueUpdater; + private V viewData; + + /** + * Constructs a new DatePickerCell that uses the date/time format + * given by {@link DateTimeFormat#getFullDateFormat}. + */ + public DatePickerCell() { + this(DateTimeFormat.getFullDateFormat()); + } + + /** + * Constructs a new DatePickerCell that uses the given date/time format. + */ + public DatePickerCell(DateTimeFormat format) { + this.format = format; + + this.datePicker = new DatePicker(); + this.panel = new PopupPanel(true, true) { + // Dismiss when escape is pressed + @Override + public boolean onKeyUpPreview(char key, int modifiers) { + if (key == ESCAPE) { + panel.hide(); + } + return true; + } + }; + panel.add(datePicker); + + // Hide the panel and call valueUpdater.update when a date is selected + datePicker.addValueChangeHandler(new ValueChangeHandler<Date>() { + public void onValueChange(ValueChangeEvent<Date> event) { + panel.hide(); + valueUpdater.update(event.getValue(), viewData); + } + }); + } + + @Override + public V onBrowserEvent(final Element parent, Date value, V viewData, + NativeEvent event, ValueUpdater<Date, V> valueUpdater) { + if (event.getType().equals("click")) { + this.viewData = viewData; + this.valueUpdater = valueUpdater; + + datePicker.setValue(value); + panel.setPopupPositionAndShow(new PositionCallback() { + public void setPosition(int offsetWidth, int offsetHeight) { + panel.setPopupPosition(parent.getAbsoluteLeft() + offsetX, + parent.getAbsoluteTop() + offsetY); + } + }); + } + return viewData; + } + + @Override + public void render(Date value, V viewData, StringBuilder sb) { + if (value != null) { + sb.append(format.format(value)); + } + } +}
diff --git a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java index 4456372..a099a0a 100644 --- a/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java +++ b/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java
@@ -17,7 +17,9 @@ import com.google.gwt.bikeshed.cells.client.ButtonCell; import com.google.gwt.bikeshed.cells.client.CheckboxCell; +import com.google.gwt.bikeshed.cells.client.DatePickerCell; import com.google.gwt.bikeshed.cells.client.FieldUpdater; +import com.google.gwt.bikeshed.list.client.Column; import com.google.gwt.bikeshed.list.client.PagingTableListView; import com.google.gwt.bikeshed.list.client.SimpleColumn; import com.google.gwt.bikeshed.list.client.TextColumn; @@ -28,6 +30,7 @@ import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; +import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; @@ -36,6 +39,7 @@ import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -165,12 +169,14 @@ boolean isRead; String sender; String subject; + Date date; - public Message(int id, String sender, String subject) { + public Message(int id, String sender, String subject, Date date) { super(); this.id = id; this.sender = sender; this.subject = subject; + this.date = date; } @Override @@ -181,6 +187,10 @@ return id == ((Message) obj).id; } + public Date getDate() { + return date; + } + public int getId() { return id; } @@ -205,7 +215,7 @@ @Override public String toString() { return "Message [id=" + id + ", sender=" + sender + ", subject=" - + subject + ", read=" + isRead + "]"; + + subject + ", read=" + isRead + ", date=" + date + "]"; } } @@ -255,11 +265,15 @@ protected Widget createWidget() { ListViewAdapter<Message> adapter = new ListViewAdapter<Message>(); List<Message> messages = adapter.getList(); + Date now = new Date(); Random rand = new Random(); for (int i = 0; i < 1000; i++) { + // Go back up to 90 days from the current date + long dateOffset = rand.nextInt(60 * 60 * 24 * 90) * 1000L; Message message = new Message(10000 + i, senders[rand.nextInt(senders.length)], - subjects[rand.nextInt(subjects.length)]); + subjects[rand.nextInt(subjects.length)], + new Date(now.getTime() - dateOffset)); message.isRead = rand.nextBoolean(); messages.add(message); } @@ -305,6 +319,22 @@ }; table.addColumn(isReadColumn, "Read"); + Column<Message, Date, Void> dateColumn = + new Column<Message, Date, Void>(new DatePickerCell<Void>()) { + @Override + public Date getValue(Message object) { + return object.getDate(); + } + }; + dateColumn.setFieldUpdater(new FieldUpdater<Message, Date, Void>() { + public void update(int index, Message object, Date value, Void viewData) { + Window.alert("Changed date from " + object.date + " to " + value); + object.date = value; + table.refresh(); + } + }); + table.addColumn(dateColumn, "Date"); + TextColumn<Message> senderColumn = new TextColumn<Message>() { @Override public String getValue(Message object) {
diff --git a/bikeshed/war/Cookbook.css b/bikeshed/war/Cookbook.css index 7856cdc..e63c422 100644 --- a/bikeshed/war/Cookbook.css +++ b/bikeshed/war/Cookbook.css
@@ -107,3 +107,81 @@ .gwt-SplitLayoutPanel-VDragger { background: transparent url(vsplitter-grip.png) center center no-repeat; } + +/* Date picker */ + +.gwt-DatePicker { + border: 1px solid #A2BBDD; + cursor: default; +} +.gwt-DatePicker td, +.datePickerMonthSelector td:focus { + outline: none +} +.datePickerDays { + width: 100%; + background: white; +} +.datePickerDay, +.datePickerWeekdayLabel, +.datePickerWeekendLabel { + font-size: 75%; + text-align: center; + padding: 4px; + outline: none; +} +.datePickerWeekdayLabel, +.datePickerWeekendLabel { + background: #C3D9FF; + padding: 0px 4px 2px; + cursor: default; +} +.datePickerDay { + padding: 4px; + cursor: hand; + cursor: pointer; +} +.datePickerDayIsToday { + border: 1px solid black; + padding: 3px; +} +.datePickerDayIsWeekend { + background: #EEEEEE; +} +.datePickerDayIsFiller { + color: #888888; +} +.datePickerDayIsValue { + background: #aaccee; +} +.datePickerDayIsDisabled { + color: #AAAAAA; + font-style: italic; +} +.datePickerDayIsHighlighted { + background: #F0E68C; +} +.datePickerDayIsValueAndHighlighted { + background: #bbddd9; +} +.datePickerMonthSelector { + background: #C3D9FF; + width: 100%; +} +td.datePickerMonth { + text-align: center; + vertical-align: center; + white-space: nowrap; + font-size: 70%; + font-weight: bold; + color: blue; +} +.datePickerPreviousButton, +.datePickerNextButton { + font-size: 120%; + line-height: 1em; + color: blue; + cursor: hand; + cursor: pointer; + padding: 0px 4px; +}