Revision: 7923
Author: r...@google.com
Date: Thu Apr 15 10:41:22 2010
Log: Implement DatePickerCell and use it the MailRecipe demo

Review at http://gwt-code-reviews.appspot.com/320803

Review by: j...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=7923

Added:
/trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/DatePickerCell.java
Modified:
 /trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/Cell.java
 /trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/DateCell.java
/trunk/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java
 /trunk/bikeshed/war/Cookbook.css

=======================================
--- /dev/null
+++ /trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/DatePickerCell.java Thu Apr 15 10:41:22 2010
@@ -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));
+    }
+  }
+}
=======================================
--- /trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/Cell.java Fri Apr 9 11:25:51 2010 +++ /trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/Cell.java Thu Apr 15 10:41:22 2010
@@ -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;
=======================================
--- /trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/DateCell.java Fri Apr 9 11:25:51 2010 +++ /trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/DateCell.java Thu Apr 15 10:41:22 2010
@@ -40,5 +40,4 @@
       sb.append(format.format(value));
     }
   }
-
-}
+}
=======================================
--- /trunk/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java Tue Apr 13 18:19:04 2010 +++ /trunk/bikeshed/src/com/google/gwt/sample/bikeshed/cookbook/client/MailRecipe.java Thu Apr 15 10:41:22 2010
@@ -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;
-
-    public Message(int id, String sender, String subject) {
+    Date date;
+
+    public Message(int id, String sender, String subject, Date date) {
       super();
       this.id = id;
       this.sender = sender;
       this.subject = subject;
+      this.date = date;
     }

     @Override
@@ -180,6 +186,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) {
=======================================
--- /trunk/bikeshed/war/Cookbook.css    Fri Apr  9 04:13:29 2010
+++ /trunk/bikeshed/war/Cookbook.css    Thu Apr 15 10:41:22 2010
@@ -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;
+}

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to