Merging in date picker branch into 1.6.

git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4264 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/eclipse/reference/code-museum/.checkstyle b/eclipse/reference/code-museum/.checkstyle
new file mode 100644
index 0000000..223d35d
--- /dev/null
+++ b/eclipse/reference/code-museum/.checkstyle
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<fileset-config file-format-version="1.2.0" simple-config="true">

+    <fileset name="all" enabled="true" check-config-name="GWT Checks" local="false">

+        <file-match-pattern match-pattern="." include-pattern="true"/>

+    </fileset>

+</fileset-config>

diff --git a/reference/code-museum/src/com/google/gwt/museum/SingleIssue.gwt.xml b/reference/code-museum/src/com/google/gwt/museum/SingleIssue.gwt.xml
index dc1f1f3..0920476 100644
--- a/reference/code-museum/src/com/google/gwt/museum/SingleIssue.gwt.xml
+++ b/reference/code-museum/src/com/google/gwt/museum/SingleIssue.gwt.xml
@@ -2,11 +2,12 @@
     
     <!-- Inherit the core Web Toolkit stuff.                  -->
     <inherits name='com.google.gwt.user.User'/>
+    <inherits name='com.google.gwt.museum.Museum'/>
     <inherits name="com.google.gwt.user.theme.standard.StandardResources"/>
     
     <!-- Specify the app entry point class.                   -->
-    <entry-point class='com.google.gwt.museum.client.defaultmuseum.Issue2703'/>
+    <entry-point class='com.google.gwt.museum.client.defaultmuseum.VisualsForDateBox'/>
     <source path="client/common"/>
-    <source path="client/defaultmuseum" includes="Issue2703.java"/>
+    <source path="client/defaultmuseum"/>
     <source path="client/viewer"/>
 </module>
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
index 2f894bb..60e3bd1 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/DefaultMuseum.java
@@ -50,6 +50,8 @@
   }
 
   public void addVisuals() {
+    addIssue(new VisualsForDateBox());
+    addIssue(new VisualsForDatePicker());
     addIssue(new VisualsForDisclosurePanelEvents());
     addIssue(new VisualsForEventsFiring());
     addIssue(new VisualsForPopupEvents());
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDateBox.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDateBox.java
new file mode 100644
index 0000000..a4423a6
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDateBox.java
@@ -0,0 +1,163 @@
+/*

+ * Copyright 2008 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.museum.client.defaultmuseum;

+

+import com.google.gwt.event.dom.client.ClickEvent;

+import com.google.gwt.event.dom.client.ClickHandler;

+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.museum.client.common.AbstractIssue;

+import com.google.gwt.user.client.ui.Button;

+import com.google.gwt.user.client.ui.HTML;

+import com.google.gwt.user.client.ui.HorizontalPanel;

+import com.google.gwt.user.client.ui.Label;

+import com.google.gwt.user.client.ui.VerticalPanel;

+import com.google.gwt.user.client.ui.Widget;

+import com.google.gwt.user.datepicker.client.DateBox;

+import com.google.gwt.user.datepicker.client.DatePicker;

+import com.google.gwt.user.datepicker.client.DateBox.InvalidDateReporter;

+

+import java.util.Date;

+

+/**

+ * Visuals for date box.

+ */

+public class VisualsForDateBox extends AbstractIssue {

+

+  @Override

+  public Widget createIssue() {

+    VerticalPanel v = new VerticalPanel();

+    v.add(new HTML("<div style='height:25px'></div>"));

+    v.add(dateRange());

+    v.add(new HTML("<div style='height:25px'></div>"));

+    final Label startErrors = makeErrorLabel();

+

+    Widget errorReportingDateBox = dateRange(new DateBox.InvalidDateReporter() {

+      public void clearError() {

+        startErrors.setText("");

+      }

+      public void reportError(String input) {

+        startErrors.setText("\"" + input + "\" is not a date");

+      }

+    });

+

+    v.add(errorReportingDateBox);

+    v.add(startErrors);

+

+    return v;

+  }

+

+  @Override

+  public String getInstructions() {

+    return "Click on first date box, see that date picker is displayed, "

+        + "use arrow keys to navigate to second date box, select a date. "

+        + "The second set includes an error display (one, shared by both "

+        + "fields). See that it notices  when you type garbage, and that "

+        + "its error message is cleared when you empty the field or provide "

+        + "a valid date.";

+  }

+

+  @Override

+  public String getSummary() {

+    return "date box visual test";

+  }

+

+  @Override

+  public boolean hasCSS() {

+    return false;

+  }

+

+  private Widget dateRange() {

+    return dateRange(null);

+  }

+

+  private Widget dateRange(InvalidDateReporter invalidDateReporter) {

+    VerticalPanel v = new VerticalPanel();

+    HorizontalPanel p = new HorizontalPanel();

+    v.add(p);

+    final DateBox start = newDateBox(invalidDateReporter);

+    start.setWidth("13em");

+    final DateBox end = newDateBox(invalidDateReporter);

+    end.setWidth("13em");

+

+    end.getDatePicker().addValueChangeHandler(new ValueChangeHandler<Date>() {

+      public void onValueChange(ValueChangeEvent<Date> event) {

+        start.removeStyleName("user-modified");

+      }

+    });

+

+    start.setValue(new Date());

+

+    p.add(start);

+    Label l = new Label(" - ");

+    l.setStyleName("filler");

+    p.add(l);

+    p.add(end);

+    final Label value = new Label();

+    p.add(value);

+    HorizontalPanel h2 = new HorizontalPanel();

+    v.add(h2);

+    h2.add(new Button("Short format", new ClickHandler() {

+      public void onClick(ClickEvent event) {

+        start.setDateFormat(DateTimeFormat.getShortDateFormat());

+        end.setDateFormat(DateTimeFormat.getShortDateFormat());

+      }

+    }));

+    h2.add(new Button("Long format", new ClickHandler() {

+

+      public void onClick(ClickEvent event) {

+        start.setDateFormat(DateTimeFormat.getLongDateFormat());

+        end.setDateFormat(DateTimeFormat.getLongDateFormat());

+      }

+    }));

+

+    h2.add(new Button("Clear", new ClickHandler() {

+      public void onClick(ClickEvent sender) {

+        start.setValue(null);

+        end.setValue(null);

+      }

+    }));

+    

+    h2.add(new Button("Get Value", new ClickHandler() {

+      public void onClick(ClickEvent event) {

+        DateTimeFormat f = DateTimeFormat.getShortDateFormat();

+        Date d1 = start.getValue();

+        Date d2 = end.getValue();

+        value.setText("Start: \"" 

+            + (d1 == null ? "null" : f.format(d1))

+            + "\" End: \"" 

+            + (d2 == null ? "null" : f.format(d2)) 

+            + "\"");

+      }

+    }));

+    return v;

+  }

+

+  private Label makeErrorLabel() {

+    final Label startErrors = new Label();

+    startErrors.getElement().getStyle().setProperty("color", "red");

+    return startErrors;

+  }

+

+  private DateBox newDateBox(InvalidDateReporter invalidDateReporter) {

+    DateBox dateBox =

+        invalidDateReporter == null ? new DateBox() : new DateBox(

+            new DatePicker(), invalidDateReporter);

+    return dateBox;

+  }

+}

diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDatePicker.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDatePicker.java
new file mode 100644
index 0000000..14386b3
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDatePicker.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2008 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.museum.client.defaultmuseum;
+
+import com.google.gwt.event.logical.shared.HighlightEvent;
+import com.google.gwt.event.logical.shared.HighlightHandler;
+import com.google.gwt.event.logical.shared.ShowRangeEvent;
+import com.google.gwt.event.logical.shared.ShowRangeHandler;
+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.museum.client.common.AbstractIssue;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.user.datepicker.client.DatePicker;
+
+import java.util.Date;
+
+/**
+ * Date picker demo.
+ */
+public class VisualsForDatePicker extends AbstractIssue {
+
+  @Override
+  public Widget createIssue() {
+    VerticalPanel p = new VerticalPanel();
+    final DatePicker picker = new DatePicker();
+    p.add(picker);
+    final Label value = new Label("value: ");
+    p.add(value);
+    final Label highlight = new Label("highlight: ");
+    p.add(highlight);
+    final Label range = new Label("range: ");
+    p.add(range);
+    picker.addValueChangeHandler(new ValueChangeHandler<Date>() {
+      public void onValueChange(ValueChangeEvent<Date> event) {
+        value.setText("value: "
+            + DateTimeFormat.getShortDateFormat().format(event.getValue()));
+      }
+    });
+    picker.addHighlightHandler(new HighlightHandler<Date>() {
+
+      @SuppressWarnings("deprecation")
+      // Should never be seen, as highlight should be cloned.
+      public void onHighlight(HighlightEvent<Date> event) {
+        event.getHighlighted().setYear(1);
+        picker.getHighlightedDate().setYear(1);
+      }
+
+    });
+    picker.addHighlightHandler(new HighlightHandler<Date>() {
+      public void onHighlight(HighlightEvent<Date> event) {
+        highlight.setText("highlight: "
+            + DateTimeFormat.getShortDateFormat().format(event.getHighlighted()));
+      }
+    });
+    picker.addShowRangeHandler(new ShowRangeHandler<Date>() {
+      public void onShowRange(ShowRangeEvent<Date> event) {
+        Date start = event.getStart();
+        Date end = event.getEnd();
+        DateTimeFormat format = DateTimeFormat.getShortDateFormat();
+        range.setText("range: " + format.format(start) + " - "
+            + format.format(end));
+      }
+    });
+    return p;
+  };
+
+  @Override
+  public String getInstructions() {
+    return "Go back one month, go forward one month, check that highlighting is working, and try selecting a date.";
+  }
+
+  @Override
+  public String getSummary() {
+    return "Visual test for date picker";
+  }
+
+  @Override
+  public boolean hasCSS() {
+    return false;
+  }
+
+}
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java
index f00e966..768e1f3 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/Showcase.java
@@ -62,6 +62,7 @@
 import com.google.gwt.sample.showcase.client.content.widgets.CwBasicButton;
 import com.google.gwt.sample.showcase.client.content.widgets.CwCheckBox;
 import com.google.gwt.sample.showcase.client.content.widgets.CwCustomButton;
+import com.google.gwt.sample.showcase.client.content.widgets.CwDatePicker;
 import com.google.gwt.sample.showcase.client.content.widgets.CwFileUpload;
 import com.google.gwt.sample.showcase.client.content.widgets.CwHyperlink;
 import com.google.gwt.sample.showcase.client.content.widgets.CwRadioButton;
@@ -320,6 +321,8 @@
         images.catWidgets());
     setupMainMenuOption(catWidgets, new CwFileUpload(constants),
         images.catWidgets());
+    setupMainMenuOption(catWidgets, new CwDatePicker(constants),
+        images.catWidgets());
     setupMainMenuOption(catWidgets, new CwHyperlink(constants),
         images.catWidgets());
 
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.java
index 99b7595..68f59ec 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.java
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.java
@@ -49,6 +49,7 @@
 import com.google.gwt.sample.showcase.client.content.widgets.CwBasicButton;
 import com.google.gwt.sample.showcase.client.content.widgets.CwCheckBox;
 import com.google.gwt.sample.showcase.client.content.widgets.CwCustomButton;
+import com.google.gwt.sample.showcase.client.content.widgets.CwDatePicker;
 import com.google.gwt.sample.showcase.client.content.widgets.CwFileUpload;
 import com.google.gwt.sample.showcase.client.content.widgets.CwHyperlink;
 import com.google.gwt.sample.showcase.client.content.widgets.CwRadioButton;
@@ -73,7 +74,7 @@
     CwDateTimeFormat.CwConstants, CwMessagesExample.CwConstants,
     CwConstantsExample.CwConstants, CwConstantsWithLookupExample.CwConstants,
     CwDictionaryExample.CwConstants, CwDecoratorPanel.CwConstants,
-    CwAnimation.CwConstants {
+    CwAnimation.CwConstants, CwDatePicker.CwConstants {
 
   /**
    * The path to source code for examples, raw files, and style definitions.
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.properties b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.properties
index a049c0b..00b8a7b 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.properties
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants.properties
@@ -73,6 +73,10 @@
 cwCustomButtonDescription = PushButtons and ToggleButtons allow you to customize the look of your buttons
 cwCustomButtonPush = <b>Push Buttons:</b>
 cwCustomButtonToggle = <b>Toggle Buttons:</b>
+cwDatePickerName = Date Picker
+cwDatePickerDescription = Let users select a date using the DatePicker.
+cwDatePickerBoxLabel = <br><br><br><b>DateBox with popup DatePicker:</b>
+cwDatePickerLabel = <b>Permanent DatePicker:</b>
 cwDateTimeFormatName = Date Time Format
 cwDateTimeFormatDescription = Class DateTimeFormat supports locale-sensitive formatting and parsing of date and time values, like NumberFormat, using a flexible pattern-based syntax. Both custom patterns and standard patterns are supported.
 cwDateTimeFormatFailedToParseInput = Unable to parse input
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_ar.properties b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_ar.properties
index 6fcfa36..09b106a 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_ar.properties
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_ar.properties
@@ -234,3 +234,7 @@
 cwTreeBrahmsWorkSonatas = اثنين السوناتات لكلارينيت -- و قاصر ,لاثنين من السوناتات كلارينيت -- ة - شقة الرئيسية
 cwTreeBrahmsWorkSymphonies = رقم 1 -- ج طفيفة ,رقم 2 -- د طفيفة ,رقم 3 -- و الرئيسية ,رقم 4 -- ة طفيفة
 cwTreeMozartWorkConcertos = كونشرتو البيانو رقم 12 , كونشرتو البيانو رقم 17 , كونشرتو الكلارينت , كونشرتو الكمان رقم 5 , رقم 4 كونشرتو الكمان
+cwDatePickerName = تاريخ القاطف
+cwDatePickerDescription = اسمحوا المستخدمين اختيار تاريخ باستخدام DatePicker.
+cwDatePickerBoxLabel = <br><br><br><b>DateBox مع قافزة DatePicker : </b>
+cwDatePickerLabel = <b>الدائم DatePicker : </b>
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_fr.properties b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_fr.properties
index 183d0c9..ca4a4a5 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_fr.properties
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_fr.properties
@@ -232,3 +232,7 @@
 cwTreeBrahmsWorkSonatas = Deux Sonates pour clarinette - F Minor, deux sonates pour clarinette - mi bémol majeur
 cwTreeBrahmsWorkSymphonies = n ° 1 - C Minor, n ° 2 - ré mineur, n ° 3 - F Major, n ° 4 - E Minor
 cwTreeMozartWorkConcertos = Concerto pour piano n ° 12, Concerto pour piano n ° 17, Concerto pour clarinette, Concerto pour violon n ° 5, Concerto pour violon n ° 4
+cwDatePickerName = Date Picker
+cwDatePickerDescription = Permettre aux utilisateurs de sélectionner une date à l'aide de la DatePicker.
+cwDatePickerBoxLabel = <br><br><b>DateBox avec popup DatePicker:</b>
+cwDatePickerLabel = <b>DatePicker permanent:</b>
\ No newline at end of file
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_zh.properties b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_zh.properties
index 47586d7..f917536 100644
--- a/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_zh.properties
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/ShowcaseConstants_zh.properties
@@ -232,3 +232,7 @@
 cwTreeBrahmsWorkSonatas = 2奏鸣曲单簧管-F小调,  2单簧管奏鸣曲- E大调大
 cwTreeBrahmsWorkSymphonies =第1号-C小调, 第2号- D小调, 第3号- F大, 第4号- E小调
 cwTreeMozartWorkConcertos =钢琴协奏曲第12号, 钢琴协奏曲第17号, 单簧管协奏曲, 小提琴协奏曲第5号, 小提琴协奏曲第4号
+cwDatePickerName =日期选择器
+cwDatePickerDescription =让用户选择日期使用DatePicker 。
+cwDatePickerBoxLabel = <br><br><br><b>DateBox与弹出DatePicker:</b>
+cwDatePickerLabel =<b>常驻DatePicker:</b>
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwDatePicker.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwDatePicker.java
new file mode 100644
index 0000000..f25df4e
--- /dev/null
+++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/widgets/CwDatePicker.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2008 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.sample.showcase.client.content.widgets;
+
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.i18n.client.Constants;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.sample.showcase.client.ContentWidget;
+import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseData;
+import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseSource;
+import com.google.gwt.sample.showcase.client.ShowcaseAnnotations.ShowcaseStyle;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.user.datepicker.client.DateBox;
+import com.google.gwt.user.datepicker.client.DatePicker;
+
+import java.util.Date;
+
+/**
+ * Example file.
+ */
+@ShowcaseStyle({
+    ".gwt-DatePicker", ".datePicker", "td.datePickerMonth", ".gwt-DateBox",
+    ".dateBox"})
+public class CwDatePicker extends ContentWidget {
+  /**
+   * The constants used in this Content Widget.
+   */
+  @ShowcaseSource
+  public static interface CwConstants extends Constants,
+      ContentWidget.CwConstants {
+    String cwDatePickerBoxLabel();
+
+    String cwDatePickerDescription();
+
+    String cwDatePickerLabel();
+
+    String cwDatePickerName();
+  }
+
+  /**
+   * An instance of the constants.
+   */
+  @ShowcaseData
+  private CwConstants constants;
+
+  /**
+   * Constructor.
+   * 
+   * @param constants the constants
+   */
+  public CwDatePicker(CwConstants constants) {
+    super(constants);
+    this.constants = constants;
+  }
+
+  @Override
+  public String getDescription() {
+    return constants.cwDatePickerDescription();
+  }
+
+  @Override
+  public String getName() {
+    return constants.cwDatePickerName();
+  }
+
+  /**
+   * Initialize this example.
+   */
+  @ShowcaseSource
+  @Override
+  public Widget onInitialize() {
+    // Create a basic date picker
+    DatePicker datePicker = new DatePicker();
+    final Label text = new Label();
+
+    // Set the value in the text box when the user selects a date
+    datePicker.addValueChangeHandler(new ValueChangeHandler<Date>() {
+      public void onValueChange(ValueChangeEvent<Date> event) {
+        Date date = event.getValue();
+        String dateString = DateTimeFormat.getMediumDateFormat().format(date);
+        text.setText(dateString);
+      }
+    });
+
+    // Set the default value
+    datePicker.setValue(new Date(), true);
+
+    // Create a DateBox
+    DateBox dateBox = new DateBox();
+
+    // Combine the widgets into a panel and return them
+    VerticalPanel vPanel = new VerticalPanel();
+    vPanel.add(new HTML(constants.cwDatePickerLabel()));
+    vPanel.add(text);
+    vPanel.add(datePicker);
+    vPanel.add(new HTML(constants.cwDatePickerBoxLabel()));
+    vPanel.add(dateBox);
+    return vPanel;
+  }
+}
diff --git a/user/javadoc/com/google/gwt/examples/DateBoxExample.java b/user/javadoc/com/google/gwt/examples/DateBoxExample.java
new file mode 100644
index 0000000..8e65035
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/DateBoxExample.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2008 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.examples;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.datepicker.client.DateBox;
+
+import java.util.Date;
+
+public class DateBoxExample implements EntryPoint {
+
+  public void onModuleLoad() {
+    DateBox dateBox = new DateBox();
+    dateBox.setValue(new Date());
+    RootPanel.get().add(dateBox);
+  }
+}
diff --git a/user/javadoc/com/google/gwt/examples/DatePickerExample.java b/user/javadoc/com/google/gwt/examples/DatePickerExample.java
new file mode 100644
index 0000000..88adac9
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/DatePickerExample.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2008 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.examples;
+
+import com.google.gwt.core.client.EntryPoint;
+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.Label;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.datepicker.client.DatePicker;
+
+import java.util.Date;
+
+public class DatePickerExample implements EntryPoint {
+
+  public void onModuleLoad() {
+    // Create a date picker
+    DatePicker datePicker = new DatePicker();
+    final Label text = new Label();
+
+    // Set the value in the text box when the user selects a date
+    datePicker.addValueChangeHandler(new ValueChangeHandler<Date>() {
+      public void onValueChange(ValueChangeEvent<Date> event) {
+        Date date = event.getValue();
+        String dateString = DateTimeFormat.getMediumDateFormat().format(date);
+        text.setText(dateString);
+      }
+    });
+
+    // Set the default value
+    datePicker.setValue(new Date(), true);
+    
+    // Add the widgets to the page
+    RootPanel.get().add(text);
+    RootPanel.get().add(datePicker);
+  }
+}
diff --git a/user/src/com/google/gwt/event/dom/client/HasBlurHandlers.java b/user/src/com/google/gwt/event/dom/client/HasBlurHandlers.java
index 2892059..14c43df 100644
--- a/user/src/com/google/gwt/event/dom/client/HasBlurHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasBlurHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link BlurHandler} instances.

  */

-public interface HasBlurHandlers {

+public interface HasBlurHandlers extends HasHandlers {

   /**

    * Adds a {@link BlurEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasChangeHandlers.java b/user/src/com/google/gwt/event/dom/client/HasChangeHandlers.java
index 8b9b8da..0a9ccc2 100644
--- a/user/src/com/google/gwt/event/dom/client/HasChangeHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasChangeHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link ChangeHandler} instances.

  */

-public interface HasChangeHandlers {

+public interface HasChangeHandlers extends HasHandlers {

   /**

    * Adds a {@link ChangeEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasClickHandlers.java b/user/src/com/google/gwt/event/dom/client/HasClickHandlers.java
index 26c1a9a..0371319 100644
--- a/user/src/com/google/gwt/event/dom/client/HasClickHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasClickHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link ClickHandler} instances.

  */

-public interface HasClickHandlers {

+public interface HasClickHandlers extends HasHandlers {

   /**

    * Adds a {@link ClickEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasContextMenuHandlers.java b/user/src/com/google/gwt/event/dom/client/HasContextMenuHandlers.java
index 669ed5d..8a7e54b 100644
--- a/user/src/com/google/gwt/event/dom/client/HasContextMenuHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasContextMenuHandlers.java
@@ -15,13 +15,14 @@
  */
 package com.google.gwt.event.dom.client;
 
+import com.google.gwt.event.logical.shared.HasHandlers;
 import com.google.gwt.event.shared.HandlerRegistration;
 
 /**
  * A widget that implements this interface provides registration for
  * {@link ContextMenuHandler} instances.
  */
-public interface HasContextMenuHandlers {
+public interface HasContextMenuHandlers extends HasHandlers {
   /**
    * Adds a {@link ContextMenuEvent} handler.
    * 
diff --git a/user/src/com/google/gwt/event/dom/client/HasDoubleClickHandlers.java b/user/src/com/google/gwt/event/dom/client/HasDoubleClickHandlers.java
index 35f6d7b..9fedae7 100644
--- a/user/src/com/google/gwt/event/dom/client/HasDoubleClickHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasDoubleClickHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link DoubleClickHandler} instances.

  */

-public interface HasDoubleClickHandlers {

+public interface HasDoubleClickHandlers extends HasHandlers {

   /**

    * Adds a {@link DoubleClickEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasErrorHandlers.java b/user/src/com/google/gwt/event/dom/client/HasErrorHandlers.java
index 00b741c..3fa51ed 100644
--- a/user/src/com/google/gwt/event/dom/client/HasErrorHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasErrorHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link ErrorHandler} instances.

  */

-public interface HasErrorHandlers {

+public interface HasErrorHandlers extends HasHandlers {

   /**

    * Adds a {@link ErrorEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasFocusHandlers.java b/user/src/com/google/gwt/event/dom/client/HasFocusHandlers.java
index a7d3dfd..8b1f69b 100644
--- a/user/src/com/google/gwt/event/dom/client/HasFocusHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasFocusHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link FocusHandler} instances.

  */

-public interface HasFocusHandlers {

+public interface HasFocusHandlers extends HasHandlers {

   /**

    * Adds a {@link FocusEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasKeyDownHandlers.java b/user/src/com/google/gwt/event/dom/client/HasKeyDownHandlers.java
index 5d584d7..e3ae78a 100644
--- a/user/src/com/google/gwt/event/dom/client/HasKeyDownHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasKeyDownHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link KeyDownHandler} instances.

  */

-public interface HasKeyDownHandlers {

+public interface HasKeyDownHandlers extends HasHandlers {

   /**

    * Adds a {@link KeyDownEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasKeyPressHandlers.java b/user/src/com/google/gwt/event/dom/client/HasKeyPressHandlers.java
index 7d55449..06e4e73 100644
--- a/user/src/com/google/gwt/event/dom/client/HasKeyPressHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasKeyPressHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link KeyPressHandler} instances.

  */

-public interface HasKeyPressHandlers {

+public interface HasKeyPressHandlers extends HasHandlers {

   /**

    * Adds a {@link KeyPressEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasKeyUpHandlers.java b/user/src/com/google/gwt/event/dom/client/HasKeyUpHandlers.java
index 0b6bc92..060494e 100644
--- a/user/src/com/google/gwt/event/dom/client/HasKeyUpHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasKeyUpHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link KeyUpHandler} instances.

  */

-public interface HasKeyUpHandlers {

+public interface HasKeyUpHandlers extends HasHandlers {

   /**

    * Adds a {@link KeyUpEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasLoadHandlers.java b/user/src/com/google/gwt/event/dom/client/HasLoadHandlers.java
index efe2892..732c3e9 100644
--- a/user/src/com/google/gwt/event/dom/client/HasLoadHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasLoadHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link LoadHandler} instances.

  */

-public interface HasLoadHandlers {

+public interface HasLoadHandlers extends HasHandlers {

   /**

    * Adds a {@link LoadEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasLoseCaptureHandlers.java b/user/src/com/google/gwt/event/dom/client/HasLoseCaptureHandlers.java
index dac1c4b..397cd4e 100644
--- a/user/src/com/google/gwt/event/dom/client/HasLoseCaptureHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasLoseCaptureHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link LoseCaptureHandler} instances.

  */

-public interface HasLoseCaptureHandlers {

+public interface HasLoseCaptureHandlers extends HasHandlers {

   /**

    * Adds a {@link LoseCaptureEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasMouseDownHandlers.java b/user/src/com/google/gwt/event/dom/client/HasMouseDownHandlers.java
index 71853a1..749b93e 100644
--- a/user/src/com/google/gwt/event/dom/client/HasMouseDownHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasMouseDownHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link MouseDownHandler} instances.

  */

-public interface HasMouseDownHandlers {

+public interface HasMouseDownHandlers extends HasHandlers {

   /**

    * Adds a {@link MouseDownEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasMouseMoveHandlers.java b/user/src/com/google/gwt/event/dom/client/HasMouseMoveHandlers.java
index 90f6e55..c68ebc3 100644
--- a/user/src/com/google/gwt/event/dom/client/HasMouseMoveHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasMouseMoveHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link MouseMoveHandler} instances.

  */

-public interface HasMouseMoveHandlers {

+public interface HasMouseMoveHandlers extends HasHandlers {

   /**

    * Adds a {@link MouseMoveEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasMouseOutHandlers.java b/user/src/com/google/gwt/event/dom/client/HasMouseOutHandlers.java
index e993c67..4d3e734 100644
--- a/user/src/com/google/gwt/event/dom/client/HasMouseOutHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasMouseOutHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link MouseOutHandler} instances.

  */

-public interface HasMouseOutHandlers {

+public interface HasMouseOutHandlers extends HasHandlers {

   /**

    * Adds a {@link MouseOutEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasMouseOverHandlers.java b/user/src/com/google/gwt/event/dom/client/HasMouseOverHandlers.java
index dab97b6..28cb7d4 100644
--- a/user/src/com/google/gwt/event/dom/client/HasMouseOverHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasMouseOverHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link MouseOverHandler} instances.

  */

-public interface HasMouseOverHandlers {

+public interface HasMouseOverHandlers extends HasHandlers {

   /**

    * Adds a {@link MouseOverEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasMouseUpHandlers.java b/user/src/com/google/gwt/event/dom/client/HasMouseUpHandlers.java
index e04a391..72eec9e 100644
--- a/user/src/com/google/gwt/event/dom/client/HasMouseUpHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasMouseUpHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link MouseUpHandler} instances.

  */

-public interface HasMouseUpHandlers {

+public interface HasMouseUpHandlers extends HasHandlers {

   /**

    * Adds a {@link MouseUpEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/HasMouseWheelHandlers.java b/user/src/com/google/gwt/event/dom/client/HasMouseWheelHandlers.java
index 7aaaa41..01c0236 100644
--- a/user/src/com/google/gwt/event/dom/client/HasMouseWheelHandlers.java
+++ b/user/src/com/google/gwt/event/dom/client/HasMouseWheelHandlers.java
@@ -15,13 +15,14 @@
  */

 package com.google.gwt.event.dom.client;

 

+import com.google.gwt.event.logical.shared.HasHandlers;

 import com.google.gwt.event.shared.HandlerRegistration;

 

 /**

  * A widget that implements this interface provides registration for

  * {@link MouseWheelHandler} instances.

  */

-public interface HasMouseWheelHandlers {

+public interface HasMouseWheelHandlers extends HasHandlers {

   /**

    * Adds a {@link MouseWheelEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/dom/client/KeyEvent.java b/user/src/com/google/gwt/event/dom/client/KeyEvent.java
index 6d73bdc..18e7d2c 100644
--- a/user/src/com/google/gwt/event/dom/client/KeyEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/KeyEvent.java
@@ -36,6 +36,17 @@
   }
 
   /**
+   * Does this event have any modifier keys down? Specifically. is the control,
+   * meta, shift, or alt key currently pressed?
+   * 
+   * @return whether this event have any modifier key down
+   */
+  public boolean isAnyModifierKeyDown() {
+    return isControlKeyDown() || isShiftKeyDown() || isMetaKeyDown()
+        || isAltKeyDown();
+  }
+
+  /**
    * Gets the key-repeat state of this event.
    * 
    * @return <code>true</code> if this key event was an auto-repeat
diff --git a/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java b/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
index d81a715..556335a 100644
--- a/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
@@ -36,14 +36,13 @@
    * manager. If no such handlers exist, this method will do nothing.
    * 
    * @param <I> the item type
-   * @param <S> The event source type
    * @param source the source of the handlers
    * @param item the item
    * @return the event so that the caller can check if it was canceled, or null
-   * if no handlers of this event type have been registered
+   *         if no handlers of this event type have been registered
    */
-  public static <I, S extends HasBeforeSelectionHandlers<I> & HasHandlers> BeforeSelectionEvent<I> fire(
-      S source, I item) {
+  public static <I> BeforeSelectionEvent<I> fire(
+      HasBeforeSelectionHandlers<I> source, I item) {
     // If no handlers exist, then type can be null.
     if (TYPE != null) {
       HandlerManager handlers = source.getHandlers();
@@ -80,7 +79,7 @@
   }
 
   /**
-   * Cancel the before selection event.  
+   * Cancel the before selection event.
    * 
    * Classes overriding this method should still call super.cancel().
    */
diff --git a/user/src/com/google/gwt/event/logical/shared/CloseEvent.java b/user/src/com/google/gwt/event/logical/shared/CloseEvent.java
index 25ceaba..c68536b 100644
--- a/user/src/com/google/gwt/event/logical/shared/CloseEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/CloseEvent.java
@@ -35,12 +35,10 @@
    * no such handlers exist, this method will do nothing.

    * 

    * @param <T> the target type

-   * @param <S> The event source

    * @param source the source of the handlers

    * @param target the target

    */

-  public static <T, S extends HasCloseHandlers<T> & HasHandlers> void fire(

-      S source, T target) {

+  public static <T> void fire(HasCloseHandlers<T> source, T target) {

     fire(source, target, false);

   }

 

@@ -48,13 +46,12 @@
    * Fires a close event on all registered handlers in the handler manager.

    * 

    * @param <T> the target type

-   * @param <S> The event source

    * @param source the source of the handlers

    * @param target the target

    * @param autoClosed was the target closed automatically

    */

-  public static <T, S extends HasCloseHandlers<T> & HasHandlers> void fire(

-      S source, T target, boolean autoClosed) {

+  public static <T> void fire(

+      HasCloseHandlers<T> source, T target, boolean autoClosed) {

     if (TYPE != null) {

       HandlerManager handlers = source.getHandlers();

       if (handlers != null) {

diff --git a/user/src/com/google/gwt/event/logical/shared/HasBeforeSelectionHandlers.java b/user/src/com/google/gwt/event/logical/shared/HasBeforeSelectionHandlers.java
index 96a6d71..1c95fcc 100644
--- a/user/src/com/google/gwt/event/logical/shared/HasBeforeSelectionHandlers.java
+++ b/user/src/com/google/gwt/event/logical/shared/HasBeforeSelectionHandlers.java
@@ -23,7 +23,7 @@
  * 
  * @param <I> the type about to be selected
  */
-public interface HasBeforeSelectionHandlers<I> {
+public interface HasBeforeSelectionHandlers<I> extends HasHandlers {
   /**
    * Adds a {@link BeforeSelectionEvent} handler.
    * 
diff --git a/user/src/com/google/gwt/event/logical/shared/HasCloseHandlers.java b/user/src/com/google/gwt/event/logical/shared/HasCloseHandlers.java
index fecdb4d..76dcede 100644
--- a/user/src/com/google/gwt/event/logical/shared/HasCloseHandlers.java
+++ b/user/src/com/google/gwt/event/logical/shared/HasCloseHandlers.java
@@ -23,7 +23,7 @@
  * 

  * @param <T> the type being closed

  */

-public interface HasCloseHandlers<T> {

+public interface HasCloseHandlers<T> extends HasHandlers {

   /**

    * Adds a {@link CloseEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/logical/shared/HasHighlightHandlers.java b/user/src/com/google/gwt/event/logical/shared/HasHighlightHandlers.java
new file mode 100644
index 0000000..5c84ce6
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/shared/HasHighlightHandlers.java
@@ -0,0 +1,34 @@
+/*

+ * Copyright 2008 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.event.logical.shared;

+

+import com.google.gwt.event.shared.HandlerRegistration;

+

+/**

+ * A widget that implements this interface is a public source of

+ * {@link HighlightEvent} events.

+ * 

+ * @param <V> the highlighted value type

+ */

+public interface HasHighlightHandlers<V> extends HasHandlers {

+  /**

+   * Adds a {@link HighlightEvent} handler.

+   * 

+   * @param handler the handler

+   * @return the registration for the event

+   */

+  HandlerRegistration addHighlightHandler(HighlightHandler<V> handler);

+}

diff --git a/user/src/com/google/gwt/event/logical/shared/HasOpenHandlers.java b/user/src/com/google/gwt/event/logical/shared/HasOpenHandlers.java
index 647f270..70bd58f 100644
--- a/user/src/com/google/gwt/event/logical/shared/HasOpenHandlers.java
+++ b/user/src/com/google/gwt/event/logical/shared/HasOpenHandlers.java
@@ -23,7 +23,7 @@
  * 

  * @param <T> the type being opened

  */

-public interface HasOpenHandlers<T> {

+public interface HasOpenHandlers<T> extends HasHandlers {

   /**

    * Adds a {@link OpenEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/logical/shared/HasResizeHandlers.java b/user/src/com/google/gwt/event/logical/shared/HasResizeHandlers.java
index a5cff3f..df0b620 100644
--- a/user/src/com/google/gwt/event/logical/shared/HasResizeHandlers.java
+++ b/user/src/com/google/gwt/event/logical/shared/HasResizeHandlers.java
@@ -21,7 +21,7 @@
  * A widget that implements this interface is a public source of
  * {@link ResizeEvent} events.
  */
-public interface HasResizeHandlers {
+public interface HasResizeHandlers extends HasHandlers {
   /**
    * Adds a {@link ResizeEvent} handler.
    * 
diff --git a/user/src/com/google/gwt/event/logical/shared/HasSelectionHandlers.java b/user/src/com/google/gwt/event/logical/shared/HasSelectionHandlers.java
index 3d310c6..392c47f 100644
--- a/user/src/com/google/gwt/event/logical/shared/HasSelectionHandlers.java
+++ b/user/src/com/google/gwt/event/logical/shared/HasSelectionHandlers.java
@@ -23,7 +23,7 @@
  * 

  * @param <I> the type being selected

  */

-public interface HasSelectionHandlers<I> {

+public interface HasSelectionHandlers<I> extends HasHandlers {

   /**

    * Adds a {@link SelectionEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/logical/shared/HasShowRangeHandlers.java b/user/src/com/google/gwt/event/logical/shared/HasShowRangeHandlers.java
new file mode 100644
index 0000000..20850ce
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/shared/HasShowRangeHandlers.java
@@ -0,0 +1,34 @@
+/*

+ * Copyright 2008 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.event.logical.shared;

+

+import com.google.gwt.event.shared.HandlerRegistration;

+

+/**

+ * A widget that implements this interface is a public source of

+ * {@link ShowRangeEvent} events.

+ * 

+ * @param <V> the type of range

+ */

+public interface HasShowRangeHandlers<V> extends HasHandlers {

+  /**

+   * Adds a {@link ShowRangeEvent} handler.

+   * 

+   * @param handler the handler

+   * @return the registration for the event

+   */

+  HandlerRegistration addShowRangeHandler(ShowRangeHandler<V> handler);

+}

diff --git a/user/src/com/google/gwt/event/logical/shared/HasValueChangeHandlers.java b/user/src/com/google/gwt/event/logical/shared/HasValueChangeHandlers.java
index 2ea1f12..f4278ab 100644
--- a/user/src/com/google/gwt/event/logical/shared/HasValueChangeHandlers.java
+++ b/user/src/com/google/gwt/event/logical/shared/HasValueChangeHandlers.java
@@ -23,7 +23,7 @@
  * 

  * @param <I> the value about to be changed

  */

-public interface HasValueChangeHandlers<I> {

+public interface HasValueChangeHandlers<I> extends HasHandlers {

   /**

    * Adds a {@link ValueChangeEvent} handler.

    * 

diff --git a/user/src/com/google/gwt/event/logical/shared/HighlightEvent.java b/user/src/com/google/gwt/event/logical/shared/HighlightEvent.java
new file mode 100644
index 0000000..fa9a535
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/shared/HighlightEvent.java
@@ -0,0 +1,96 @@
+/*

+ * Copyright 2008 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.event.logical.shared;

+

+import com.google.gwt.event.shared.GwtEvent;

+import com.google.gwt.event.shared.HandlerManager;

+

+/**

+ * Represents a highlight event.

+ * 

+ * @param <V> the highlighted value type

+ */

+public class HighlightEvent<V> extends GwtEvent<HighlightHandler<V>> {

+

+  /**

+   * Handler type.

+   */

+  private static Type<HighlightHandler<?>> TYPE;

+

+  /**

+   * Fires a highlight event on all registered handlers in the handler manager.

+   * 

+   * @param <V> the highlighted value type

+   * @param <S> The event source

+   * @param source the source of the handlers

+   * @param highlighted the value highlighted

+   */

+  public static <V, S extends HasHighlightHandlers<V> & HasHandlers> void fire(

+      S source, V highlighted) {

+    if (TYPE != null) {

+      HandlerManager handlers = source.getHandlers();

+      if (handlers != null) {

+        HighlightEvent<V> event = new HighlightEvent<V>(highlighted);

+        handlers.fireEvent(event);

+      }

+    }

+  }

+

+  /**

+   * Gets the type associated with this event.

+   * 

+   * @return returns the handler type

+   */

+  public static Type<HighlightHandler<?>> getType() {

+    if (TYPE == null) {

+      TYPE = new Type<HighlightHandler<?>>();

+    }

+    return TYPE;

+  }

+

+  private final V highlighted;

+

+  /**

+   * Creates a new highlight event.

+   * 

+   * @param highlighted value highlighted

+   */

+  protected HighlightEvent(V highlighted) {

+    this.highlighted = highlighted;

+  }

+

+  /**

+   * Gets the value highlighted.

+   * 

+   * @return value highlighted

+   */

+  public V getHighlighted() {

+    return highlighted;

+  }

+

+  @Override

+  protected void dispatch(HighlightHandler<V> handler) {

+    handler.onHighlight(this);

+  }

+

+  // Because of type erasure, our static type is

+  // wild carded, yet the "real" type should use our I param.

+  @SuppressWarnings("unchecked")

+  @Override

+  protected final Type<HighlightHandler<V>> getAssociatedType() {

+    return (Type) TYPE;

+  }

+}

diff --git a/user/src/com/google/gwt/event/logical/shared/HighlightHandler.java b/user/src/com/google/gwt/event/logical/shared/HighlightHandler.java
new file mode 100644
index 0000000..effc2ce
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/shared/HighlightHandler.java
@@ -0,0 +1,33 @@
+/*

+ * Copyright 2008 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.event.logical.shared;

+

+import com.google.gwt.event.shared.EventHandler;

+

+/**

+ * Handler interface for {@link HighlightEvent} events.

+ * 

+ * @param <V> the highlighted value type

+ */

+public interface HighlightHandler<V> extends EventHandler {

+

+  /**

+   * Called when {@link HighlightEvent} is fired.

+   * 

+   * @param event the {@link HighlightEvent} that was fired

+   */

+  void onHighlight(HighlightEvent<V> event);

+}

diff --git a/user/src/com/google/gwt/event/logical/shared/OpenEvent.java b/user/src/com/google/gwt/event/logical/shared/OpenEvent.java
index 34026f2..ca8c1a6 100644
--- a/user/src/com/google/gwt/event/logical/shared/OpenEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/OpenEvent.java
@@ -35,12 +35,10 @@
    * such handlers exist, this method will do nothing.

    * 

    * @param <T> the target type

-   * @param <S> The event source

    * @param source the source of the handlers

    * @param target the target

    */

-  public static <T, S extends HasOpenHandlers<T> & HasHandlers> void fire(

-      S source, T target) {

+  public static <T> void fire(HasOpenHandlers<T> source, T target) {

     if (TYPE != null) {

       HandlerManager handlers = source.getHandlers();

       if (handlers != null) {

diff --git a/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java b/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
index 40a8423..c43ab56 100644
--- a/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
@@ -39,8 +39,7 @@
    * @param source the source of the handlers

    * @param selectedItem the selected item

    */

-  public static <I, S extends HasSelectionHandlers<I> & HasHandlers> void fire(

-      S source, I selectedItem) {

+  public static <I> void fire(HasSelectionHandlers<I> source, I selectedItem) {

     if (TYPE != null) {

       HandlerManager handlers = source.getHandlers();

       if (handlers != null) {

diff --git a/user/src/com/google/gwt/event/logical/shared/ShowRangeEvent.java b/user/src/com/google/gwt/event/logical/shared/ShowRangeEvent.java
new file mode 100644
index 0000000..cbbccb9
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/shared/ShowRangeEvent.java
@@ -0,0 +1,110 @@
+/*

+ * Copyright 2008 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.event.logical.shared;

+

+import com.google.gwt.event.shared.GwtEvent;

+import com.google.gwt.event.shared.HandlerManager;

+

+/**

+ * Represents a show range event.

+ * 

+ * @param <V> the type of range

+ */

+public class ShowRangeEvent<V> extends GwtEvent<ShowRangeHandler<V>> {

+

+  /**

+   * Handler type.

+   */

+  private static Type<ShowRangeHandler<?>> TYPE;

+

+  /**

+   * Fires a show range event on all registered handlers in the handler manager.

+   * 

+   * @param <V> the type of range

+   * @param <S> the event source

+   * @param source the source of the handlers

+   * @param start the start of the range

+   * @param end the end of the range

+   */

+  public static <V, S extends HasShowRangeHandlers<V> & HasHandlers> void fire(

+      S source, V start, V end) {

+    if (TYPE != null) {

+      HandlerManager handlers = source.getHandlers();

+      if (handlers != null) {

+        ShowRangeEvent<V> event = new ShowRangeEvent<V>(start, end);

+        handlers.fireEvent(event);

+      }

+    }

+  }

+

+  /**

+   * Gets the type associated with this event.

+   * 

+   * @return returns the handler type

+   */

+  public static Type<ShowRangeHandler<?>> getType() {

+    if (TYPE == null) {

+      TYPE = new Type<ShowRangeHandler<?>>();

+    }

+    return TYPE;

+  }

+

+  private final V start;

+

+  private final V end;

+

+  /**

+   * Creates a new show range event.

+   * 

+   * @param start start of the range

+   * @param end end of the range

+   */

+  protected ShowRangeEvent(V start, V end) {

+    this.start = start;

+    this.end = end;

+  }

+

+  /**

+   * Gets the end of the range.

+   * 

+   * @return end of the range

+   */

+  public V getEnd() {

+    return end;

+  }

+

+  /**

+   * Gets the start of the range.

+   * 

+   * @return start of the range

+   */

+  public V getStart() {

+    return start;

+  }

+

+  @Override

+  protected void dispatch(ShowRangeHandler<V> handler) {

+    handler.onShowRange(this);

+  }

+

+  // Because of type erasure, our static type is

+  // wild carded, yet the "real" type should use our I param.

+  @SuppressWarnings("unchecked")

+  @Override

+  protected final Type<ShowRangeHandler<V>> getAssociatedType() {

+    return (Type) TYPE;

+  }

+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/event/logical/shared/ShowRangeHandler.java b/user/src/com/google/gwt/event/logical/shared/ShowRangeHandler.java
new file mode 100644
index 0000000..bde468f
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/shared/ShowRangeHandler.java
@@ -0,0 +1,33 @@
+/*

+ * Copyright 2008 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.event.logical.shared;

+

+import com.google.gwt.event.shared.EventHandler;

+

+/**

+ * Handler interface for {@link ShowRangeEvent} events.

+ * 

+ * @param <V> the type of range

+ */

+public interface ShowRangeHandler<V> extends EventHandler {

+

+  /**

+   * Called when {@link ShowRangeEvent} is fired.

+   * 

+   * @param event the {@link ShowRangeEvent} that was fired

+   */

+  void onShowRange(ShowRangeEvent<V> event);

+}

diff --git a/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java b/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java
index 52376e8..5a769dc 100644
--- a/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java
+++ b/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java
@@ -35,12 +35,10 @@
    * manager.If no such handlers exist, this method will do nothing.

    * 

    * @param <I> the old value type

-   * @param <S> The event source

    * @param source the source of the handlers

    * @param value the value

    */

-  public static <I, S extends HasValueChangeHandlers<I> & HasHandlers> void fire(

-      S source, I value) {

+  public static <I> void fire(HasValueChangeHandlers<I> source, I value) {

     if (TYPE != null) {

       HandlerManager handlers = source.getHandlers();

       if (handlers != null && handlers.isEventHandled(TYPE)) {

@@ -61,13 +59,11 @@
    * @param oldValue the oldValue, may be null

    * @param newValue the newValue, may be null

    */

-  public static <I, S extends HasValueChangeHandlers<I> & HasHandlers> void fireIfNotEqual(

-      S source, I oldValue, I newValue) {

-    if (TYPE != null) {

-      if (oldValue != newValue

-          && (oldValue == null || !oldValue.equals(newValue))) {

-        fire(source, newValue);

-      }

+  public static <I> void fireIfNotEqual(HasValueChangeHandlers<I> source,

+      I oldValue, I newValue) {

+    if (shouldFire(source, oldValue, newValue)) {

+      ValueChangeEvent<I> event = new ValueChangeEvent<I>(newValue);

+      source.getHandlers().fireEvent(event);

     }

   }

 

@@ -83,10 +79,27 @@
     return TYPE;

   }

 

+  /**

+   * Convenience method to allow subtypes to know when they should fire a value

+   * change event in a null-safe manner.

+   * 

+   * @param <I> value type

+   * @param source the source

+   * @param oldValue the old value

+   * @param newValue the new value

+   * @return whether the event should be fired

+   */

+  protected static <I> boolean shouldFire(HasValueChangeHandlers<I> source,

+      I oldValue, I newValue) {

+    return TYPE != null && source.getHandlers() != null && oldValue != newValue

+        && (oldValue == null || !oldValue.equals(newValue));

+  }

+

   private final I value;

 

   /**

    * Creates a value change event.

+   * 

    * @param value the value

    */

   protected ValueChangeEvent(I value) {

diff --git a/user/src/com/google/gwt/user/User.gwt.xml b/user/src/com/google/gwt/user/User.gwt.xml
index 17de395..70216b7 100644
--- a/user/src/com/google/gwt/user/User.gwt.xml
+++ b/user/src/com/google/gwt/user/User.gwt.xml
@@ -40,7 +40,7 @@
    <inherits name="com.google.gwt.user.Window" />
    <inherits name="com.google.gwt.user.Tree"/>
    <inherits name="com.google.gwt.user.Hyperlink"/>
-    
+   <inherits name="com.google.gwt.user.datepicker.DatePicker"/>
     <super-source path="translatable"/>
     <source path="client"/>
     
diff --git a/user/src/com/google/gwt/user/client/ui/PopupPanel.java b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
index 417134d..2792e80 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
@@ -272,6 +272,8 @@
   private String desiredWidth;
 
   private boolean isAnimationEnabled = false;
+  
+  private Element autoHidePartner;
 
   /**
    * The {@link ResizeAnimation} used to open and close the {@link PopupPanel}s.
@@ -454,6 +456,7 @@
     return modal;
   }
 
+  @SuppressWarnings("deprecation")
   public boolean onEventPreview(Event event) {
     Element target = DOM.eventGetTarget(event);
 
@@ -485,7 +488,7 @@
           return true;
         }
 
-        if (!eventTargetsPopup && autoHide) {
+        if (!eventTargetsPopup && shouldAutoHide(event)) {
           hide(true);
           return true;
         }
@@ -503,7 +506,8 @@
         // If it's an outside click and auto-hide is enabled:
         // hide the popup and _don't_ eat the event. ONMOUSEDOWN is used to
         // prevent problems with showing a popup in response to a mousedown.
-        if (!eventTargetsPopup && autoHide && (type == Event.ONMOUSEDOWN)) {
+        if (!eventTargetsPopup && shouldAutoHide(event)
+            && (type == Event.ONMOUSEDOWN)) {
           hide(true);
           return true;
         }
@@ -581,6 +585,15 @@
   }
 
   /**
+   * If the auto hide partner is non null, its mouse events will 
+   * not hide a panel set to autohide.
+   * @param element new auto hide partner
+   */
+  public void setAutoHidePartner(Element element) {
+    this.autoHidePartner = element;
+  }
+
+  /**
    * Sets the height of the panel's child widget. If the panel's child widget
    * has not been set, the height passed in will be cached and used to set the
    * height immediately after the child widget is set.
@@ -613,7 +626,7 @@
   public void setModal(boolean modal) {
     this.modal = modal;
   }
-
+  
   /**
    * Sets the popup's position relative to the browser's client area. The
    * popup's position may be set before calling {@link #show()}.
@@ -728,6 +741,25 @@
     resizeAnimation.setState(true);
   }
 
+  /**
+   * Normally, the popup is positioned directly below the relative target, with
+   * its left edge aligned with the left edge of the target. Depending on the
+   * width and height of the popup and the distance from the target to the
+   * bottom and right edges of the window, the popup may be displayed directly
+   * above the target, and/or its right edge may be aligned with the right edge
+   * of the target.
+   * 
+   * @param target the target to show the popup below
+   */
+  public final void showRelativeTo(final UIObject target) {
+    // Set the position of the popup right before it is shown.
+    setPopupPositionAndShow(new PositionCallback() {
+      public void setPosition(int offsetWidth, int offsetHeight) {
+        position(target, offsetWidth, offsetHeight);
+      }
+    });
+  }
+
   @Override
   protected Element getContainerElement() {
     return impl.getContainerElement(DOM.getFirstChild(super.getContainerElement()));
@@ -801,4 +833,144 @@
       elt.blur();
     }
   }-*/;
+
+  private boolean eventInPartner(Event event) {
+    return autoHidePartner != null
+      && autoHidePartner.isOrHasChild(event.getTarget());
+  }
+
+  /**
+   * Positions the popup, called after the offset width and height of the popup are known.
+   * 
+   * @param relativeObject the ui object to position relative to
+   * @param offsetWidth the drop down's offset width
+   * @param offsetHeight the drop down's offset height
+   */
+  private void position(final UIObject relativeObject, int offsetWidth,
+      int offsetHeight) {
+    // Calculate left position for the popup. The computation for
+    // the left position is bidi-sensitive.
+
+    int textBoxOffsetWidth = relativeObject.getOffsetWidth();
+
+    // Compute the difference between the popup's width and the
+    // textbox's width
+    int offsetWidthDiff = offsetWidth - textBoxOffsetWidth;
+
+    int left;
+
+    if (LocaleInfo.getCurrentLocale().isRTL()) { // RTL case
+
+      int textBoxAbsoluteLeft = relativeObject.getAbsoluteLeft();
+
+      // Right-align the popup. Note that this computation is
+      // valid in the case where offsetWidthDiff is negative.
+      left = textBoxAbsoluteLeft - offsetWidthDiff;
+
+      // If the suggestion popup is not as wide as the text box, always
+      // align to the right edge of the text box. Otherwise, figure out whether
+      // to right-align or left-align the popup.
+      if (offsetWidthDiff > 0) {
+
+        // Make sure scrolling is taken into account, since
+        // box.getAbsoluteLeft() takes scrolling into account.
+        int windowRight = Window.getClientWidth() + Window.getScrollLeft();
+        int windowLeft = Window.getScrollLeft();
+
+        // Compute the left value for the right edge of the textbox
+        int textBoxLeftValForRightEdge = textBoxAbsoluteLeft
+            + textBoxOffsetWidth;
+
+        // Distance from the right edge of the text box to the right edge
+        // of the window
+        int distanceToWindowRight = windowRight - textBoxLeftValForRightEdge;
+
+        // Distance from the right edge of the text box to the left edge of the
+        // window
+        int distanceFromWindowLeft = textBoxLeftValForRightEdge - windowLeft;
+
+        // If there is not enough space for the overflow of the popup's
+        // width to the right of the text box and there IS enough space for the
+        // overflow to the right of the text box, then left-align the popup.
+        // However, if there is not enough space on either side, stick with
+        // right-alignment.
+        if (distanceFromWindowLeft < offsetWidth
+            && distanceToWindowRight >= offsetWidthDiff) {
+          // Align with the left edge of the text box.
+          left = textBoxAbsoluteLeft;
+        }
+      }
+    } else { // LTR case
+
+      // Left-align the popup.
+      left = relativeObject.getAbsoluteLeft();
+
+      // If the suggestion popup is not as wide as the text box, always align to
+      // the left edge of the text box. Otherwise, figure out whether to
+      // left-align or right-align the popup.
+      if (offsetWidthDiff > 0) {
+        // Make sure scrolling is taken into account, since
+        // box.getAbsoluteLeft() takes scrolling into account.
+        int windowRight = Window.getClientWidth() + Window.getScrollLeft();
+        int windowLeft = Window.getScrollLeft();
+
+        // Distance from the left edge of the text box to the right edge
+        // of the window
+        int distanceToWindowRight = windowRight - left;
+
+        // Distance from the left edge of the text box to the left edge of the
+        // window
+        int distanceFromWindowLeft = left - windowLeft;
+
+        // If there is not enough space for the overflow of the popup's
+        // width to the right of hte text box, and there IS enough space for the
+        // overflow to the left of the text box, then right-align the popup.
+        // However, if there is not enough space on either side, then stick with
+        // left-alignment.
+        if (distanceToWindowRight < offsetWidth
+            && distanceFromWindowLeft >= offsetWidthDiff) {
+          // Align with the right edge of the text box.
+          left -= offsetWidthDiff;
+        }
+      }
+    }
+
+    // Calculate top position for the popup
+
+    int top = relativeObject.getAbsoluteTop();
+
+    // Make sure scrolling is taken into account, since
+    // box.getAbsoluteTop() takes scrolling into account.
+    int windowTop = Window.getScrollTop();
+    int windowBottom = Window.getScrollTop() + Window.getClientHeight();
+
+    // Distance from the top edge of the window to the top edge of the
+    // text box
+    int distanceFromWindowTop = top - windowTop;
+
+    // Distance from the bottom edge of the window to the bottom edge of
+    // the text box
+    int distanceToWindowBottom = windowBottom
+        - (top + relativeObject.getOffsetHeight());
+
+    // If there is not enough space for the popup's height below the text
+    // box and there IS enough space for the popup's height above the text
+    // box, then then position the popup above the text box. However, if there
+    // is not enough space on either side, then stick with displaying the
+    // popup below the text box.
+    if (distanceToWindowBottom < offsetHeight
+        && distanceFromWindowTop >= offsetHeight) {
+      top -= offsetHeight;
+    } else {
+      // Position above the text box
+      top += relativeObject.getOffsetHeight();
+    }
+    setPopupPosition(left, top);
+  }
+  
+  private boolean shouldAutoHide(Event event) {
+    boolean shouldAutoHide = autoHide && !eventInPartner(event);
+    return shouldAutoHide;
+  }
+
 }
diff --git a/user/src/com/google/gwt/user/datepicker/DatePicker.gwt.xml b/user/src/com/google/gwt/user/datepicker/DatePicker.gwt.xml
new file mode 100644
index 0000000..d8acc9d
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/DatePicker.gwt.xml
@@ -0,0 +1,3 @@
+<module>  

+</module>

+

diff --git a/user/src/com/google/gwt/user/datepicker/client/CalendarModel.java b/user/src/com/google/gwt/user/datepicker/client/CalendarModel.java
new file mode 100644
index 0000000..d38dd0b
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/CalendarModel.java
@@ -0,0 +1,201 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import com.google.gwt.i18n.client.DateTimeFormat;

+

+import java.util.Date;

+

+/**

+ * Model used to get calendar information for {@link DatePicker} and its

+ * subclasses.

+ */

+@SuppressWarnings(/* Required to use Date API in gwt */{"deprecation"})

+public class CalendarModel {

+

+  /**

+   * The number of weeks normally displayed in a month.

+   */

+  public static final int WEEKS_IN_MONTH = 6;

+

+  /**

+   * Number of days normally displayed in a week.

+   */

+  public static final int DAYS_IN_WEEK = 7;

+

+  private static final String[] dayOfWeekNames = new String[7];

+

+  private static final DateTimeFormat dayOfMonthFormatter = DateTimeFormat.getFormat("d");

+

+  private static final DateTimeFormat dayOfWeekFormatter = DateTimeFormat.getFormat("ccccc");

+

+  private static final DateTimeFormat monthAndYearFormatter = DateTimeFormat.getFormat("MMM yyyy");

+

+  private static String[] dayOfMonthNames = new String[32];

+

+  private final Date currentMonth;

+

+  /**

+   * Constructor.

+   */

+  public CalendarModel() {

+    currentMonth = new Date();

+

+    CalendarUtil.setToFirstDayOfMonth(currentMonth);

+

+    // Finding day of week names

+    Date date = new Date();

+    for (int i = 1; i <= 7; i++) {

+      date.setDate(i);

+      int dayOfWeek = date.getDay();

+      dayOfWeekNames[dayOfWeek] = getDayOfWeekFormatter().format(date);

+    }

+

+    // Finding day of month names

+    date.setMonth(0);

+

+    for (int i = 1; i < 32; ++i) {

+      date.setDate(i);

+      dayOfMonthNames[i] = getDayOfMonthFormatter().format(date);

+    }

+  }

+

+  /**

+   * Formats the current specified month. For example "Sep".

+   * 

+   * @return the formatted month

+   */

+  public String formatCurrentMonth() {

+    return getMonthAndYearFormatter().format(currentMonth);

+  }

+

+  /**

+   * Formats a date's day of month. For example "1".

+   * 

+   * @param date the date

+   * @return the formated day of month

+   */

+  public String formatDayOfMonth(Date date) {

+    return dayOfMonthNames[date.getDate()];

+  }

+

+  /**

+   * Format a day in the week. So, for example "Monday".

+   * 

+   * @param dayInWeek the day in week to format

+   * @return the formatted day in week

+   */

+  public String formatDayOfWeek(int dayInWeek) {

+    return dayOfWeekNames[dayInWeek];

+  }

+

+  /**

+   * Gets the first day of the first week in the currently specified month.

+   * 

+   * @return the first day

+   */

+  public Date getCurrentFirstDayOfFirstWeek() {

+    int wkDayOfMonth1st = currentMonth.getDay();

+    int start = CalendarUtil.getStartingDayOfWeek();

+    if (wkDayOfMonth1st == start) {

+      // always return a copy to allow SimpleCalendarView to adjust first

+      // display date

+      return new Date(currentMonth.getTime());

+    } else {

+      Date d = new Date(currentMonth.getTime());

+      int offset = wkDayOfMonth1st - start > 0 ? wkDayOfMonth1st - start

+          : DAYS_IN_WEEK - (start - wkDayOfMonth1st);

+      CalendarUtil.addDaysToDate(d, -offset);

+      return d;

+    }

+  }

+

+  /**

+   * Gets the date representation of the currently specified month. Used to

+   * access both the month and year information.

+   * 

+   * @return the month and year

+   */

+  public Date getCurrentMonth() {

+    return currentMonth;

+  }

+

+  /**

+   * Is a date in the currently specified month?

+   * 

+   * @param date the date

+   * @return date

+   */

+  public boolean isInCurrentMonth(Date date) {

+    return currentMonth.getMonth() == date.getMonth();

+  }

+

+  /**

+   * Sets the currently specified date.

+   * 

+   * @param currentDate the currently specified date

+   */

+  public void setCurrentMonth(Date currentDate) {

+    this.currentMonth.setYear(currentDate.getYear());

+    this.currentMonth.setMonth(currentDate.getMonth());

+  }

+

+  /**

+   * Shifts the currently specified date by the given number of months. The day

+   * of the month will be pinned to the original value as far as possible.

+   * 

+   * @param deltaMonths - number of months to be added to the current date

+   */

+  public void shiftCurrentMonth(int deltaMonths) {

+    CalendarUtil.addMonthsToDate(currentMonth, deltaMonths);

+    refresh();

+  }

+

+  /**

+   * Gets the date of month formatter.

+   * 

+   * @return the day of month formatter

+   */

+  protected DateTimeFormat getDayOfMonthFormatter() {

+    return dayOfMonthFormatter;

+  }

+

+  /**

+   * Gets the day of week formatter.

+   * 

+   * @return the day of week formatter

+   */

+  protected DateTimeFormat getDayOfWeekFormatter() {

+    return dayOfWeekFormatter;

+  }

+

+  /**

+   * Gets the month and year formatter.

+   * 

+   * @return the month and year formatter

+   */

+  protected DateTimeFormat getMonthAndYearFormatter() {

+    return monthAndYearFormatter;

+  }

+

+  /**

+   * Refresh the current model as needed.

+   */

+  protected void refresh() {

+  }

+

+}

diff --git a/user/src/com/google/gwt/user/datepicker/client/CalendarUtil.java b/user/src/com/google/gwt/user/datepicker/client/CalendarUtil.java
new file mode 100644
index 0000000..0df0427
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/CalendarUtil.java
@@ -0,0 +1,168 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import com.google.gwt.core.client.GWT;

+import com.google.gwt.i18n.client.constants.DateTimeConstants;

+

+import java.util.Date;

+

+/**

+ * Useful utilities for creating views of a calendar.

+ */

+public class CalendarUtil {

+

+  static DateTimeConstants intlConstants;

+

+  private static int firstDayOfWeekend;

+

+  private static int lastDayOfWeekend;

+  private static int startingDay;

+

+  static {

+    if (GWT.isClient()) {

+      intlConstants = (DateTimeConstants) GWT.create(DateTimeConstants.class);

+      // Finding the start and end of weekend

+      firstDayOfWeekend = Integer.parseInt(intlConstants.weekendRange()[0]) - 1;

+      lastDayOfWeekend = Integer.parseInt(intlConstants.weekendRange()[1]) - 1;

+      startingDay = Integer.parseInt(CalendarUtil.intlConstants.firstDayOfTheWeek()) - 1;

+    }

+  }

+

+  /**

+   * Adds the given number of days to a date.

+   * 

+   * @param date the date

+   * @param days number of days

+   */

+  public static void addDaysToDate(Date date, int days) {

+    date.setDate(date.getDate() + days);

+  }

+

+  /**

+   * Adds the given number of months to a date.

+   * 

+   * @param date the date

+   * @param months number of months

+   */

+  public static void addMonthsToDate(Date date, int months) {

+    if (months != 0) {

+      int month = date.getMonth();

+      int year = date.getYear();

+

+      int resultMonthCount = year * 12 + month + months;

+      int resultYear = resultMonthCount / 12;

+      int resultMonth = resultMonthCount - resultYear * 12;

+

+      date.setMonth(resultMonth);

+      date.setYear(resultYear);

+    }

+  }

+

+  /**

+   * Copies a date.

+   * 

+   * @param date the date

+   * @return the copy

+   */

+  public static Date copyDate(Date date) {

+    if (date == null) {

+      return null;

+    }

+    Date newDate = new Date();

+    newDate.setTime(date.getTime());

+    return newDate;

+  }

+

+  /**

+   * Returns the number of days between the two dates. Time is ignored.

+   * 

+   * @param start starting date

+   * @param finish ending date

+   * @return the different

+   */

+  public static int getDaysBetween(Date start, Date finish) {

+    if (hasTime(start)) {

+      start = copyDate(start);

+      resetTime(start);

+    }

+

+    if (hasTime(finish)) {

+      finish = copyDate(finish);

+      resetTime(finish);

+    }

+

+    long aTime = start.getTime();

+    long bTime = finish.getTime();

+

+    long adjust = 60 * 60 * 1000;

+    adjust = (bTime > aTime) ? adjust : -adjust;

+

+    return (int) ((bTime - aTime + adjust) / (24 * 60 * 60 * 1000));

+  }

+

+  /**

+   * Returns the day of the week on which week starts in the current locale. The

+   * range between 0 for Sunday and 6 for Saturday.

+   * 

+   * @return the day of the week

+   */

+  public static int getStartingDayOfWeek() {

+    return startingDay;

+  }

+

+  /**

+   * Sets a date object to be at the beginning of the month and no time

+   * specified.

+   * 

+   * @param date the date

+   */

+  public static void setToFirstDayOfMonth(Date date) {

+    resetTime(date);

+    date.setDate(1);

+  }

+

+  static boolean hasTime(Date start) {

+    return start.getHours() != 0 || start.getMinutes() != 0

+        || start.getSeconds() != 0;

+  }

+

+  /**

+   * Is a day in the week a weekend?

+   * 

+   * @param dayOfWeek day of week

+   * @return is the day of week a weekend?

+   */

+  static boolean isWeekend(int dayOfWeek) {

+    return dayOfWeek == firstDayOfWeekend || dayOfWeek == lastDayOfWeekend;

+  }

+

+  /**

+   * Resets the date to have no time modifiers.

+   * 

+   * @param date the date

+   */

+  private static void resetTime(Date date) {

+    long msec = date.getTime();

+    msec = (msec / 1000) * 1000;

+    date.setTime(msec);

+

+    date.setHours(0);

+    date.setMinutes(0);

+    date.setSeconds(0);

+  }

+}

diff --git a/user/src/com/google/gwt/user/datepicker/client/CalendarView.java b/user/src/com/google/gwt/user/datepicker/client/CalendarView.java
new file mode 100644
index 0000000..adaa19a
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/CalendarView.java
@@ -0,0 +1,91 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import java.util.Date;

+

+/**

+ * The CalendarView is a calendar grid that represents the current view of a

+ * {@link DatePicker}. Note, the calendar view only deals with the currently

+ * visible dates and all state is flushed when the calendar view is refreshed.

+ * 

+ */

+public abstract class CalendarView extends DatePickerComponent {

+

+  /**

+   * Constructor.

+   */

+  public CalendarView() {

+  }

+

+  /**

+   * Adds a style name to the cell of the supplied date. This style is only set

+   * until the next time the {@link CalendarView} is refreshed.

+   * 

+   * @param styleName style name to add

+   * @param date date that will have the supplied style added

+   */

+  public abstract void addStyleToDate(String styleName, Date date);

+

+  /**

+   * Returns the first date that is currently shown by the calendar.

+   * 

+   * @return the first date.

+   */

+  public abstract Date getFirstDate();

+

+  /**

+   * Returns the last date that is currently shown by the calendar.

+   * 

+   * @return the last date.

+   */

+  public abstract Date getLastDate();

+

+  /**

+   * Is the cell representing the given date enabled?

+   * 

+   * @param date the date

+   * @return is the date enabled

+   */

+  public abstract boolean isDateEnabled(Date date);

+

+  /**

+   * Removes a visible style name from the cell of the supplied date.

+   * 

+   * @param styleName style name to remove

+   * @param date date that will have the supplied style added

+   */

+  public abstract void removeStyleFromDate(String styleName, Date date);

+

+  /**

+   * Enables or Disables a particular date. by default all valid dates are

+   * enabled after a rendering event. Disabled dates cannot be selected.

+   * 

+   * @param enabled true for enabled, false for disabled

+   * @param date date to enable or disable

+   */

+  public abstract void setEnabledOnDate(boolean enabled, Date date);

+

+  /**

+   * Allows the calendar view to update the date picker's highlighted date.

+   * 

+   * @param date the highlighted date

+   */

+  protected final void setHighlightedDate(Date date) {

+    getDatePicker().setHighlightedDate(date);

+  }

+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/datepicker/client/CellGridImpl.java b/user/src/com/google/gwt/user/datepicker/client/CellGridImpl.java
new file mode 100644
index 0000000..7530165
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/CellGridImpl.java
@@ -0,0 +1,272 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import com.google.gwt.dom.client.Element;

+import com.google.gwt.event.dom.client.KeyDownEvent;

+import com.google.gwt.event.dom.client.KeyCodes;

+import com.google.gwt.user.client.DOM;

+import com.google.gwt.user.client.Event;

+import com.google.gwt.user.client.ui.Grid;

+import com.google.gwt.user.client.ui.UIObject;

+

+import java.util.ArrayList;

+import java.util.Iterator;

+

+/**

+ * Highlighting, selectable cell grid. Used to help construct the default

+ * calendar view.

+ * 

+ * @param <V> type of value in grid.

+ */

+@SuppressWarnings("unchecked")

+abstract class CellGridImpl<V> extends Grid {

+

+  /**

+   * Cell type.

+   */

+  abstract class Cell extends UIObject {

+    private boolean enabled = true;

+    private V value;

+    private int index;

+

+    /**

+     * Create a cell grid.

+     * 

+     * @param elem the wrapped element

+     * @param value the value

+     */

+    public Cell(Element elem, V value) {

+      this.value = value;

+      Cell current = this;

+      index = cellList.size();

+      cellList.add(current);

+

+      setElement(elem);

+      elementToCell.put(current);

+    }

+

+    public V getValue() {

+      return value;

+    }

+

+    public boolean isEnabled() {

+      return enabled;

+    }

+

+    public boolean isHighlighted() {

+      return this == highlightedCell;

+    }

+

+    public boolean isSelected() {

+      return selectedCell == this;

+    }

+

+    public final void setEnabled(boolean enabled) {

+      this.enabled = enabled;

+      onEnabled(enabled);

+    }

+

+    public void verticalNavigation(int keyCode) {

+      switch (keyCode) {

+        case KeyCodes.KEY_UP:

+          setHighlighted(previousItem());

+          break;

+        case KeyCodes.KEY_DOWN:

+          setHighlighted(nextItem());

+          break;

+        case KeyCodes.KEY_ESCAPE:

+          // Figure out new event for this.

+          break;

+        case KeyCodes.KEY_ENTER:

+          setSelected(this);

+          break;

+      }

+    }

+

+    protected Cell nextItem() {

+      if (index == getLastIndex()) {

+        return cellList.get(0);

+      } else {

+        return cellList.get(index + 1);

+      }

+    }

+

+    protected void onEnabled(boolean enabled) {

+      updateStyle();

+    }

+

+    protected void onHighlighted(boolean highlighted) {

+      updateStyle();

+    }

+

+    protected void onSelected(boolean selected) {

+      updateStyle();

+    }

+

+    protected Cell previousItem() {

+      if (index != 0) {

+        return cellList.get(index - 1);

+      } else {

+        return cellList.get(getLastIndex());

+      }

+    }

+

+    protected abstract void updateStyle();

+

+    private int getLastIndex() {

+      return cellList.size() - 1;

+    }

+  }

+

+  private Cell highlightedCell;

+

+  private Cell selectedCell;

+  private ElementMapper<Cell> elementToCell = new ElementMapper<Cell>();

+  private ArrayList<Cell> cellList = new ArrayList<Cell>();

+

+  protected CellGridImpl() {

+    setCellPadding(0);

+    setCellSpacing(0);

+    setBorderWidth(0);

+    sinkEvents(Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT);

+  }

+

+  public Cell getCell(Element element) {

+    return elementToCell.get((com.google.gwt.user.client.Element) element);

+  }

+

+  public Cell getCell(Event e) {

+    // Find out which cell was actually clicked.

+    Element td = getEventTargetCell(e);

+    return td != null

+        ? elementToCell.get((com.google.gwt.user.client.Element) td) : null;

+  }

+

+  public Cell getCell(int i) {

+    return cellList.get(i);

+  }

+

+  public Iterator getCells() {

+    return cellList.iterator();

+  }

+

+  public Cell getHighlightedCell() {

+    return highlightedCell;

+  }

+

+  public int getNumCells() {

+    return cellList.size();

+  }

+

+  public Cell getSelectedCell() {

+    return selectedCell;

+  }

+

+  public V getSelectedValue() {

+    return getValue(selectedCell);

+  }

+

+  public V getValue(Cell cell) {

+    return (cell == null ? null : cell.getValue());

+  }

+

+  @Override

+  public void onBrowserEvent(Event event) {

+    switch (DOM.eventGetType(event)) {

+      case Event.ONCLICK: {

+        Cell cell = getCell(event);

+        if (isActive(cell)) {

+          setSelected(cell);

+        }

+        break;

+      }

+      case Event.ONMOUSEOUT: {

+        Element e = DOM.eventGetFromElement(event);

+        if (e != null) {

+          Cell cell = elementToCell.get((com.google.gwt.user.client.Element) e);

+          if (cell == highlightedCell) {

+            setHighlighted(null);

+          }

+        }

+        break;

+      }

+      case Event.ONMOUSEOVER: {

+        Element e = DOM.eventGetToElement(event);

+        if (e != null) {

+          Cell cell = elementToCell.get((com.google.gwt.user.client.Element) e);

+          if (isActive(cell)) {

+            setHighlighted(cell);

+          }

+        }

+        break;

+      }

+    }

+  }

+

+  @Override

+  public void onUnload() {

+    setHighlighted(null);

+  }

+

+  public final void setHighlighted(Cell nextHighlighted) {

+    if (nextHighlighted == highlightedCell) {

+      return;

+    }

+    Cell oldHighlighted = highlightedCell;

+    highlightedCell = nextHighlighted;

+    if (oldHighlighted != null) {

+      oldHighlighted.onHighlighted(false);

+    }

+    if (highlightedCell != null) {

+      highlightedCell.onHighlighted(true);

+    }

+  }

+

+  public final void setSelected(Cell cell) {

+    Cell last = getSelectedCell();

+    selectedCell = cell;

+

+    if (last != null) {

+      last.onSelected(false);

+    }

+    if (selectedCell != null) {

+      selectedCell.onSelected(true);

+    }

+    onSelected(last, selectedCell);

+  }

+

+  protected void onKeyDown(Cell lastHighlighted, KeyDownEvent event) {

+    if (event.isAnyModifierKeyDown()) {

+      return;

+    }

+    int keyCode = event.getNativeKeyCode();

+    if (lastHighlighted == null) {

+      if (keyCode == KeyCodes.KEY_DOWN && cellList.size() > 0) {

+        setHighlighted(cellList.get(0));

+      }

+    } else {

+      lastHighlighted.verticalNavigation(keyCode);

+    }

+  }

+

+  protected abstract void onSelected(Cell lastSelected, Cell cell);

+

+  private boolean isActive(Cell cell) {

+    return cell != null && cell.isEnabled();

+  }

+}

diff --git a/user/src/com/google/gwt/user/datepicker/client/DateBox.java b/user/src/com/google/gwt/user/datepicker/client/DateBox.java
new file mode 100644
index 0000000..6bc18b9
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/DateBox.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2008 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.user.datepicker.client;
+
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HasValue;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.TextBox;
+
+import java.util.Date;
+
+/**
+ * A text box that shows a {@link DatePicker} when the user focuses on it.
+ * 
+ * <h3>CSS Style Rules</h3>
+ * 
+ * <ul class="css">
+ * 
+ * <li>.gwt-DateBox { }</li>
+ * 
+ * <li>.dateBoxPopup { Applied to the popup around the DatePicker }</li>
+ * 
+ * </ul>
+ * 
+ * <p>
+ * <h3>Example</h3>
+ * {@example com.google.gwt.examples.DateBoxExample}
+ * </p>
+ */
+public class DateBox extends Composite implements HasValue<Date> {
+
+  /**
+   * Implemented by a delegate to report errors parsing date values from the
+   * user's input.
+   */
+  public interface InvalidDateReporter {
+    /**
+     * Called when a valid date has been parsed, or the datebox has been
+     * cleared.
+     */
+    void clearError();
+
+    /**
+     * Given an unparseable string, explain the situation to the user.
+     * 
+     * @param input what the user typed
+     */
+    void reportError(String input);
+  }
+
+  private class DateBoxHandler implements ValueChangeHandler<Date>,
+      FocusHandler, BlurHandler, ClickHandler, KeyDownHandler {
+
+    public void onBlur(BlurEvent event) {
+      if (!popup.isVisible()) {
+        updateDateFromTextBox();
+      }
+    }
+
+    public void onClick(ClickEvent event) {
+      showDatePicker();
+    }
+
+    public void onFocus(FocusEvent event) {
+      if (allowDPShow) {
+        showDatePicker();
+      }
+    }
+
+    public void onKeyDown(KeyDownEvent event) {
+      switch (event.getNativeKeyCode()) {
+        case KeyCodes.KEY_ENTER:
+        case KeyCodes.KEY_TAB:
+        case KeyCodes.KEY_ESCAPE:
+        case KeyCodes.KEY_UP:
+          updateDateFromTextBox();
+          hideDatePicker();
+          break;
+        case KeyCodes.KEY_DOWN:
+          showDatePicker();
+          break;
+      }
+    }
+
+    public void onValueChange(ValueChangeEvent<Date> event) {
+      setValue(event.getValue());
+      hideDatePicker();
+      preventDatePickerPopup();
+      box.setFocus(true);
+    }
+  }
+
+  /**
+   * Default style name.
+   */
+  public static final String DEFAULT_STYLENAME = "gwt-DateBox";
+
+  public static final InvalidDateReporter DEFAULT_INVALID_DATE_REPORTER = new InvalidDateReporter() {
+    public void clearError() {
+    }
+
+    public void reportError(String input) {
+    }
+  };
+  private static final DateTimeFormat DEFAULT_FORMATTER = DateTimeFormat.getMediumDateFormat();
+
+  private final PopupPanel popup;
+  private final TextBox box = new TextBox();
+  private final DatePicker picker;
+
+  private final InvalidDateReporter invalidDateReporter;
+  private DateTimeFormat dateFormatter = DEFAULT_FORMATTER;
+
+  private boolean allowDPShow = true;
+
+  /**
+   * Create a new date box with a new {@link DatePicker} and the
+   * {@link #DEFAULT_INVALID_DATE_REPORTER}, which does nothing.
+   */
+  public DateBox() {
+    this(new DatePicker(), DEFAULT_INVALID_DATE_REPORTER);
+  }
+
+  /**
+   * Create a new date box.
+   * 
+   * @param picker the picker to drop down from the date box
+   */
+  public DateBox(DatePicker picker, InvalidDateReporter invalidDateReporter) {
+    this.picker = picker;
+    this.invalidDateReporter = invalidDateReporter;
+    this.popup = new PopupPanel();
+    popup.setAutoHideEnabled(true);
+    popup.setAutoHidePartner(box.getElement());
+    popup.setWidget(picker);
+    popup.setStyleName("dateBoxPopup");
+    initWidget(box);
+    setStyleName(DEFAULT_STYLENAME);
+
+    DateBoxHandler handler = new DateBoxHandler();
+    picker.addValueChangeHandler(handler);
+    box.addFocusHandler(handler);
+    box.addBlurHandler(handler);
+    box.addClickHandler(handler);
+    box.addKeyDownHandler(handler);
+  }
+
+  public HandlerRegistration addValueChangeHandler(
+      ValueChangeHandler<Date> handler) {
+    return addHandler(handler, ValueChangeEvent.getType());
+  }
+
+  /**
+   * Gets the current cursor position in the date box.
+   * 
+   * @return the cursor position
+   * 
+   */
+  public int getCursorPos() {
+    return box.getCursorPos();
+  }
+
+  /**
+   * Gets the date picker.
+   * 
+   * @return the date picker
+   */
+  public DatePicker getDatePicker() {
+    return picker;
+  }
+
+  /**
+   * Gets the date box's position in the tab index.
+   * 
+   * @return the date box's tab index
+   */
+  public int getTabIndex() {
+    return box.getTabIndex();
+  }
+
+  /**
+   * Get text box.
+   * 
+   * @return the text box used to enter the formatted date
+   */
+  public TextBox getTextBox() {
+    return box;
+  }
+
+  /**
+   * Get the date displayed, or null if the text box is empty, or cannot be
+   * interpretted. The {@link InvalidDateReporter} may fire as a side effect of
+   * this call.
+   * 
+   * @return the Date
+   */
+  public Date getValue() {
+    return parseDate(true);
+  }
+
+  /**
+   * Hide the date picker.
+   */
+  public void hideDatePicker() {
+    popup.hide();
+  }
+
+  /**
+   * @return true if date picker is currently visible, false if not
+   */
+  public boolean isDatePickerVisible() {
+    return popup.isVisible();
+  }
+
+  /**
+   * Sets the date box's 'access key'. This key is used (in conjunction with a
+   * browser-specific modifier key) to automatically focus the widget.
+   * 
+   * @param key the date box's access key
+   */
+  public void setAccessKey(char key) {
+    box.setAccessKey(key);
+  }
+
+  /**
+   * Sets the date format to the given format. If date box is not empty,
+   * contents of date box will be replaced with current date in new format. If
+   * the date cannot be parsed, the current value will be preserved and the
+   * InvalidDateReporter notified as usual.
+   * 
+   * @param format format.
+   */
+  public void setDateFormat(DateTimeFormat format) {
+    if (format != dateFormatter) {
+      Date date = getValue();
+      dateFormatter = format;
+      setValue(date);
+    }
+  }
+
+  /**
+   * Sets whether the date box is enabled.
+   * 
+   * @param enabled is the box enabled
+   */
+  public void setEnabled(boolean enabled) {
+    box.setEnabled(enabled);
+  }
+
+  /**
+   * Explicitly focus/unfocus this widget. Only one widget can have focus at a
+   * time, and the widget that does will receive all keyboard events.
+   * 
+   * @param focused whether this widget should take focus or release it
+   */
+  public void setFocus(boolean focused) {
+    box.setFocus(focused);
+  }
+
+  /**
+   * Sets the date box's position in the tab index. If more than one widget has
+   * the same tab index, each such widget will receive focus in an arbitrary
+   * order. Setting the tab index to <code>-1</code> will cause this widget to
+   * be removed from the tab order.
+   * 
+   * @param index the date box's tab index
+   */
+  public void setTabIndex(int index) {
+    box.setTabIndex(index);
+  }
+
+  /**
+   * Set the date.
+   */
+  public void setValue(Date date) {
+    setValue(date, false);
+  }
+
+  public void setValue(Date date, boolean fireEvents) {
+    Date oldDate = getValue();
+
+    if (date == null) {
+      picker.setValue(null);
+      box.setText("");
+    } else {
+      picker.setValue(date, false);
+      picker.setCurrentMonth(date);
+      setDate(date);
+    }
+
+    invalidDateReporter.clearError();
+    if (fireEvents) {
+      DateChangeEvent.fireIfNotEqualDates(this, oldDate, date);
+    }
+  }
+
+  /**
+   * Parses the current date box's value and shows that date.
+   */
+  public void showDatePicker() {
+    Date current = parseDate(false);
+    if (current == null) {
+      current = new Date();
+    }
+    picker.setCurrentMonth(current);
+    popup.showRelativeTo(this);
+  }
+
+  private Date parseDate(boolean reportError) {
+    Date d = null;
+    String text = box.getText().trim();
+    if (!text.equals("")) {
+      try {
+        d = dateFormatter.parse(text);
+      } catch (IllegalArgumentException exception) {
+        if (reportError) {
+          invalidDateReporter.reportError(text);
+        }
+      }
+    }
+    return d;
+  }
+
+  private void preventDatePickerPopup() {
+    allowDPShow = false;
+    DeferredCommand.addCommand(new Command() {
+      public void execute() {
+        allowDPShow = true;
+      }
+    });
+  }
+
+  /**
+   * Does the actual work of setting the date. Performs no validation, fires no
+   * events.
+   */
+  private void setDate(Date value) {
+    box.setText(dateFormatter.format(value));
+  }
+
+  private void updateDateFromTextBox() {
+    Date parsedDate = parseDate(true);
+    if (parsedDate != null) {
+      setValue(parsedDate);
+    }
+  }
+}
diff --git a/user/src/com/google/gwt/user/datepicker/client/DateChangeEvent.java b/user/src/com/google/gwt/user/datepicker/client/DateChangeEvent.java
new file mode 100644
index 0000000..6c2affb
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/DateChangeEvent.java
@@ -0,0 +1,60 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import com.google.gwt.event.logical.shared.HasHandlers;

+import com.google.gwt.event.logical.shared.HasValueChangeHandlers;

+import com.google.gwt.event.logical.shared.ValueChangeEvent;

+

+import java.util.Date;

+

+/**

+ * Creates a new value every time a date is accessed.

+ */

+class DateChangeEvent extends ValueChangeEvent<Date> {

+

+  /**

+   * Fires value change event if the old value is not equal to the new value.

+   * Use this call rather than making the decision to short circuit yourself for

+   * safe handling of null.

+   * 

+   * @param <I> the old value type

+   * @param <S> The event source

+   * @param source the source of the handlers

+   * @param oldValue the oldValue, may be null

+   * @param newValue the newValue, may be null

+   */

+  public static <S extends HasValueChangeHandlers<Date> & HasHandlers> void fireIfNotEqualDates(

+      S source, Date oldValue, Date newValue) {

+    if (ValueChangeEvent.shouldFire(source, oldValue, newValue)) {

+      source.getHandlers().fireEvent(new DateChangeEvent(newValue));

+    }

+  }

+

+  /**

+   * Creates a new date value change event.

+   * 

+   * @param value the value

+   */

+  protected DateChangeEvent(Date value) {

+    super(value);

+  }

+

+  public Date getValue() {

+    return CalendarUtil.copyDate(super.getValue());

+  }

+}

diff --git a/user/src/com/google/gwt/user/datepicker/client/DatePicker.java b/user/src/com/google/gwt/user/datepicker/client/DatePicker.java
new file mode 100644
index 0000000..e6705a5
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/DatePicker.java
@@ -0,0 +1,652 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import com.google.gwt.event.logical.shared.HasHighlightHandlers;

+import com.google.gwt.event.logical.shared.HasShowRangeHandlers;

+import com.google.gwt.event.logical.shared.HighlightEvent;

+import com.google.gwt.event.logical.shared.HighlightHandler;

+import com.google.gwt.event.logical.shared.ShowRangeEvent;

+import com.google.gwt.event.logical.shared.ShowRangeHandler;

+import com.google.gwt.event.logical.shared.ValueChangeEvent;

+import com.google.gwt.event.logical.shared.ValueChangeHandler;

+import com.google.gwt.event.shared.HandlerRegistration;

+import com.google.gwt.user.client.ui.Composite;

+import com.google.gwt.user.client.ui.HasValue;

+import com.google.gwt.user.client.ui.VerticalPanel;

+

+import java.util.Date;

+import java.util.HashMap;

+import java.util.Map;

+

+/**

+ * Standard GWT date picker.

+ * 

+ * <h3>CSS Style Rules</h3>

+ * 

+ * <ul class="css">

+ * 

+ * <li>.gwt-DatePicker { }</li>

+ * 

+ * <li>.datePickerMonthSelector { the month selector widget }</li>

+ * 

+ * <li>.datePickerMonth { the month in the month selector widget } <li>

+ * 

+ * <li>.datePickerPreviousButton { the previous month button } <li>

+ * 

+ * <li>.datePickerNextButton { the next month button } <li>

+ * 

+ * <li>.datePickerDays { the portion of the picker that shows the days }</li>

+ * 

+ * <li>.datePickerWeekdayLabel { the label over weekdays }</li>

+ * 

+ * <li>.datePickerWeekendLabel { the label over weekends }</li>

+ * 

+ * <li>.datePickerDay { a single day }</li>

+ * 

+ * <li>.datePickerDayIsToday { today's date }</li>

+ * 

+ * <li>.datePickerDayIsWeekend { a weekend day }</li>

+ * 

+ * <li>.datePickerDayIsFiller { a day in another month }</li>

+ * 

+ * <li>.datePickerDayIsValue { the selected day }</li>

+ * 

+ * <li>.datePickerDayIsDisabled { a disabled day }</li>

+ * 

+ * <li>.datePickerDayIsHighlighted { the currently highlighted day }</li>

+ * 

+ * <li>.datePickerDayIsValueAndHighlighted { the highlighted day if it is also

+ * selected }</li>

+ * 

+ * </ul>

+ * 

+ * <p>

+ * <h3>Example</h3>

+ * {@example com.google.gwt.examples.DatePickerExample}

+ * </p>

+ */

+public class DatePicker extends Composite implements

+    HasHighlightHandlers<Date>, HasShowRangeHandlers<Date>, HasValue<Date> {

+

+  /**

+   * Convenience class to group css style names.

+   */

+  static class StandardCss {

+

+    static StandardCss DEFAULT = new StandardCss("gwt-DatePicker", "datePicker");

+

+    private String baseName;

+    private String widgetName;

+

+    public StandardCss(String widgetName, String baseName) {

+      this.widgetName = widgetName;

+      this.baseName = baseName;

+    }

+

+    public String datePicker() {

+      return getWidgetStyleName();

+    }

+

+    public String day() {

+      return wrap("Day");

+    }

+

+    public String day(String dayModifier) {

+      return day() + "Is" + dayModifier;

+    }

+

+    public String dayIsDisabled() {

+      return day("Disabled");

+    }

+

+    public String dayIsFiller() {

+      return day("Filler");

+    }

+

+    public String dayIsHighlighted() {

+      return day("Highlighted");

+    }

+

+    public String dayIsToday() {

+      return day("Today");

+    }

+

+    public String dayIsValue() {

+      return day("Value");

+    }

+

+    public String dayIsValueAndHighlighted() {

+      return dayIsValue() + "AndHighlighted";

+    }

+

+    public String dayIsWeekend() {

+      return day("Weekend");

+    }

+

+    public String days() {

+      return wrap("Days");

+    }

+

+    public String daysLabel() {

+      return wrap("DaysLabel");

+    }

+

+    public String getBaseStyleName() {

+      return baseName;

+    }

+

+    public String getWidgetStyleName() {

+      return widgetName;

+    }

+

+    public String month() {

+      return wrap("Month");

+    }

+

+    public String monthSelector() {

+      return wrap("MonthSelector");

+    }

+

+    public String nextButton() {

+      return wrap("NextButton");

+    }

+

+    public String previousButton() {

+      return wrap("PreviousButton");

+    }

+

+    public String weekdayLabel() {

+      return wrap("WeekdayLabel");

+    }

+

+    public String weekendLabel() {

+      return wrap("WeekendLabel");

+    }

+

+    /**

+     * Prepends the base name to the given style.

+     * 

+     * @param style style name

+     * @return style name

+     */

+    protected String wrap(String style) {

+      return baseName + style;

+    }

+  }

+

+  /**

+   * A date highlighted event that copied on read.

+   */

+  private class DateHighlightEvent extends HighlightEvent<Date> {

+    protected DateHighlightEvent(Date highlighted) {

+      super(highlighted);

+    }

+

+    @Override

+    public Date getHighlighted() {

+      return CalendarUtil.copyDate(super.getHighlighted());

+    }

+  }

+

+  private class DateStyler {

+    private Map<String, String> info = new HashMap<String, String>();

+

+    public String getStyleName(Date d) {

+      return info.get(genKey(d));

+    }

+

+    public void setStyleName(Date d, String styleName, boolean add) {

+      // Code is easier to maintain if surrounded by " ", and on all browsers

+      // this is a no-op.

+      styleName = " " + styleName + " ";

+      String key = genKey(d);

+      String current = info.get(key);

+

+      if (add) {

+        if (current == null) {

+          info.put(key, styleName);

+        } else if (current.indexOf(styleName) == -1) {

+          info.put(key, current + styleName);

+        }

+      } else {

+        if (current != null) {

+          String newValue = current.replaceAll(styleName, "");

+          if (newValue.trim().length() == 0) {

+            info.remove(key);

+          } else {

+            info.put(key, newValue);

+          }

+        }

+      }

+    }

+

+    @SuppressWarnings("deprecation")

+    private String genKey(Date d) {

+      return d.getYear() + "/" + d.getMonth() + "/" + d.getDate();

+    }

+  }

+  private final DateStyler styler = new DateStyler();

+  private final MonthSelector monthSelector;

+  private final CalendarView view;

+  private final CalendarModel model;

+  private Date value;

+  private Date highlighted;

+

+  private StandardCss css = StandardCss.DEFAULT;

+

+  /**

+   * Create a new date picker.

+   */

+  public DatePicker() {

+    this(new DefaultMonthSelector(), new DefaultCalendarView(),

+        new CalendarModel());

+  }

+

+  /**

+   * Creates a new date picker.

+   * 

+   * @param monthSelector the month selector

+   * @param view the view

+   * @param model the model

+   */

+

+  protected DatePicker(MonthSelector monthSelector, CalendarView view,

+      CalendarModel model) {

+

+    this.model = model;

+    this.monthSelector = monthSelector;

+    monthSelector.setDatePicker(this);

+    this.view = view;

+    view.setDatePicker(this);

+

+    view.setup();

+    monthSelector.setup();

+    this.setup();

+

+    setCurrentMonth(new Date());

+    addStyleToDates(css().dayIsToday(), new Date());

+  }

+  

+  public HandlerRegistration addHighlightHandler(HighlightHandler<Date> handler) {

+    return addHandler(handler, HighlightEvent.getType());

+  }

+  

+  public HandlerRegistration addShowRangeHandler(ShowRangeHandler<Date> handler) {

+    return addHandler(handler, ShowRangeEvent.getType());

+  }

+

+  /**

+   * Adds a show range handler and immediately activate the handler on the

+   * current view.

+   * 

+   * @param handler the handler

+   * @return the handler registration

+   */

+  public HandlerRegistration addShowRangeHandlerAndFire(

+      ShowRangeHandler<Date> handler) {

+    ShowRangeEvent<Date> event = new ShowRangeEvent<Date>(

+        getView().getFirstDate(), getView().getLastDate()) {

+    };

+    handler.onShowRange(event);

+    return addShowRangeHandler(handler);

+  }

+

+  /**

+   * Add a style name to the given dates. 

+   */

+  public void addStyleToDates(String styleName, Date date) {

+    styler.setStyleName(date, styleName, true);

+    if (isDateVisible(date)) {

+      getView().addStyleToDate(styleName, date);

+    }

+  }

+

+  /**

+   * Add a style name to the given dates. 

+   */

+  public void addStyleToDates(String styleName, Date date, Date... moreDates) {

+    addStyleToDates(styleName, date);

+    for (Date d : moreDates) {

+      addStyleToDates(styleName, d);

+    }

+  }

+

+  /**

+   * Add a style name to the given dates.

+   */

+  public void addStyleToDates(String styleName, Iterable<Date> dates) {

+    for (Date d : dates) {

+      addStyleToDates(styleName, d);

+    }

+  }

+

+  /**

+   * Adds the given style name to the specified dates, which must be visible. 

+   * This is only set until the next time the DatePicker is refreshed.

+   */

+  public void addTransientStyleToDates(String styleName, Date date) {

+    assert isDateVisible(date) : date + " must be visible";

+    getView().addStyleToDate(styleName, date);

+  }

+

+  /**

+   * Adds the given style name to the specified dates, which must be visible. 

+   * This is only set until the next time the DatePicker is refreshed.

+   */

+  public final void addTransientStyleToDates(String styleName, Date date,

+      Date... moreDates) {

+    addTransientStyleToDates(styleName, date);

+    for (Date d : moreDates) {

+      addTransientStyleToDates(styleName, d);

+    }

+  }

+

+  /**

+   * Adds the given style name to the specified dates, which must be visible. 

+   * This is only set until the next time the DatePicker is refreshed.

+   */

+  public final void addTransientStyleToDates(String styleName,

+      Iterable<Date> dates) {

+    for (Date d : dates) {

+      addTransientStyleToDates(styleName, d);

+    }

+  }

+

+  public HandlerRegistration addValueChangeHandler(

+      ValueChangeHandler<Date> handler) {

+    return addHandler(handler, ValueChangeEvent.getType());

+  }

+

+  /**

+   * Gets the current month the date picker is showing.

+   * 

+   * <p>

+   * A datepicker <b> may </b> show days not in the current month. It

+   * <b>must</b> show all days in the current month.

+   * </p>

+   * @return the current month

+   * 

+   */

+  public Date getCurrentMonth() {

+    return getModel().getCurrentMonth();

+  }

+

+  /**

+   * Returns the first shown date.

+   * 

+   * @return the first date.

+   */

+  // Final because the view should always control the value of the first date.

+  public final Date getFirstDate() {

+    return view.getFirstDate();

+  }

+

+  /**

+   * Gets the highlighted date (the one the mouse is hovering over), if any.

+   * 

+   * @return the highlighted date

+   */

+  public final Date getHighlightedDate() {

+    return CalendarUtil.copyDate(highlighted);

+  }

+

+  /**

+   * Returns the last shown date.

+   * 

+   * @return the last date.

+   */

+  // Final because the view should always control the value of the last date.

+  public final Date getLastDate() {

+    return view.getLastDate();

+  }

+

+  /**

+   * Gets the style associated with a date (does not include styles

+   * set via {@link #addTransientStyleToDates}).

+   * 

+   * @param date the date

+   * @return the styles associated with this date

+   */

+  public String getStyleOfDate(Date date) {

+    return styler.getStyleName(date);

+  }

+

+  /**

+   * Returns the selected date, or null if none is selected.

+   * 

+   * @return the selected date, or null

+   */

+  public final Date getValue() {

+    return CalendarUtil.copyDate(value);

+  }

+

+  /**

+   * Is the visible date enabled?

+   * 

+   * @param date the date, which must be visible

+   * @return is the date enabled?

+   */

+  public boolean isDateEnabled(Date date) {

+    assert isDateVisible(date) : date + " is not visible";

+    return getView().isDateEnabled(date);

+  }

+

+  /**

+   * Is the date currently shown in the date picker?

+   * 

+   * @param date

+   * @return is the date currently shown

+   */

+  public boolean isDateVisible(Date date) {

+    CalendarView r = getView();

+    Date first = r.getFirstDate();

+    Date last = r.getLastDate();

+    return (date != null && (first.equals(date) || last.equals(date) || (first.before(date) && last.after(date))));

+  }

+

+  /**

+   * Removes the styleName from the given dates (even if it is transient).

+   */

+  public void removeStyleFromDates(String styleName, Date date) {

+    styler.setStyleName(date, styleName, false);

+    if (isDateVisible(date)) {

+      getView().removeStyleFromDate(styleName, date);

+    }

+  }

+

+  /**

+   * Removes the styleName from the given dates (even if it is transient).

+   */

+  public void removeStyleFromDates(String styleName, Date date, Date... moreDates) {

+    removeStyleFromDates(styleName, date);

+    for (Date d : moreDates) {

+      removeStyleFromDates(styleName, d);

+    }

+  }

+

+  /**

+   * Removes the styleName from the given dates (even if it is transient).

+   */

+  public void removeStyleFromDates(String styleName, Iterable<Date> dates) {

+    for (Date d : dates) {

+      removeStyleFromDates(styleName, d);

+    }

+  }

+

+  /**

+   * Sets the date picker to show the given month, use {@link #getFirstDate()}

+   * and {@link #getLastDate()} to access the exact date range the date picker

+   * chose to display.

+   * <p>

+   * A datepicker <b> may </b> show days not in the current month. It

+   * <b>must</b> show all days in the current month.

+   * </p>

+   * 

+   * @param month the month to show

+   */

+  public void setCurrentMonth(Date month) {

+    getModel().setCurrentMonth(month);

+    refreshAll();

+  }

+

+  /**

+   * Sets the date picker style name.

+   */

+  @Override

+  public void setStyleName(String styleName) {

+    css = new StandardCss(styleName, "datePicker");

+    super.setStyleName(styleName);

+  }

+

+  /**

+   * Sets a visible date to be enabled or disabled. This is only set until the

+   * next time the DatePicker is refreshed.

+   */

+  public final void setTransientEnabledOnDates(boolean enabled, Date date) {

+    assert isDateVisible(date) : date + " must be visible";

+    getView().setEnabledOnDate(enabled, date);

+  }

+

+  /**

+   * Sets a visible date to be enabled or disabled. This is only set until the

+   * next time the DatePicker is refreshed.

+   */

+  public final void setTransientEnabledOnDates(boolean enabled,

+      Date date, Date... moreDates) {

+    setTransientEnabledOnDates(enabled, date);

+    for (Date d : moreDates) {

+      setTransientEnabledOnDates(enabled, d);

+    }

+  }

+

+  /**

+   * Sets a group of visible dates to be enabled or disabled. This is only set

+   * until the next time the DatePicker is refreshed.

+   */

+  public final void setTransientEnabledOnDates(boolean enabled,

+      Iterable<Date> dates) {

+    for (Date d : dates) {

+      setTransientEnabledOnDates(enabled, d);

+    }

+  }

+

+  /**

+   * Sets the {@link DatePicker}'s value.

+   * 

+   * @param newValue the new value

+   */

+  public final void setValue(Date newValue) {

+    setValue(newValue, false);

+  }

+

+  /**

+   * Sets the {@link DatePicker}'s value.

+   * 

+   * @param newValue the new value for this date picker

+   * @param fireEvents should events be fired.

+   */

+  public final void setValue(Date newValue, boolean fireEvents) {

+    Date oldValue = value;

+

+    if (oldValue != null) {

+      removeStyleFromDates(css().dayIsValue(), oldValue);

+    }

+

+    value = CalendarUtil.copyDate(newValue);

+    if (value != null) {

+      addStyleToDates(css().dayIsValue(), value);

+    }

+    if (fireEvents) {

+      DateChangeEvent.fireIfNotEqualDates(this, oldValue, newValue);

+    }

+  }

+

+  /**

+   * Gets the {@link CalendarModel} associated with this date picker.

+   * 

+   * @return the model

+   */

+  protected final CalendarModel getModel() {

+    return model;

+  }

+

+  /**

+   * Gets the {@link MonthSelector} associated with this date picker.

+   * 

+   * @return the month selector

+   */

+  protected final MonthSelector getMonthSelector() {

+    return monthSelector;

+  }

+

+  /**

+   * Gets the {@link CalendarView} associated with this date picker.

+   * 

+   * @return the view

+   */

+  protected final CalendarView getView() {

+    return view;

+  }

+

+  /**

+   * Refreshes all components of this date picker.

+   */

+  protected final void refreshAll() {

+    highlighted = null;

+    getModel().refresh();

+    getView().refresh();

+    getMonthSelector().refresh();

+    ShowRangeEvent.fire(this, getFirstDate(), getLastDate());

+  }

+

+  /**

+   * Sets up the date picker.

+   */

+  protected void setup() {

+    /*

+     * Use a table (VerticalPanel) to get shrink-to-fit behavior. Divs expand to

+     * fill the available width, so we'd need to give it a size.

+     */

+    VerticalPanel panel = new VerticalPanel();

+    initWidget(panel);

+    setStyleName(panel.getElement(), css.datePicker());

+    setStyleName(css().datePicker());

+    panel.add(this.getMonthSelector());

+    panel.add(this.getView());

+  }

+

+  /**

+   * Gets the css associated with this date picker for use by extended month and

+   * cell grids.

+   * 

+   * @return the css.

+   */

+  final StandardCss css() {

+    return css;

+  }

+

+  /**

+   * Sets the highlighted date.

+   * 

+   * @param highlighted highlighted date

+   */

+  void setHighlightedDate(Date highlighted) {

+    this.highlighted = highlighted;

+    fireEvent(new DateHighlightEvent(highlighted));

+  }

+}

diff --git a/user/src/com/google/gwt/user/datepicker/client/DatePickerComponent.java b/user/src/com/google/gwt/user/datepicker/client/DatePickerComponent.java
new file mode 100644
index 0000000..6250316
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/DatePickerComponent.java
@@ -0,0 +1,69 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import com.google.gwt.user.client.ui.Composite;

+

+/**

+ * Package protected class used to combine functionality for the

+ * {@link MonthSelector} and {@link CalendarView} components.

+ * 

+ */

+abstract class DatePickerComponent extends Composite {

+  private DatePicker datePicker;

+

+  public CalendarModel getModel() {

+    return datePicker.getModel();

+  }

+

+  protected void addMonths(int numMonths) {

+    getModel().shiftCurrentMonth(numMonths);

+    getDatePicker().refreshAll();

+  }

+

+  protected DatePicker getDatePicker() {

+    return datePicker;

+  }

+

+  /**

+   * Refresh the component. Usually called because the model's current date has

+   * changed. In general, only should be called by {@link DatePicker}. Use

+   * refreshAll() if you need to refresh all components.

+   */

+  protected abstract void refresh();

+

+  /**

+   * Refreshes the {@link DatePicker}, {@link CalendarView}, and

+   * {@link CalendarModel}.

+   */

+  protected void refreshAll() {

+    getDatePicker().refreshAll();

+  }

+

+  /**

+   * Set up the component.

+   */

+  protected abstract void setup();

+

+  DatePicker.StandardCss css() {

+    return datePicker.css();

+  }

+

+  void setDatePicker(DatePicker me) {

+    this.datePicker = me;

+  }

+}

diff --git a/user/src/com/google/gwt/user/datepicker/client/DefaultCalendarView.java b/user/src/com/google/gwt/user/datepicker/client/DefaultCalendarView.java
new file mode 100644
index 0000000..1f72e65
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/DefaultCalendarView.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2008 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.user.datepicker.client;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
+import com.google.gwt.user.datepicker.client.DefaultCalendarView.CellGrid.DateCell;
+
+import java.util.Date;
+
+/**
+ * Simple calendar view. Not extensible as we wish to evolve it freely over
+ * time.
+ */
+
+@SuppressWarnings(/* Date manipulation required */{"deprecation"})
+public final class DefaultCalendarView extends CalendarView {
+
+  /**
+   * Cell grid.
+   */
+  // Javac bug requires that date be fully specified here.
+  class CellGrid extends CellGridImpl<java.util.Date> {
+    /**
+     * A cell representing a date.
+     */
+    class DateCell extends Cell {
+      private String cellStyle;
+      private String dateStyle;
+
+      DateCell(Element td, boolean isWeekend) {
+        super(td, new Date());
+        cellStyle = css().day();
+        if (isWeekend) {
+          cellStyle += " " + css().dayIsWeekend();
+        }
+      }
+
+      @Override
+      public void addStyleName(String styleName) {
+        if (dateStyle.indexOf(" " + styleName + " ") == -1) {
+          dateStyle += styleName + " ";
+        }
+        updateStyle();
+      }
+
+      public boolean isFiller() {
+        return !getModel().isInCurrentMonth(getValue());
+      }
+
+      @Override
+      public void onHighlighted(boolean highlighted) {
+        setHighlightedDate(getValue());
+        updateStyle();
+      }
+
+      @Override
+      public void onSelected(boolean selected) {
+        if (selected) {
+          getDatePicker().setValue(getValue(), true);
+          if (isFiller()) {
+            getDatePicker().setCurrentMonth(getValue());
+          }
+        }
+        updateStyle();
+      }
+
+      @Override
+      public void removeStyleName(String styleName) {
+        dateStyle = dateStyle.replace(" " + styleName + " ", " ");
+        updateStyle();
+      }
+
+      public void update(Date current) {
+        setEnabled(true);
+        getValue().setTime(current.getTime());
+        String value = getModel().formatDayOfMonth(getValue());
+        setText(value);
+        dateStyle = cellStyle;
+        if (isFiller()) {
+          dateStyle += " " + css().dayIsFiller();
+        } else {
+          String extraStyle = getDatePicker().getStyleOfDate(current);
+          if (extraStyle != null) {
+            dateStyle += " " + extraStyle;
+          }
+        }
+        // We want to certify that all date styles have " " before and after
+        // them for ease of adding to and replacing them.
+        dateStyle += " ";
+        updateStyle();
+      }
+
+      @Override
+      public void updateStyle() {
+        String accum = dateStyle;
+
+        if (isHighlighted()) {
+          accum += " " + css().dayIsHighlighted();
+
+          if (isHighlighted() && isSelected()) {
+            accum += " " + css().dayIsValueAndHighlighted();
+          }
+        }
+        if (!isEnabled()) {
+          accum += " " + css().dayIsDisabled();
+        }
+        setStyleName(accum);
+      }
+
+      private void setText(String value) {
+        DOM.setInnerText(getElement(), value);
+      }
+    }
+
+    CellGrid() {
+      resize(CalendarModel.WEEKS_IN_MONTH + 1, CalendarModel.DAYS_IN_WEEK);
+    }
+
+    @Override
+    protected void onSelected(Cell lastSelected, Cell cell) {
+    }
+  }
+
+  private CellGrid grid = new CellGrid();
+
+  private Date firstDisplayed;
+
+  private Date lastDisplayed = new Date();
+
+  /**
+   * Constructor.
+   */
+  public DefaultCalendarView() {
+  }
+
+  @Override
+  public void addStyleToDate(String styleName, Date date) {
+    assert getDatePicker().isDateVisible(date) : "You tried to add style " + styleName + " to "
+        + date + ". The calendar is currently showing " + getFirstDate()
+        + " to " + getLastDate();
+    getCell(date).addStyleName(styleName);
+  }
+
+  @Override
+  public Date getFirstDate() {
+    return firstDisplayed;
+  }
+
+  @Override
+  public Date getLastDate() {
+    return lastDisplayed;
+  }
+
+  @Override
+  public boolean isDateEnabled(Date d) {
+    return getCell(d).isEnabled();
+  }
+
+  @Override
+  public void refresh() {
+    firstDisplayed = getModel().getCurrentFirstDayOfFirstWeek();
+
+    if (firstDisplayed.getDate() == 1) {
+      // show one empty week if date is Monday is the first in month.
+      CalendarUtil.addDaysToDate(firstDisplayed, -7);
+    }
+
+    lastDisplayed.setTime(firstDisplayed.getTime());
+
+    for (int i = 0; i < grid.getNumCells(); i++) {
+      if (i != 0) {
+        CalendarUtil.addDaysToDate(lastDisplayed, 1);
+      }
+      DateCell cell = (DateCell) grid.getCell(i);
+      cell.update(lastDisplayed);
+    }
+  }
+
+  @Override
+  public void removeStyleFromDate(String styleName, Date date) {
+    getCell(date).removeStyleName(styleName);
+  }
+
+  @Override
+  public void setEnabledOnDate(boolean enabled, Date date) {
+    getCell(date).setEnabled(enabled);
+  }
+
+  @Override
+  public void setup() {
+    // Preparation
+    CellFormatter formatter = grid.getCellFormatter();
+    int weekendStartColumn = -1;
+    int weekendEndColumn = -1;
+
+    // Set up the day labels.
+    for (int i = 0; i < CalendarModel.DAYS_IN_WEEK; i++) {
+      int shift = CalendarUtil.getStartingDayOfWeek();
+      int dayIdx = i + shift < CalendarModel.DAYS_IN_WEEK ? i + shift : i
+          + shift - CalendarModel.DAYS_IN_WEEK;
+      grid.setText(0, i, getModel().formatDayOfWeek(dayIdx));
+
+      if (CalendarUtil.isWeekend(dayIdx)) {
+        formatter.setStyleName(0, i, css().weekendLabel());
+        if (weekendStartColumn == -1) {
+          weekendStartColumn = i;
+        } else {
+          weekendEndColumn = i;
+        }
+      } else {
+        formatter.setStyleName(0, i, css().weekdayLabel());
+      }
+    }
+
+    // Set up the calendar grid.
+    for (int row = 1; row <= CalendarModel.WEEKS_IN_MONTH; row++) {
+      for (int column = 0; column < CalendarModel.DAYS_IN_WEEK; column++) {
+        // set up formatter.
+        Element e = formatter.getElement(row, column);
+        grid.new DateCell(e, column == weekendStartColumn
+            || column == weekendEndColumn);
+      }
+    }
+    initWidget(grid);
+    grid.setStyleName(css().days());
+  }
+
+  private DateCell getCell(Date d) {
+    int index = CalendarUtil.getDaysBetween(firstDisplayed, d);
+    assert (index >= 0);
+
+    DateCell cell = (DateCell) grid.getCell(index);
+    if (cell.getValue().getDate() != d.getDate()) {
+      throw new IllegalStateException(d + " cannot be associated with cell "
+          + cell + " as it has date " + cell.getValue());
+    }
+    return cell;
+  }
+}
diff --git a/user/src/com/google/gwt/user/datepicker/client/DefaultMonthSelector.java b/user/src/com/google/gwt/user/datepicker/client/DefaultMonthSelector.java
new file mode 100644
index 0000000..611b354
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/DefaultMonthSelector.java
@@ -0,0 +1,84 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import com.google.gwt.event.dom.client.ClickEvent;

+import com.google.gwt.event.dom.client.ClickHandler;

+import com.google.gwt.user.client.ui.Grid;

+import com.google.gwt.user.client.ui.PushButton;

+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;

+

+/**

+ * A simple {@link MonthSelector} used for the default date picker. Not

+ * extensible as we wish to evolve it freely over time.

+ */

+

+public final class DefaultMonthSelector extends MonthSelector {

+

+  private PushButton backwards;

+  private PushButton forwards;

+  private Grid grid;

+

+  /**

+   * Constructor.

+   */

+  public DefaultMonthSelector() {

+  }

+ 

+  @Override

+  protected void refresh() {

+    String formattedMonth = getModel().formatCurrentMonth();

+    grid.setText(0, 1, formattedMonth);

+  }

+

+  @Override

+  protected void setup() {

+    // Set up backwards.

+    backwards = new PushButton();

+    backwards.addClickHandler(new ClickHandler() {

+      public void onClick(ClickEvent event) {

+        addMonths(-1);

+      }

+    });

+

+    backwards.getUpFace().setHTML("&laquo;");

+    backwards.setStyleName(css().previousButton());

+

+    forwards = new PushButton();

+    forwards.getUpFace().setHTML("&raquo;");

+    forwards.setStyleName(css().nextButton());

+    forwards.addClickHandler(new ClickHandler() {

+      public void onClick(ClickEvent event) {

+        addMonths(+1);

+      }

+    });

+

+    // Set up grid.

+    grid = new Grid(1, 3);

+    grid.setWidget(0, 0, backwards);

+    grid.setWidget(0, 2, forwards);

+

+    CellFormatter formatter = grid.getCellFormatter();

+    formatter.setStyleName(0, 1, css().month());

+    formatter.setWidth(0, 0, "1");

+    formatter.setWidth(0, 1, "100%");

+    formatter.setWidth(0, 2, "1");

+    grid.setStyleName(css().monthSelector());

+    initWidget(grid);

+  }

+

+}

diff --git a/user/src/com/google/gwt/user/datepicker/client/ElementMapper.java b/user/src/com/google/gwt/user/datepicker/client/ElementMapper.java
new file mode 100644
index 0000000..a495ee1
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/ElementMapper.java
@@ -0,0 +1,105 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import com.google.gwt.user.client.Element;

+import com.google.gwt.user.client.ui.UIObject;

+

+import java.util.ArrayList;

+

+/**

+ * Creates a mapping from elements to their associated ui objects.

+ * 

+ * @param <T> the type that the element is mapped to

+ */

+class ElementMapper<T extends UIObject> {

+

+  private static class FreeNode {

+    int index;

+    ElementMapper.FreeNode next;

+

+    public FreeNode(int index, ElementMapper.FreeNode next) {

+      this.index = index;

+      this.next = next;

+    }

+  }

+

+  private static native void clearIndex(Element elem) /*-{

+    elem["__uiObjectID"] = null;

+  }-*/;

+

+  private static native int getIndex(Element elem) /*-{

+    var index = elem["__uiObjectID"];

+    return (index == null) ? -1 : index;

+  }-*/;

+

+  private static native void setIndex(Element elem, int index) /*-{

+    elem["__uiObjectID"] = index;

+  }-*/;

+

+  private ElementMapper.FreeNode freeList = null;

+

+  private final ArrayList<T> uiObjectList = new ArrayList<T>();

+

+  /**

+   * Returns the uiObject associated with the given element.

+   * 

+   * @param elem uiObject's element

+   * @return the uiObject

+   */

+  public T get(Element elem) {

+    int index = getIndex(elem);

+    if (index < 0) {

+      return null;

+    }

+    return uiObjectList.get(index);

+  }

+

+  /**

+   * Adds the MappedType.

+   * 

+   * @param uiObject uiObject to add

+   */

+  public void put(T uiObject) {

+    int index;

+    if (freeList == null) {

+      index = uiObjectList.size();

+      uiObjectList.add(uiObject);

+    } else {

+      index = freeList.index;

+      uiObjectList.set(index, uiObject);

+      freeList = freeList.next;

+    }

+    setIndex(uiObject.getElement(), index);

+  }

+

+  /**

+   * Remove the uiObject associated with the given element.

+   * 

+   * @param elem the uiObject's element

+   */

+  public void removeByElement(Element elem) {

+    int index = getIndex(elem);

+    removeImpl(elem, index);

+  }

+

+  private void removeImpl(Element elem, int index) {

+    clearIndex(elem);

+    uiObjectList.set(index, null);

+    freeList = new FreeNode(index, freeList);

+  }

+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/datepicker/client/MonthSelector.java b/user/src/com/google/gwt/user/datepicker/client/MonthSelector.java
new file mode 100644
index 0000000..25e3dc7
--- /dev/null
+++ b/user/src/com/google/gwt/user/datepicker/client/MonthSelector.java
@@ -0,0 +1,22 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+/**

+ * Abstract month selector widget.

+ */

+public abstract class MonthSelector extends DatePickerComponent {

+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css
index c109008..0cbeb4e 100644
--- a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css
+++ b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css
@@ -1083,3 +1083,83 @@
 .gwt-Tree .gwt-TreeItem-selected {
   background: #93c2f1 url(images/hborder.png) repeat-x 0px -1463px;
 }
+
+.gwt-DateBox input {
+  width: 8em;
+}
+.dateBoxPopup {
+}
+
+.gwt-DatePicker {
+  border: 1px solid #888;
+  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: #c1c1c1;
+  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: #abf;
+}
+.datePickerDayIsDisabled {
+  color: #AAAAAA;
+  font-style: italic;
+}
+.datePickerDayIsHighlighted {
+  background: #dde;
+}
+.datePickerDayIsValueAndHighlighted {
+  background: #ccf;
+}
+.datePickerMonthSelector {
+  background: #c1c1c1;
+  width: 100%;
+}
+td.datePickerMonth {
+  text-align: center;
+  vertical-align: center;
+  white-space: nowrap;
+  font-size: 70%;
+  font-weight: bold;
+}
+.datePickerPreviousButton,
+.datePickerNextButton {
+  font-size: 120%;
+  line-height: 1em;
+  cursor: hand;
+  cursor: pointer;
+  padding: 0px 4px;
+}
diff --git a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css
index 3e46467..c4c3746 100644
--- a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css
+++ b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css
@@ -1083,3 +1083,83 @@
 .gwt-Tree .gwt-TreeItem-selected {
   background: #93c2f1 url(images/hborder.png) repeat-x 0px -1463px;
 }
+
+.gwt-DateBox input {
+  width: 8em;
+}
+.dateBoxPopup {
+}
+
+.gwt-DatePicker {
+  border: 1px solid #888;
+  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: #c1c1c1;
+  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: #abf;
+}
+.datePickerDayIsDisabled {
+  color: #AAAAAA;
+  font-style: italic;
+}
+.datePickerDayIsHighlighted {
+  background: #dde;
+}
+.datePickerDayIsValueAndHighlighted {
+  background: #ccf;
+}
+.datePickerMonthSelector {
+  background: #c1c1c1;
+  width: 100%;
+}
+td.datePickerMonth {
+  text-align: center;
+  vertical-align: center;
+  white-space: nowrap;
+  font-size: 70%;
+  font-weight: bold;
+}
+.datePickerPreviousButton,
+.datePickerNextButton {
+  font-size: 120%;
+  line-height: 1em;
+  cursor: hand;
+  cursor: pointer;
+  padding: 0px 4px;
+}
diff --git a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
index 8e38b61..37ab4c6 100644
--- a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
+++ b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
@@ -17,7 +17,7 @@
 body, table td, select {
   font-family: Arial Unicode MS, Arial, sans-serif;
   font-size: small;
-  color: #bec7cc;
+  color: #bec7cc
 }
 select {
   color: #000;
@@ -988,3 +988,89 @@
   color: #0cf;
   background: #1c1c1c;
 }
+
+.gwt-DateBox input {
+  width: 8em;
+}
+.dateBoxPopup {
+}
+
+.gwt-DatePicker {
+  border: 1px solid #00CCFF;
+  cursor: default;
+}
+.gwt-DatePicker td,
+.datePickerMonthSelector td:focus {
+  outline: none
+}
+.datePickerDays {
+  width: 100%;
+  background: #4d4d4d;
+}
+.datePickerDay,
+.datePickerWeekdayLabel,
+.datePickerWeekendLabel {
+  font-size: 75%;
+  text-align: center;
+  padding: 4px;
+  outline: none;
+  color: #dddddd;
+}
+.datePickerWeekdayLabel,
+.datePickerWeekendLabel {
+  background: #222222;
+  padding: 0px 4px 2px;
+  cursor: default;
+}
+.datePickerDay {
+  padding: 4px;
+  cursor: hand;
+  cursor: pointer;
+}
+.datePickerDayIsToday {
+  border: 1px solid #00CCFF;
+  padding: 3px;
+}
+.datePickerDayIsWeekend {
+  background: #333333;
+}
+.datePickerDayIsFiller {
+  color: #959595;
+}
+.datePickerDayIsValue {
+  background: #1C1C1C;
+  color: #00CCFF;
+}
+.datePickerDayIsDisabled {
+  color: #AAAAAA;
+  font-style: italic;
+}
+.datePickerDayIsHighlighted {
+  background: #00CCFF;
+  color: #1C1C1C;
+}
+.datePickerDayIsValueAndHighlighted {
+  background: #1C1C77;
+  color: #00CCFF;
+}
+.datePickerMonthSelector {
+  background: #222222;
+  width: 100%;
+}
+td.datePickerMonth {
+  text-align: center;
+  vertical-align: center;
+  white-space: nowrap;
+  font-size: 70%;
+  font-weight: bold;
+  color: #dddddd;
+}
+.datePickerPreviousButton,
+.datePickerNextButton {
+  font-size: 120%;
+  line-height: 1em;
+  cursor: hand;
+  cursor: pointer;
+  padding: 0px 4px;
+  color: #dddddd;
+}
diff --git a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
index 4c27422..6de5961 100644
--- a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
+++ b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
@@ -988,3 +988,89 @@
   color: #0cf;
   background: #1c1c1c;
 }
+
+.gwt-DateBox input {
+  width: 8em;
+}
+.dateBoxPopup {
+}
+
+.gwt-DatePicker {
+  border: 1px solid #00CCFF;
+  cursor: default;
+}
+.gwt-DatePicker td,
+.datePickerMonthSelector td:focus {
+  outline: none
+}
+.datePickerDays {
+  width: 100%;
+  background: #4d4d4d;
+}
+.datePickerDay,
+.datePickerWeekdayLabel,
+.datePickerWeekendLabel {
+  font-size: 75%;
+  text-align: center;
+  padding: 4px;
+  outline: none;
+  color: #dddddd;
+}
+.datePickerWeekdayLabel,
+.datePickerWeekendLabel {
+  background: #222222;
+  padding: 0px 4px 2px;
+  cursor: default;
+}
+.datePickerDay {
+  padding: 4px;
+  cursor: hand;
+  cursor: pointer;
+}
+.datePickerDayIsToday {
+  border: 1px solid #00CCFF;
+  padding: 3px;
+}
+.datePickerDayIsWeekend {
+  background: #333333;
+}
+.datePickerDayIsFiller {
+  color: #959595;
+}
+.datePickerDayIsValue {
+  background: #1C1C1C;
+  color: #00CCFF;
+}
+.datePickerDayIsDisabled {
+  color: #AAAAAA;
+  font-style: italic;
+}
+.datePickerDayIsHighlighted {
+  background: #00CCFF;
+  color: #1C1C1C;
+}
+.datePickerDayIsValueAndHighlighted {
+  background: #1C1C77;
+  color: #00CCFF;
+}
+.datePickerMonthSelector {
+  background: #222222;
+  width: 100%;
+}
+td.datePickerMonth {
+  text-align: center;
+  vertical-align: center;
+  white-space: nowrap;
+  font-size: 70%;
+  font-weight: bold;
+  color: #dddddd;
+}
+.datePickerPreviousButton,
+.datePickerNextButton {
+  font-size: 120%;
+  line-height: 1em;
+  cursor: hand;
+  cursor: pointer;
+  padding: 0px 4px;
+  color: #dddddd;
+}
diff --git a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css
index aecc9f8..76fb73a 100644
--- a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css
+++ b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css
@@ -1082,3 +1082,85 @@
 .gwt-Tree .gwt-TreeItem-selected {
   background: #93c2f1 url(images/hborder.png) repeat-x 0px -1463px;
 }
+
+.gwt-DateBox input {
+  width: 8em;
+}
+.dateBoxPopup {
+}
+
+.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;
+}
diff --git a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css
index 6cecc14..916ea1f 100644
--- a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css
+++ b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css
@@ -1082,3 +1082,85 @@
 .gwt-Tree .gwt-TreeItem-selected {
   background: #93c2f1 url(images/hborder.png) repeat-x 0px -1463px;
 }
+
+.gwt-DateBox input {
+  width: 8em;
+}
+.dateBoxPopup {
+}
+
+.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;
+}
diff --git a/user/test/com/google/gwt/event/logical/shared/LogicalEventsTest.java b/user/test/com/google/gwt/event/logical/shared/LogicalEventsTest.java
index 985c79a..dc03d2a 100644
--- a/user/test/com/google/gwt/event/logical/shared/LogicalEventsTest.java
+++ b/user/test/com/google/gwt/event/logical/shared/LogicalEventsTest.java
@@ -67,7 +67,7 @@
     simpleFire(BeforeSelectionEvent.getType(),
         new BeforeSelectionEvent<String>());
     simpleFire(SelectionEvent.getType(), new SelectionEvent<String>(null));
-    simpleFire(CloseEvent.getType(), new CloseEvent<String>(null,false));
+    simpleFire(CloseEvent.getType(), new CloseEvent<String>(null, false));
     simpleFire(OpenEvent.getType(), new OpenEvent<String>(null));
     simpleFire(ResizeEvent.getType(), new ResizeEvent(0, 0));
     simpleFire(ValueChangeEvent.getType(), new ValueChangeEvent<String>(null));
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index 1f06f51..56d1d5b 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -26,12 +26,15 @@
 import com.google.gwt.user.client.ui.CompositeTest;
 import com.google.gwt.user.client.ui.CustomButtonTest;
 import com.google.gwt.user.client.ui.DOMTest;
+import com.google.gwt.user.client.ui.DateBoxTest;
+import com.google.gwt.user.client.ui.DatePickerTest;
 import com.google.gwt.user.client.ui.DeckPanelTest;
 import com.google.gwt.user.client.ui.DecoratedPopupTest;
 import com.google.gwt.user.client.ui.DecoratedStackPanelTest;
 import com.google.gwt.user.client.ui.DecoratedTabBarTest;
 import com.google.gwt.user.client.ui.DecoratedTabPanelTest;
 import com.google.gwt.user.client.ui.DecoratorPanelTest;
+import com.google.gwt.user.client.ui.DelegatingKeyboardListenerCollectionTest;
 import com.google.gwt.user.client.ui.DialogBoxTest;
 import com.google.gwt.user.client.ui.DisclosurePanelTest;
 import com.google.gwt.user.client.ui.DockPanelTest;
@@ -73,6 +76,7 @@
 import com.google.gwt.user.client.ui.WidgetOnLoadTest;
 import com.google.gwt.user.client.ui.WidgetSubclassingTest;
 import com.google.gwt.user.client.ui.impl.ClippedImagePrototypeTest;
+import com.google.gwt.user.datepicker.client.DateChangeEventTest;
 import com.google.gwt.user.rebind.ui.ImageBundleGeneratorTest;
 import com.google.gwt.xml.client.XMLTest;
 
@@ -83,8 +87,7 @@
  */
 public class UISuite {
   public static Test suite() {
-    GWTTestSuite suite = new GWTTestSuite(
-        "Test for suite for the com.google.gwt.ui module");
+    GWTTestSuite suite = new GWTTestSuite("Test for suite for all user widgets");
 
     suite.addTestSuite(AbsolutePanelTest.class);
     suite.addTestSuite(AnchorTest.class);
@@ -95,14 +98,15 @@
     suite.addTestSuite(CompositeTest.class);
     suite.addTestSuite(CookieTest.class);
     suite.addTestSuite(CustomButtonTest.class);
+    suite.addTestSuite(DateBoxTest.class);
+    suite.addTestSuite(DatePickerTest.class);
     suite.addTestSuite(DeckPanelTest.class);
     suite.addTestSuite(DecoratedPopupTest.class);
     suite.addTestSuite(DecoratedStackPanelTest.class);
     suite.addTestSuite(DecoratedTabBarTest.class);
     suite.addTestSuite(DecoratedTabPanelTest.class);
     suite.addTestSuite(DecoratorPanelTest.class);
-    // TEMP
-    // suite.addTestSuite(DelegatingKeyboardListenerCollectionTest.class);
+    suite.addTestSuite(DelegatingKeyboardListenerCollectionTest.class);
     suite.addTestSuite(DialogBoxTest.class);
     suite.addTestSuite(DisclosurePanelTest.class);
     suite.addTestSuite(DockPanelTest.class);
@@ -149,7 +153,7 @@
     suite.addTestSuite(WindowTest.class);
     suite.addTestSuite(XMLTest.class);
     suite.addTestSuite(ClassInitTest.class);
-
+    suite.addTestSuite(DateChangeEventTest.class);
     return suite;
   }
 }
diff --git a/user/test/com/google/gwt/user/client/ui/DateBoxTest.java b/user/test/com/google/gwt/user/client/ui/DateBoxTest.java
new file mode 100644
index 0000000..624359a
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/DateBoxTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 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.user.client.ui;
+
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.datepicker.client.DateBox;
+
+/**
+ * Tests DateBox.
+ */
+public class DateBoxTest extends GWTTestCase {
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+  
+  public void testValueChangeEvent() {
+    DateBox db = new DateBox();
+    RootPanel.get().add(db);
+    new DateValueChangeTester(db).run();    
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/DatePickerTest.java b/user/test/com/google/gwt/user/client/ui/DatePickerTest.java
new file mode 100644
index 0000000..cafac56
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/DatePickerTest.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2008 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.user.client.ui;
+
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.datepicker.client.CalendarModel;
+import com.google.gwt.user.datepicker.client.CalendarView;
+import com.google.gwt.user.datepicker.client.DatePicker;
+import com.google.gwt.user.datepicker.client.DefaultMonthSelector;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Tests DatePicker's public api.
+ */
+@SuppressWarnings("deprecation")
+// Due to Date
+public class DatePickerTest extends GWTTestCase {
+
+  private static class DatePickerWithView extends DatePicker {
+    DatePickerWithView(MockCalendarView view) {
+      super(new DefaultMonthSelector(), view, new CalendarModel());
+    }
+  }
+  /**
+   * Mock calendar view pretends to show datesVisibleList from the first of the month to
+   * the 30th day after that.
+   */
+  private static class MockCalendarView extends CalendarView {
+    Map<Date, Set<String>> dateStyles = new HashMap<Date, Set<String>>();
+    Set<Date> disabledDates = new HashSet<Date>();
+
+    MockCalendarView() {
+      initWidget(new Label());
+    }
+
+    @Override
+    public void addStyleToDate(String styleName, Date date) {
+      Set<String> fred = dateStyles.get(date);
+      if (fred == null) {
+        fred = new HashSet<String>();
+        dateStyles.put(date, fred);
+      }
+      fred.add(styleName);
+    }
+
+    @Override
+    public Date getFirstDate() {
+      Date thisMonth = getModel().getCurrentMonth();
+      return new Date(thisMonth.getYear(), thisMonth.getMonth(), 1);
+    }
+
+    @Override
+    public Date getLastDate() {
+      Date thisMonth = getModel().getCurrentMonth();
+      return new Date(thisMonth.getYear(), thisMonth.getMonth(), 30);
+    }
+
+    @Override
+    public boolean isDateEnabled(Date date) {
+      return !disabledDates.contains(date);
+    }
+
+    @Override
+    public void refresh() {
+    }
+
+    @Override
+    public void removeStyleFromDate(String styleName, Date date) {
+      Set<String> fred;
+      assertNotNull(fred = dateStyles.get(date));
+      assertTrue(fred.remove(styleName));
+    }
+
+    @Override
+    public void setEnabledOnDate(boolean enabled, Date date) {
+      if (enabled) {
+        disabledDates.remove(date);
+      } else {
+        disabledDates.add(date);
+      }
+    }
+
+    @Override
+    protected void setup() {
+    }
+  }
+
+  private static final String STYLE_LATER = "styleLater";
+
+  private static final String STYLE = "style1";
+
+  private DatePickerWithView mockedDatePicker;
+  private MockCalendarView view;
+
+  private final Date dateVisible1 = new Date(65, 6, 12);
+  private final Date dateVisible2 = new Date(65, 6, 13);
+  private final Date dateVisible3 = new Date(65, 6, 14);
+  private final Date dateVisible4 = new Date(65, 6, 15);
+  private final Date dateVisible5 = new Date(65, 6, 16);
+  private final List<Date> datesVisibleList = new ArrayList<Date>();
+  private final Date dateLater1 =
+      new Date(dateVisible1.getYear(), dateVisible1.getMonth() + 1,
+          dateVisible1.getDay());
+
+  private final Date dateLater2 =
+      new Date(dateVisible2.getYear(), dateVisible2.getMonth() + 1,
+          dateVisible2.getDay());
+  private final Date dateLater3 =
+      new Date(dateVisible1.getYear(), dateVisible3.getMonth() + 1,
+          dateVisible3.getDay());
+  private final Date dateLater4 =
+      new Date(dateVisible2.getYear(), dateVisible4.getMonth() + 1,
+          dateVisible4.getDay());
+  private final Date dateLater5 =
+      new Date(dateVisible1.getYear(), dateVisible5.getMonth() + 1,
+          dateVisible5.getDay());
+  private final List<Date> datesLaterList = new ArrayList<Date>();
+  {
+    datesVisibleList.add(dateVisible4);
+    datesVisibleList.add(dateVisible5);
+  }
+  {
+    datesLaterList.add(dateLater4);
+    datesLaterList.add(dateLater5);
+  }
+
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+
+  @Override
+  public void gwtSetUp() throws Exception {
+    super.gwtSetUp();
+
+    view = new MockCalendarView();
+    mockedDatePicker = new DatePickerWithView(view);
+    mockedDatePicker.setCurrentMonth(dateVisible1);
+  }
+
+  public void testDisabling() {
+    mockedDatePicker.setTransientEnabledOnDates(false, dateVisible1);
+    mockedDatePicker.setTransientEnabledOnDates(false, dateVisible2,
+        dateVisible3);
+    mockedDatePicker.setTransientEnabledOnDates(false, datesVisibleList);
+    
+    assertTrue(view.disabledDates.contains(dateVisible1));
+    assertTrue(view.disabledDates.contains(dateVisible2));
+    assertTrue(view.disabledDates.contains(dateVisible3));
+    assertTrue(view.disabledDates.contains(dateVisible4));
+    assertTrue(view.disabledDates.contains(dateVisible5));
+
+    mockedDatePicker.setTransientEnabledOnDates(true, dateVisible1);
+    mockedDatePicker.setTransientEnabledOnDates(true, dateVisible2,
+        dateVisible3);
+    mockedDatePicker.setTransientEnabledOnDates(true, datesVisibleList);
+
+    assertFalse(view.disabledDates.contains(dateVisible1));
+    assertFalse(view.disabledDates.contains(dateVisible2));
+    assertFalse(view.disabledDates.contains(dateVisible3));
+    assertFalse(view.disabledDates.contains(dateVisible4));
+    assertFalse(view.disabledDates.contains(dateVisible5));
+  }
+
+  public void testStyleSetting() {
+    mockedDatePicker.addStyleToDates(STYLE, dateVisible1);
+    mockedDatePicker.addStyleToDates(STYLE, dateVisible2, dateVisible3);
+    mockedDatePicker.addStyleToDates(STYLE, datesVisibleList);
+
+    assertViewHasStyleOnVisibleDates(STYLE);
+    assertPickerHasStyleOnVisibleDates(STYLE);
+
+    // See that styles on an invisible datesVisibleList don't
+
+    mockedDatePicker.addStyleToDates(STYLE_LATER, dateLater1);
+    mockedDatePicker.addStyleToDates(STYLE_LATER, dateLater2, dateLater3);
+    mockedDatePicker.addStyleToDates(STYLE_LATER, datesLaterList);
+
+    assertViewHasNoStyleOnHiddenDates();
+    assertPickerLacksStyleOnHiddenDates(STYLE_LATER);
+
+    // Remove a style from a visible date, and it should leave the view too
+    mockedDatePicker.removeStyleFromDates(STYLE, dateVisible1);
+    mockedDatePicker.removeStyleFromDates(STYLE, dateVisible2, dateVisible3);
+    mockedDatePicker.removeStyleFromDates(STYLE, datesVisibleList);
+
+    assertViewLacksStyleOnVisibleDates(STYLE);
+    assertPickerLacksStyleOnVisibleDates();
+
+    // Remove a style from an invisible date, and the view should not hear
+    // about it (the mock will explode if asked to remove a style it doesn't
+    // have)
+    mockedDatePicker.removeStyleFromDates(STYLE_LATER, dateLater1);
+    mockedDatePicker.removeStyleFromDates(STYLE_LATER, dateLater2, dateLater3);
+    mockedDatePicker.removeStyleFromDates(STYLE_LATER, datesLaterList);
+    assertPickerHasNoStyleOnInvisibleDates();
+  }
+
+  public void testTransientStyles() {
+    mockedDatePicker.addTransientStyleToDates(STYLE, dateVisible1);
+    mockedDatePicker.addTransientStyleToDates(STYLE, dateVisible2,
+        dateVisible3);
+    mockedDatePicker.addTransientStyleToDates(STYLE, datesVisibleList);
+    assertViewHasStyleOnVisibleDates(STYLE);
+    assertPickerLacksStyleOnVisibleDates();
+    
+    mockedDatePicker.removeStyleFromDates(STYLE, dateVisible1);
+    mockedDatePicker.removeStyleFromDates(STYLE, dateVisible2, dateVisible3);
+    mockedDatePicker.removeStyleFromDates(STYLE, datesVisibleList);
+    assertViewLacksStyleOnVisibleDates(STYLE);
+    assertPickerLacksStyleOnVisibleDates();
+  }
+  
+  public void testValueChangeEvent() {
+    DatePicker dp = new DatePicker();
+    RootPanel.get().add(dp);
+    new DateValueChangeTester(dp).run();
+  }
+  
+  public void testValueStyle() {
+    assertNull(mockedDatePicker.getStyleOfDate(dateVisible4));
+    
+    mockedDatePicker.setValue(dateVisible4);
+    assertTrue(mockedDatePicker.getStyleOfDate(dateVisible4).contains("datePickerDayIsValue"));
+    assertTrue(view.dateStyles.get(dateVisible4).contains("datePickerDayIsValue"));
+
+    mockedDatePicker.setValue(dateVisible5);
+    assertNull(mockedDatePicker.getStyleOfDate(dateVisible4));
+    assertFalse(view.dateStyles.get(dateVisible4).contains("datePickerDayIsValue"));
+  }
+
+  private void assertPickerHasNoStyleOnInvisibleDates() {
+    assertNull(mockedDatePicker.getStyleOfDate(dateLater1));
+    assertNull(mockedDatePicker.getStyleOfDate(dateLater2));
+    assertNull(mockedDatePicker.getStyleOfDate(dateLater3));
+    assertNull(mockedDatePicker.getStyleOfDate(dateLater4));
+    assertNull(mockedDatePicker.getStyleOfDate(dateLater5));
+  }
+
+  private void assertPickerHasStyleOnVisibleDates(String style) {
+    assertTrue(mockedDatePicker.getStyleOfDate(dateVisible1).contains(
+        style));
+    assertTrue(mockedDatePicker.getStyleOfDate(dateVisible2).contains(
+        style));
+    assertTrue(mockedDatePicker.getStyleOfDate(dateVisible3).contains(
+        style));
+    assertTrue(mockedDatePicker.getStyleOfDate(dateVisible4).contains(
+        style));
+    assertTrue(mockedDatePicker.getStyleOfDate(dateVisible5).contains(
+        style));
+  }
+
+  private void assertPickerLacksStyleOnHiddenDates(String styleLater) {
+    assertTrue(mockedDatePicker.getStyleOfDate(dateLater1).contains(
+        styleLater));
+    assertTrue(mockedDatePicker.getStyleOfDate(dateLater2).contains(
+        styleLater));
+    assertTrue(mockedDatePicker.getStyleOfDate(dateLater3).contains(
+        styleLater));
+    assertTrue(mockedDatePicker.getStyleOfDate(dateLater4).contains(
+        styleLater));
+    assertTrue(mockedDatePicker.getStyleOfDate(dateLater5).contains(
+        styleLater));
+  }
+
+  private void assertPickerLacksStyleOnVisibleDates() {
+    assertNull(mockedDatePicker.getStyleOfDate(dateVisible1));
+    assertNull(mockedDatePicker.getStyleOfDate(dateVisible2));
+    assertNull(mockedDatePicker.getStyleOfDate(dateVisible3));
+    assertNull(mockedDatePicker.getStyleOfDate(dateVisible4));
+    assertNull(mockedDatePicker.getStyleOfDate(dateVisible5));
+  }
+
+  private void assertViewHasNoStyleOnHiddenDates() {
+    assertNull(view.dateStyles.get(dateLater1));
+    assertNull(view.dateStyles.get(dateLater2));
+    assertNull(view.dateStyles.get(dateLater3));
+    assertNull(view.dateStyles.get(dateLater4));
+    assertNull(view.dateStyles.get(dateLater5));
+  }
+
+  private void assertViewHasStyleOnVisibleDates(String style) {
+    assertTrue(view.dateStyles.get(dateVisible1).contains(style));
+    assertTrue(view.dateStyles.get(dateVisible2).contains(style));
+    assertTrue(view.dateStyles.get(dateVisible3).contains(style));
+    assertTrue(view.dateStyles.get(dateVisible4).contains(style));
+    assertTrue(view.dateStyles.get(dateVisible5).contains(style));
+  }
+
+  private void assertViewLacksStyleOnVisibleDates(String style) {
+    assertFalse(view.dateStyles.get(dateVisible1).contains(style));
+    assertFalse(view.dateStyles.get(dateVisible2).contains(style));
+    assertFalse(view.dateStyles.get(dateVisible3).contains(style));
+    assertFalse(view.dateStyles.get(dateVisible4).contains(style));
+    assertFalse(view.dateStyles.get(dateVisible5).contains(style));
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/DateValueChangeTester.java b/user/test/com/google/gwt/user/client/ui/DateValueChangeTester.java
new file mode 100644
index 0000000..0e9636f
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/DateValueChangeTester.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2008 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.user.client.ui;
+
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+
+import junit.framework.TestCase;
+
+import java.util.Date;
+
+/**
+ * Handy tool for testing classes that implement {@link HasValue<Date>}.
+ */
+public class DateValueChangeTester {
+  static class Handler implements ValueChangeHandler<Date> {
+    Date received = null;
+
+    public void onValueChange(ValueChangeEvent<Date> event) {
+      received = event.getValue();
+    }
+  }
+
+  private final HasValue<Date> subject;
+
+  /**
+   * The HasValue<Date> to be tested. It should have been freshly created before
+   * handing it to this tester.
+   */
+  public DateValueChangeTester(HasValue<Date> subject) {
+    this.subject = subject;
+  }
+
+  /**
+   * Asserts that the default value is null, checks that value change events do
+   * and don't fire when appropriate, and that getValue() always returns what
+   * was handed to getValue().
+   */
+  @SuppressWarnings("deprecation")
+  public void run() {
+    TestCase.assertNull(subject.getValue());
+
+    DateValueChangeTester.Handler h = new Handler();
+    subject.addValueChangeHandler(h);
+
+    subject.setValue(null);
+    TestCase.assertNull(subject.getValue());
+    TestCase.assertNull(h.received);
+
+    Date able = new Date(1999, 5, 15);
+    subject.setValue(able);
+    TestCase.assertEquals(able, subject.getValue());
+    TestCase.assertNull(h.received);
+
+    subject.setValue(able);
+    TestCase.assertNull(h.received);
+
+    Date baker = new Date(1965, 12, 7);
+    subject.setValue(baker);
+    TestCase.assertNull(h.received);
+
+    // Value has not changed, so should not fire a change event even though
+    // fire event is true.
+    subject.setValue(baker, true);
+    TestCase.assertNull(h.received);
+
+    subject.setValue(able, true);
+    TestCase.assertEquals(able, h.received);
+    TestCase.assertNotSame(able, h.received);
+
+    subject.setValue(baker, true);
+    TestCase.assertEquals(baker, h.received);
+    TestCase.assertNotSame(baker, h.received);
+    
+    h.received = null;
+    // Value has changed, but boolean is false.
+    subject.setValue(baker, false);
+    TestCase.assertNull(h.received);
+  }
+}
\ No newline at end of file
diff --git a/user/test/com/google/gwt/user/client/ui/TextBoxBaseTestBase.java b/user/test/com/google/gwt/user/client/ui/TextBoxBaseTestBase.java
index bf47218..58aa3e2 100644
--- a/user/test/com/google/gwt/user/client/ui/TextBoxBaseTestBase.java
+++ b/user/test/com/google/gwt/user/client/ui/TextBoxBaseTestBase.java
@@ -98,22 +98,31 @@
   
   public void testValueChangeEvent() {
     TextBoxBase tb = createTextBoxBase();
-
     // To work cross-platform, the tb must be added to the root panel.
     RootPanel.get().add(tb);
+    
     Handler h = new Handler();
     tb.addValueChangeHandler(h);
-    tb.setText("able");
+    
+    tb.setValue(null);
+    assertEquals("", tb.getValue());
     assertNull(h.received);
     
-    tb.setValue("able");
+    tb.setText("able");
+    assertEquals("able", tb.getValue());
     assertNull(h.received);
+
+    tb.setValue("able");
+    assertEquals("able", tb.getValue());
+    assertNull(h.received);
+
     tb.setValue("baker");
     assertNull(h.received);
 
     tb.setValue("baker", true);
+    assertEquals("baker", tb.getValue());
     assertNull(h.received);
-    
+
     tb.setValue("able", true);
     assertEquals("able", h.received);
 
diff --git a/user/test/com/google/gwt/user/datepicker/client/DateChangeEventTest.java b/user/test/com/google/gwt/user/datepicker/client/DateChangeEventTest.java
new file mode 100644
index 0000000..b8c5361
--- /dev/null
+++ b/user/test/com/google/gwt/user/datepicker/client/DateChangeEventTest.java
@@ -0,0 +1,69 @@
+/*

+ * Copyright 2008 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.user.datepicker.client;

+

+import com.google.gwt.event.logical.shared.ValueChangeEvent;

+import com.google.gwt.event.logical.shared.ValueChangeHandler;

+import com.google.gwt.event.shared.HandlerManager;

+import com.google.gwt.event.shared.HandlerRegistration;

+import com.google.gwt.user.client.ui.DateValueChangeTester;

+import com.google.gwt.user.client.ui.HasValue;

+

+import junit.framework.TestCase;

+

+import java.util.Date;

+

+/**

+ * Test the DateChangeEvent in isolation from GWT.

+ */

+public class DateChangeEventTest extends TestCase {

+

+  private class MockWidget implements HasValue<Date> {

+    private final HandlerManager handlers = new HandlerManager(this);

+    private Date value;

+

+    public HandlerRegistration addValueChangeHandler(

+        ValueChangeHandler<Date> handler) {

+      return handlers.addHandler(ValueChangeEvent.getType(), handler);

+    }

+

+    public HandlerManager getHandlers() {

+      return handlers;

+    }

+

+    public Date getValue() {

+      return value;

+    }

+

+    public void setValue(Date value) {

+      setValue(value, false);

+    }

+

+    public void setValue(Date value, boolean fireEvents) {

+      Date oldValue = this.value;

+      this.value = value;

+      if (fireEvents) {

+        DateChangeEvent.fireIfNotEqualDates(this, oldValue, value);

+      }

+    }

+  }

+

+  public void testValueChangeViaHasValue() {

+    new DateValueChangeTester(new MockWidget()).run();

+  }

+

+}