This patch:
- reuses editors in every IsEditor widget (issue 5479)
- adds a ValueLabel widget, and DateLabel and NumberLabel subclasses
(issue 5507), introduces a NumberFormatRenderer (similar to the
existing DateTimeFormatRenderer) for use in NumberLabel (this one is
a paraterized class to make it usable with Editors:
NumberLabel<Double>, NumberLabel<Integer>, etc.)
- makes ToggleButton an IsEditor<LeafValueEditor<Boolean>> (issue
5571)
- makes SimpleCheckBox a TakesValue<Boolean> and
IsEditor<LeafValueEditor<Boolean>> to put it on par with CheckBox
- makes Hidden implement TakesValue<String> and
IsEditor<LeafValueEditor<String>>, which makes it usable with editors
*and* FormPanel (SimpleEditor is OK if you're not using FormPanel)

Public review at http://gwt-code-reviews.appspot.com/1099801/show

Patch by: tbroyer
Review by: rjrjr, jat


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9297 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/i18n/client/DateTimeFormatInfo.java b/user/src/com/google/gwt/i18n/client/DateTimeFormatInfo.java
index a4d3fb2..6672ac8 100644
--- a/user/src/com/google/gwt/i18n/client/DateTimeFormatInfo.java
+++ b/user/src/com/google/gwt/i18n/client/DateTimeFormatInfo.java
@@ -98,7 +98,7 @@
    * @param timePattern the time pattern String
    * @param datePattern the data pattern String
    */
-  String dateTimeShort(String datePattern, String timePattern);
+  String dateTimeShort(String timePattern, String datePattern);
 
   /**
    * Returns an array of the full era names.
diff --git a/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java b/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java
index 9a8699b..78af84d 100644
--- a/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java
+++ b/user/src/com/google/gwt/text/client/DateTimeFormatRenderer.java
@@ -47,6 +47,7 @@
    * Create an instance with the given format and time zone.
    */
   public DateTimeFormatRenderer(DateTimeFormat format, TimeZone timeZone) {
+    assert format != null;
     this.format = format;
     this.timeZone = timeZone;
   }
diff --git a/user/src/com/google/gwt/text/client/NumberFormatRenderer.java b/user/src/com/google/gwt/text/client/NumberFormatRenderer.java
new file mode 100644
index 0000000..b6e1e88
--- /dev/null
+++ b/user/src/com/google/gwt/text/client/NumberFormatRenderer.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.text.client;
+
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.text.shared.AbstractRenderer;
+
+/**
+ * Renders {@link Number} objects with a {@link NumberFormat}.
+ */
+public class NumberFormatRenderer extends AbstractRenderer<Number> {
+  private final NumberFormat format;
+
+  /**
+   * Create an instance using {@link NumberFormat#getDecimalFormat()}.
+   */
+  public NumberFormatRenderer() {
+    this(NumberFormat.getDecimalFormat());
+  }
+
+  /**
+   * Create an instance with the given format.
+   */
+  public NumberFormatRenderer(NumberFormat format) {
+    this.format = format;
+  }
+
+  public String render(Number object) {
+    if (object == null) {
+      return "";
+    }
+    return format.format(object);
+  }
+}
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/DateLabelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/DateLabelParser.java
new file mode 100644
index 0000000..1359664
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/elementparsers/DateLabelParser.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.uibinder.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.core.ext.typeinfo.TypeOracleException;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.TimeZone;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.XMLElement;
+
+/**
+ * Parses {@link com.google.gwt.user.client.ui.DateLabel} widgets.
+ */
+public class DateLabelParser implements ElementParser {
+
+  static final String AT_MOST_ONE_SPECIFIED_FORMAT = "May have at most one of format, predefinedFormat and customFormat.";
+  static final String AT_MOST_ONE_SPECIFIED_TIME_ZONE = "May have at most one of timezone and timezoneOffset.";
+  static final String NO_TIMEZONE_WITHOUT_SPECIFIED_FORMAT = "May not specify a time zone if no format is given.";
+
+  public void parse(XMLElement elem, String fieldName, JClassType type,
+      UiBinderWriter writer) throws UnableToCompleteException {
+    boolean supportsTimeZone = hasDateTimeFormatAndTimeZoneConstructor(
+        writer.getOracle(), type);
+    if (hasDateTimeFormatConstructor(writer.getOracle(), type)
+        || supportsTimeZone) {
+      String format = consumeFormat(elem, writer);
+
+      if (format != null) {
+        String timeZone = (supportsTimeZone ? consumeTimeZone(elem, writer)
+            : null);
+
+        writer.setFieldInitializerAsConstructor(fieldName, type, makeArgs(
+            format, timeZone));
+      } else if (supportsTimeZone && hasTimeZone(elem)) {
+        writer.die(elem, NO_TIMEZONE_WITHOUT_SPECIFIED_FORMAT);
+      }
+    }
+  }
+
+  private String consumeFormat(XMLElement elem, UiBinderWriter writer)
+      throws UnableToCompleteException {
+    String format = elem.consumeAttribute("format",
+        writer.getOracle().findType(DateTimeFormat.class.getCanonicalName()));
+    String predefinedFormat = elem.consumeAttribute("predefinedFormat",
+        writer.getOracle().findType(PredefinedFormat.class.getCanonicalName()));
+    String customFormat = elem.consumeStringAttribute("customFormat");
+
+    if (format != null) {
+      if (predefinedFormat != null || customFormat != null) {
+        writer.die(elem, AT_MOST_ONE_SPECIFIED_FORMAT);
+      }
+      return format;
+    }
+    if (predefinedFormat != null) {
+      if (customFormat != null) {
+        writer.die(elem, AT_MOST_ONE_SPECIFIED_FORMAT);
+      }
+      return makeGetFormat(predefinedFormat);
+    }
+    if (customFormat != null) {
+      return makeGetFormat(customFormat);
+    }
+    return null;
+  }
+
+  private String consumeTimeZone(XMLElement elem, UiBinderWriter writer)
+      throws UnableToCompleteException {
+    String timeZone = elem.consumeAttribute("timezone",
+        writer.getOracle().findType(TimeZone.class.getCanonicalName()));
+    String timeZoneOffset = elem.consumeAttribute("timezoneOffset",
+        getIntType(writer.getOracle()));
+    if (timeZone != null && timeZoneOffset != null) {
+      writer.die(elem, AT_MOST_ONE_SPECIFIED_TIME_ZONE);
+    }
+    if (timeZone != null) {
+      return timeZone;
+    }
+    if (timeZoneOffset != null) {
+      return TimeZone.class.getCanonicalName() + ".createTimeZone("
+          + timeZoneOffset + ")";
+    }
+    return null;
+  }
+
+  private JType getIntType(TypeOracle oracle) {
+    try {
+      return oracle.parse("int");
+    } catch (TypeOracleException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  private boolean hasDateTimeFormatAndTimeZoneConstructor(
+      TypeOracle typeOracle, JClassType type) {
+    JType dateTimeFormatType = typeOracle.findType(DateTimeFormat.class.getName());
+    JType timeZoneType = typeOracle.findType(TimeZone.class.getName());
+    return type.findConstructor(new JType[] {dateTimeFormatType, timeZoneType}) != null;
+  }
+
+  private boolean hasDateTimeFormatConstructor(TypeOracle typeOracle,
+      JClassType type) {
+    JType dateTimeFormatType = typeOracle.findType(DateTimeFormat.class.getName());
+    return type.findConstructor(new JType[] {dateTimeFormatType}) != null;
+  }
+
+  private boolean hasTimeZone(XMLElement elem) {
+    return elem.hasAttribute("timezone") || elem.hasAttribute("timezoneOffset");
+  }
+
+  private String[] makeArgs(String format, String timeZone) {
+    if (timeZone == null) {
+      return new String[] {format};
+    }
+    return new String[] {format, timeZone};
+  }
+
+  private String makeGetFormat(String format) {
+    return DateTimeFormat.class.getCanonicalName() + ".getFormat(" + format
+        + ")";
+  }
+}
diff --git a/user/src/com/google/gwt/uibinder/elementparsers/NumberLabelParser.java b/user/src/com/google/gwt/uibinder/elementparsers/NumberLabelParser.java
new file mode 100644
index 0000000..5ff6656
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/elementparsers/NumberLabelParser.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.uibinder.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.i18n.client.CurrencyData;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.XMLElement;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parses {@link com.google.gwt.user.client.ui.DateLabel} widgets.
+ */
+public class NumberLabelParser implements ElementParser {
+
+  static final String AT_MOST_ONE_SPECIFIED_FORMAT = "May have only one of format, predefinedFormat and customFormat.";
+  static final String AT_MOST_ONE_SPECIFIED_CURRENCY = "May have only one of currencyData and customCode.";
+  static final String NO_CURRENCY_WITH_FORMAT = "May not specify both a NumberFormat and a currency code.";
+  static final String NO_CURRENCY_WITHOUT_SPECIFIED_FORMAT = "May not specify a currency code if no format is given.";
+  static final String NO_CURRENCY_WITH_PREDEFINED_FORMAT = "May not specify a currency code with a predefined format (except the CURRENCY format)";
+  static final String UNKNOWN_PREDEFINED_FORMAT = "Unknown predefined format: %s";
+
+  private static final Map<String, String> predefinedFormats;
+
+  static {
+    String prefix = NumberFormat.class.getCanonicalName();
+    Map<String, String> formats = new HashMap<String, String>(4);
+    formats.put("DECIMAL", prefix + ".getDecimalFormat()");
+    formats.put("PERCENT", prefix + ".getPercentFormat()");
+    formats.put("SCIENTIFIC", prefix + ".getScientificFormat()");
+    // CURRENCY is special-cased in consumeFormat.
+    predefinedFormats = Collections.unmodifiableMap(formats);
+  }
+
+  public void parse(XMLElement elem, String fieldName, JClassType type,
+      UiBinderWriter writer) throws UnableToCompleteException {
+    if (hasNumberFormatConstructor(writer.getOracle(), type)) {
+      String format = consumeFormat(elem, writer);
+
+      if (format != null) {
+        writer.setFieldInitializerAsConstructor(fieldName, type, format);
+      }
+    }
+  }
+
+  private String consumeCurrency(XMLElement elem, UiBinderWriter writer)
+      throws UnableToCompleteException {
+    String currencyData = elem.consumeAttribute("currencyData",
+        writer.getOracle().findType(CurrencyData.class.getCanonicalName()));
+    String currencyCode = elem.consumeStringAttribute("currencyCode");
+
+    if (currencyData != null && currencyCode != null) {
+      writer.die(elem, AT_MOST_ONE_SPECIFIED_CURRENCY);
+    }
+    return currencyData != null ? currencyData : currencyCode;
+  }
+
+  private String consumeFormat(XMLElement elem, UiBinderWriter writer)
+      throws UnableToCompleteException {
+    String format = elem.consumeAttribute("format",
+        writer.getOracle().findType(DateTimeFormat.class.getCanonicalName()));
+    String predefinedFormat = elem.consumeRawAttribute("predefinedFormat");
+    String customFormat = elem.consumeStringAttribute("customFormat");
+
+    if (format != null) {
+      if (predefinedFormat != null || customFormat != null) {
+        writer.die(elem, AT_MOST_ONE_SPECIFIED_FORMAT);
+      }
+      if (hasCurrency(elem)) {
+        writer.die(elem, NO_CURRENCY_WITH_FORMAT);
+      }
+      return format;
+    }
+    if (predefinedFormat != null) {
+      if (customFormat != null) {
+        writer.die(elem, AT_MOST_ONE_SPECIFIED_FORMAT);
+      }
+      if ("CURRENCY".equals(predefinedFormat)) {
+        String currency = consumeCurrency(elem, writer);
+        return NumberFormat.class.getCanonicalName() + ".getCurrencyFormat("
+            + (currency != null ? currency : "") + ")";
+      }
+      if (hasCurrency(elem)) {
+        writer.die(elem, NO_CURRENCY_WITH_PREDEFINED_FORMAT);
+      }
+      String f = predefinedFormats.get(predefinedFormat);
+      if (f == null) {
+        writer.die(elem, UNKNOWN_PREDEFINED_FORMAT, predefinedFormat);
+      }
+      return f;
+    }
+    if (customFormat != null) {
+      String currency = consumeCurrency(elem, writer);
+      return NumberFormat.class.getCanonicalName() + ".getFormat(" + customFormat
+          + (currency != null ? ", " + currency : "") + ")";
+    }
+    if (hasCurrency(elem)) {
+      writer.die(elem, NO_CURRENCY_WITHOUT_SPECIFIED_FORMAT);
+    }
+    return null;
+  }
+
+  private boolean hasCurrency(XMLElement elem) {
+    return elem.hasAttribute("currencyData")
+        || elem.hasAttribute("currencyCode");
+  }
+
+  private boolean hasNumberFormatConstructor(TypeOracle typeOracle,
+      JClassType type) {
+    JType numberFormatType = typeOracle.findType(NumberFormat.class.getName());
+    return type.findConstructor(new JType[] {numberFormatType}) != null;
+  }
+}
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
index bc5c3a3..4297a32 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderParser.java
@@ -264,10 +264,10 @@
     /* Perhaps it is provided via @UiField */
 
     if (ownerField != null) {
-      if (!resourceType.equals(ownerField.getType().getRawType())) {
+      if (!resourceType.getErasedType().equals(ownerField.getType().getRawType()
+          .getErasedType())) {
         writer.die(elem, "Type must match %s", ownerField);
       }
-
       if (ownerField.isProvided()) {
         String initializer;
         if (writer.getDesignTime().isDesignTime()) {
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index e807ac6..a7589b5 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -998,6 +998,8 @@
     addWidgetParser("ListBox");
     addWidgetParser("Grid");
     addWidgetParser("HasAlignment");
+    addWidgetParser("DateLabel");
+    addWidgetParser("NumberLabel");
   }
 
   /**
diff --git a/user/src/com/google/gwt/user/client/ui/CheckBox.java b/user/src/com/google/gwt/user/client/ui/CheckBox.java
index 75635ee..3549e0d 100644
--- a/user/src/com/google/gwt/user/client/ui/CheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/CheckBox.java
@@ -59,6 +59,7 @@
     HasWordWrap, IsEditor<LeafValueEditor<Boolean>> {
   InputElement inputElem;
   LabelElement labelElem;
+  private LeafValueEditor<Boolean> editor;
   private boolean valueChangeHandlerInitialized;
 
   /**
@@ -134,7 +135,10 @@
   }
 
   public LeafValueEditor<Boolean> asEditor() {
-    return TakesValueEditor.of(this);
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
   }
 
   /**
@@ -172,7 +176,7 @@
   /**
    * Determines whether this check box is currently checked.
    * <p>
-   * Note that this <em>is not</em> return the value property of the checkbox
+   * Note that this <em>does not</em> return the value property of the checkbox
    * input element wrapped by this widget. For access to that property, see
    * {@link #getFormValue()}
    * 
diff --git a/user/src/com/google/gwt/user/client/ui/DateLabel.java b/user/src/com/google/gwt/user/client/ui/DateLabel.java
new file mode 100644
index 0000000..0c925a8
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/DateLabel.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.TimeZone;
+import com.google.gwt.text.client.DateTimeFormatRenderer;
+
+import java.util.Date;
+
+/**
+ * Extends {@link ValueLabel} for convenience when dealing with dates and
+ * {@link DateTimeFormat}, especially in
+ * {@link com.google.gwt.uibinder.client.UiBinder UiBinder} templates. (Note
+ * that this class does not accept renderers. To do so use {@link ValueLabel}
+ * directly.)
+ * 
+ * <h3>Use in UiBinder Templates</h3>
+ * In {@link com.google.gwt.uibinder.client.UiBinder UiBinder} templates, both the format and time zone can be configured.
+ * <p>
+ * The format can be given with one of these attributes:
+ * <dl>
+ * <dt>format</dt><dd>a reference to a {@link DateTimeFormat} instance.</dd>
+ * <dt>predefinedFormat</dt><dd>a {@link DateTimeFormat.PredefinedFormat}.</dd>
+ * <dt>customFormat</dt><dd>a date time pattern that can be passed to {@link DateTimeFormat#getFormat(String)}.</dd>
+ * </dl>
+ * <p>
+ * The time zone can be specified with either of these attributes:
+ * <dl>
+ * <dt>timezone</dt><dd>a reference to a {@link TimeZone} instance.</dd>
+ * <dt>timezoneOffset</dt><dd>the time zone offset in minutes.</dd>
+ * </dl>
+ */
+public class DateLabel extends ValueLabel<Date> {
+
+  public DateLabel() {
+    super(new DateTimeFormatRenderer());
+  }
+
+  public DateLabel(DateTimeFormat format) {
+    super(new DateTimeFormatRenderer(format));
+  }
+
+  public DateLabel(DateTimeFormat format, TimeZone timeZone) {
+    super(new DateTimeFormatRenderer(format, timeZone));
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/Hidden.java b/user/src/com/google/gwt/user/client/ui/Hidden.java
index fcd978b..d9f1466 100644
--- a/user/src/com/google/gwt/user/client/ui/Hidden.java
+++ b/user/src/com/google/gwt/user/client/ui/Hidden.java
@@ -18,11 +18,15 @@
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.editor.client.IsEditor;
+import com.google.gwt.editor.client.LeafValueEditor;
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
+import com.google.gwt.user.client.TakesValue;
 
 /**
  * Represents a hidden field in an HTML form.
  */
-public class Hidden extends Widget implements HasName {
+public class Hidden extends Widget implements HasName, TakesValue<String>, IsEditor<LeafValueEditor<String>> {
 
   /**
    * Creates a Hidden widget that wraps an existing &lt;input type='hidden'&gt;
@@ -47,6 +51,8 @@
     return hidden;
   }
 
+  private LeafValueEditor<String> editor;
+
   /**
    * Constructor for <code>Hidden</code>.
    */
@@ -87,6 +93,13 @@
     setElement(element);
   }
 
+  public LeafValueEditor<String> asEditor() {
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
+  }
+
   /**
    * Gets the default value of the hidden field.
    * 
diff --git a/user/src/com/google/gwt/user/client/ui/Label.java b/user/src/com/google/gwt/user/client/ui/Label.java
index a2ab4bc..29bb577 100644
--- a/user/src/com/google/gwt/user/client/ui/Label.java
+++ b/user/src/com/google/gwt/user/client/ui/Label.java
@@ -59,7 +59,6 @@
 import com.google.gwt.i18n.client.BidiUtils;
 import com.google.gwt.i18n.client.HasDirection;
 import com.google.gwt.i18n.shared.DirectionEstimator;
-import com.google.gwt.i18n.shared.HasDirectionEstimator;
 
 /**
  * A widget that contains arbitrary text, <i>not</i> interpreted as HTML.
@@ -86,10 +85,10 @@
  * </p>
  */
 @SuppressWarnings("deprecation")
-public class Label extends Widget implements HasDirectionalText, HasWordWrap,
+public class Label extends LabelBase<String> implements HasDirectionalText,
     HasDirection, HasClickHandlers, HasDoubleClickHandlers, SourcesClickEvents,
-    SourcesMouseEvents, HasAllGestureHandlers, HasAllMouseHandlers, HasAllTouchHandlers,
-    HasDirectionEstimator, HasAutoHorizontalAlignment, IsEditor<LeafValueEditor<String>> {
+    SourcesMouseEvents, HasAllGestureHandlers, HasAllMouseHandlers,
+    HasAllTouchHandlers, IsEditor<LeafValueEditor<String>> {
 
   public static final DirectionEstimator DEFAULT_DIRECTION_ESTIMATOR =
       DirectionalTextHelper.DEFAULT_DIRECTION_ESTIMATOR;
@@ -117,29 +116,14 @@
     return label;
   }
 
-  /**
-   * The widget's DirectionalTextHelper object.
-   */
-  final DirectionalTextHelper directionalTextHelper;
-
-  /**
-   * The widget's auto horizontal alignment policy.
-   * @see HasAutoHorizontalAlignment
-   */
-  private AutoHorizontalAlignmentConstant autoHorizontalAlignment;
-  
-  /**
-   * The widget's horizontal alignment.
-   */
-  private HorizontalAlignmentConstant horzAlign;
+  private LeafValueEditor<String> editor;
 
   /**
    * Creates an empty label.
    */
   public Label() {
-    setElement(Document.get().createDivElement());
+    super(false);
     setStyleName("gwt-Label");
-    directionalTextHelper = new DirectionalTextHelper(getElement(), false);
   }
 
   /**
@@ -196,12 +180,7 @@
    * @param element the element to be used
    */
   protected Label(Element element) {
-    setElement(element);
-    String tagName = element.getTagName();
-    boolean isElementInline = tagName.equalsIgnoreCase("span");
-    assert isElementInline || tagName.equalsIgnoreCase("div");
-    directionalTextHelper = new DirectionalTextHelper(getElement(),
-        isElementInline);
+    super(element);
   }
 
   public HandlerRegistration addClickHandler(ClickHandler handler) {
@@ -291,14 +270,10 @@
   }
   
   public LeafValueEditor<String> asEditor() {
-    return HasTextEditor.of(this);
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public AutoHorizontalAlignmentConstant getAutoHorizontalAlignment() {
-    return autoHorizontalAlignment;
+    if (editor == null) {
+      editor = HasTextEditor.of(this);
+    }
+    return editor;
   }
 
   /**
@@ -310,17 +285,6 @@
     return BidiUtils.getDirectionOnElement(getElement());
   }
 
-  public DirectionEstimator getDirectionEstimator() {
-    return directionalTextHelper.getDirectionEstimator();
-  }
-
-  /**
-   * {@inheritDoc}
-   */
-  public HorizontalAlignmentConstant getHorizontalAlignment() {
-    return horzAlign;
-  }
-
   public String getText() {
     return directionalTextHelper.getTextOrHtml(false);
   }
@@ -329,10 +293,6 @@
     return directionalTextHelper.getTextDirection();
   }
 
-  public boolean getWordWrap() {
-    return !getElement().getStyle().getProperty("whiteSpace").equals("nowrap");
-  }
-
   /**
    * @deprecated Use the {@link HandlerRegistration#removeHandler} method on
    * the object returned by {@link #addClickHandler} instead
@@ -361,15 +321,6 @@
   }
 
   /**
-   * {@inheritDoc}
-   */
-  public void setAutoHorizontalAlignment(AutoHorizontalAlignmentConstant
-      autoAlignment) {
-    autoHorizontalAlignment = autoAlignment;
-    updateHorizontalAlignment();
-  }
-
-  /**
    * Sets the widget element's direction.
    * @deprecated Use {@link #setDirectionEstimator} and / or pass explicit
    * direction to {@link #setText} instead
@@ -381,44 +332,6 @@
   }
 
   /**
-   * {@inheritDoc}
-   * <p>
-   * See note at {@link #setDirectionEstimator(DirectionEstimator)}.
-   */
-  public void setDirectionEstimator(boolean enabled) {
-    directionalTextHelper.setDirectionEstimator(enabled);
-    updateHorizontalAlignment();
-  }
-
-  /**
-   * {@inheritDoc}
-   * <p>
-   * Note: DirectionEstimator should be set before the widget has any content;
-   * it's highly recommended to set it using a constructor. Reason: if the
-   * widget already has non-empty content, this will update its direction
-   * according to the new estimator's result. This may cause flicker, and thus
-   * should be avoided.
-   */
-  public void setDirectionEstimator(DirectionEstimator directionEstimator) {
-    directionalTextHelper.setDirectionEstimator(directionEstimator);
-    updateHorizontalAlignment();
-  }
-
-  /**
-   * {@inheritDoc}
-   *
-   * <p> Note: A subsequent call to {@link #setAutoHorizontalAlignment} may
-   * override the horizontal alignment set by this method.
-   * <p> Note: For {@code null}, the horizontal alignment is cleared, allowing
-   * it to be determined by the standard HTML mechanisms such as inheritance and
-   * CSS rules.
-   * @see #setAutoHorizontalAlignment
-   */
-  public void setHorizontalAlignment(HorizontalAlignmentConstant align) {
-    setAutoHorizontalAlignment(align);
-  }
-
-  /**
    * Sets the label's content to the given text.
    * <p>
    * Doesn't change the widget's direction or horizontal alignment if {@code
@@ -457,36 +370,4 @@
     directionalTextHelper.setTextOrHtml(text, dir, false);
     updateHorizontalAlignment();
   }
-
-  public void setWordWrap(boolean wrap) {
-    getElement().getStyle().setProperty("whiteSpace",
-        wrap ? "normal" : "nowrap");
-  }
-
-  /**
-   * Sets the horizontal alignment of the widget according to the current
-   * AutoHorizontalAlignment setting. Should be invoked whenever the horizontal
-   * alignment may be affected, i.e. on every modification of the content or its
-   * direction.
-   */
-  protected void updateHorizontalAlignment() {
-    HorizontalAlignmentConstant align;
-    if (autoHorizontalAlignment == null) {
-      align = null;
-    } else if (autoHorizontalAlignment instanceof HorizontalAlignmentConstant) {
-      align = (HorizontalAlignmentConstant) autoHorizontalAlignment;
-    } else {
-      /* autoHorizontalAlignment is a truly automatic policy, i.e. either
-      ALIGN_CONTENT_START or ALIGN_CONTENT_END */
-      align = autoHorizontalAlignment == ALIGN_CONTENT_START ?
-          HorizontalAlignmentConstant.startOf(getTextDirection()) :
-          HorizontalAlignmentConstant.endOf(getTextDirection());
-    }
-
-    if (align != horzAlign) {
-      horzAlign = align;
-      getElement().getStyle().setProperty("textAlign", horzAlign == null ? ""
-          : horzAlign.getTextAlignString());
-    }
-  }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/Label.java.rej b/user/src/com/google/gwt/user/client/ui/Label.java.rej
new file mode 100644
index 0000000..975186f
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/Label.java.rej
@@ -0,0 +1,15 @@
+--- user/src/com/google/gwt/user/client/ui/Label.java	(revision 9255)
++++ user/src/com/google/gwt/user/client/ui/Label.java	(working copy)
+@@ -69,10 +68,8 @@
+  * </p>
+  */
+ @SuppressWarnings("deprecation")
+-public class Label extends Widget implements HasDirectionalText, HasWordWrap,
+-    HasDirection, HasClickHandlers, HasDoubleClickHandlers, SourcesClickEvents,
+-    SourcesMouseEvents, HasAllMouseHandlers, HasDirectionEstimator,
+-    HasAutoHorizontalAlignment, IsEditor<LeafValueEditor<String>> {
++public class Label extends LabelBase<String> implements HasDirectionalText, HasDirection, HasClickHandlers, HasDoubleClickHandlers, SourcesClickEvents,
++    SourcesMouseEvents, HasAllMouseHandlers, IsEditor<LeafValueEditor<String>> {
+ 
+   public static final DirectionEstimator DEFAULT_DIRECTION_ESTIMATOR =
+       DirectionalTextHelper.DEFAULT_DIRECTION_ESTIMATOR;
diff --git a/user/src/com/google/gwt/user/client/ui/LabelBase.java b/user/src/com/google/gwt/user/client/ui/LabelBase.java
new file mode 100644
index 0000000..4f15d3f
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/LabelBase.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.i18n.shared.DirectionEstimator;
+import com.google.gwt.i18n.shared.HasDirectionEstimator;
+
+/**
+ * Abstract base class for all text display widgets.
+ * 
+ * <h3>Use in UiBinder Templates</h3>
+ * 
+ * @param <T> the value type
+ */
+public class LabelBase<T> extends Widget implements HasWordWrap,
+    HasDirectionEstimator, HasAutoHorizontalAlignment {
+
+  /**
+   * The widget's DirectionalTextHelper object.
+   */
+  final DirectionalTextHelper directionalTextHelper;
+
+  /**
+   * The widget's auto horizontal alignment policy.
+   * 
+   * @see HasAutoHorizontalAlignment
+   */
+  private AutoHorizontalAlignmentConstant autoHorizontalAlignment;
+
+  /**
+   * The widget's horizontal alignment.
+   */
+  private HorizontalAlignmentConstant horzAlign;
+
+  protected LabelBase(boolean inline) {
+    this(inline ? Document.get().createSpanElement()
+        : Document.get().createDivElement(), inline);
+  }
+
+  protected LabelBase(Element element) {
+    this(element, "span".equalsIgnoreCase(element.getTagName()));
+  }
+
+  private LabelBase(Element element, boolean isElementInline) {
+    assert (isElementInline ? "span" : "div").equalsIgnoreCase(element.getTagName());
+    setElement(element);
+    directionalTextHelper = new DirectionalTextHelper(getElement(),
+        isElementInline);
+  }
+
+  public AutoHorizontalAlignmentConstant getAutoHorizontalAlignment() {
+    return autoHorizontalAlignment;
+  }
+
+  public DirectionEstimator getDirectionEstimator() {
+    return directionalTextHelper.getDirectionEstimator();
+  }
+
+  public HorizontalAlignmentConstant getHorizontalAlignment() {
+    return horzAlign;
+  }
+
+  public boolean getWordWrap() {
+    return !getElement().getStyle().getProperty("whiteSpace").equals("nowrap");
+  }
+
+  public void setAutoHorizontalAlignment(
+      AutoHorizontalAlignmentConstant autoAlignment) {
+    autoHorizontalAlignment = autoAlignment;
+    updateHorizontalAlignment();
+  }
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * See note at {@link #setDirectionEstimator(DirectionEstimator)}.
+   */
+  public void setDirectionEstimator(boolean enabled) {
+    directionalTextHelper.setDirectionEstimator(enabled);
+    updateHorizontalAlignment();
+  }
+
+  /**
+   * {@inheritDoc}
+   * <p>
+   * Note: DirectionEstimator should be set before the widget has any content;
+   * it's highly recommended to set it using a constructor. Reason: if the
+   * widget already has non-empty content, this will update its direction
+   * according to the new estimator's result. This may cause flicker, and thus
+   * should be avoided.
+   */
+  public void setDirectionEstimator(DirectionEstimator directionEstimator) {
+    directionalTextHelper.setDirectionEstimator(directionEstimator);
+    updateHorizontalAlignment();
+  }
+
+  /**
+   * {@inheritDoc}
+   * 
+   * <p>
+   * Note: A subsequent call to {@link #setAutoHorizontalAlignment} may override
+   * the horizontal alignment set by this method.
+   * <p>
+   * Note: For {@code null}, the horizontal alignment is cleared, allowing it to
+   * be determined by the standard HTML mechanisms such as inheritance and CSS
+   * rules.
+   * 
+   * @see #setAutoHorizontalAlignment
+   */
+  public void setHorizontalAlignment(HorizontalAlignmentConstant align) {
+    setAutoHorizontalAlignment(align);
+  }
+
+  public void setWordWrap(boolean wrap) {
+    getElement().getStyle().setProperty("whiteSpace",
+        wrap ? "normal" : "nowrap");
+  }
+
+  /**
+   * Sets the horizontal alignment of the widget according to the current
+   * AutoHorizontalAlignment setting. Should be invoked whenever the horizontal
+   * alignment may be affected, i.e. on every modification of the content or its
+   * direction.
+   */
+  protected void updateHorizontalAlignment() {
+    HorizontalAlignmentConstant align;
+    if (autoHorizontalAlignment == null) {
+      align = null;
+    } else if (autoHorizontalAlignment instanceof HorizontalAlignmentConstant) {
+      align = (HorizontalAlignmentConstant) autoHorizontalAlignment;
+    } else {
+      /*
+       * autoHorizontalAlignment is a truly automatic policy, i.e. either
+       * ALIGN_CONTENT_START or ALIGN_CONTENT_END
+       */
+      align = autoHorizontalAlignment == ALIGN_CONTENT_START
+          ? HorizontalAlignmentConstant.startOf(directionalTextHelper.getTextDirection())
+          : HorizontalAlignmentConstant.endOf(directionalTextHelper.getTextDirection());
+    }
+
+    if (align != horzAlign) {
+      horzAlign = align;
+      getElement().getStyle().setProperty("textAlign",
+          horzAlign == null ? "" : horzAlign.getTextAlignString());
+    }
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/NumberLabel.java b/user/src/com/google/gwt/user/client/ui/NumberLabel.java
new file mode 100644
index 0000000..ad398ca
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/NumberLabel.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.text.client.NumberFormatRenderer;
+
+/**
+ * Extends {@link ValueLabel} for convenience when dealing with numbers and
+ * {@link NumberFormat}, especially in
+ * {@link com.google.gwt.uibinder.client.UiBinder UiBinder} templates. (Note
+ * that this class does not accept renderers. To do so use {@link ValueLabel}
+ * directly.)
+ * 
+ * <h3>Use in UiBinder Templates</h3> In
+ * {@link com.google.gwt.uibinder.client.UiBinder UiBinder} templates, the
+ * {@link NumberFormat} can be specified with one of these attributes:
+ * <dl>
+ * <dt>format</dt>
+ * <dd>a reference to a {@link NumberFormat} instance.</dd>
+ * <dt>predefinedFormat</dt>
+ * <dd>a predefined format (see below for the list of acceptable values).</dd>
+ * <dt>customFormat</dt>
+ * <dd>a number format pattern that can be passed to
+ * {@link NumberFormat#getFormat(String)}. See below for a way of specifying a
+ * currency code.</dd>
+ * </dl>
+ * The valid values for the {@code predefinedFormat} attributes are:
+ * <dl>
+ * <dt>DECIMAL</dt>
+ * <dd>the standard decimal format for the current locale, as given by
+ * {@link NumberFormat#getDecimalFormat()}.</dd>
+ * <dt>CURRENCY</dt>
+ * <dd>the standard currency format for the current locale, as given by
+ * {@link NumberFormat#getCurrencyFormat()}. See below for a way of specifying a
+ * currency code.</dd>
+ * <dt>PERCENT</dt>
+ * <dd>the standard percent format for the current locale, as given by
+ * {@link NumberFormat#getPercentFormat()}.</dd>
+ * <dt>SCIENTIFIC</dt>
+ * <dd>the standard scientific format for the current locale, as given by
+ * {@link NumberFormat#getScientificFormat()}.</dd>
+ * </dl>
+ * When using {@code predefinedFormat="CURRENCY"} or a {@code customFormat}, you
+ * can specify a currency code using either of the following attributes:
+ * <dl>
+ * <dt>currencyData</dt>
+ * <dd>a reference to a {@link com.google.gwt.i18n.client.CurrencyData
+ * CurrencyData} instance.</dd>
+ * <dt>currencyCode</dt>
+ * <dd>an ISO4217 currency code.</dd>
+ * </dl>
+ * 
+ * @param <T> The exact type of number
+ */
+public class NumberLabel<T extends Number> extends ValueLabel<T> {
+
+  public NumberLabel() {
+    super(new NumberFormatRenderer());
+  }
+
+  public NumberLabel(NumberFormat format) {
+    super(new NumberFormatRenderer(format));
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/SimpleCheckBox.java b/user/src/com/google/gwt/user/client/ui/SimpleCheckBox.java
index 4bc465c..4975554 100644
--- a/user/src/com/google/gwt/user/client/ui/SimpleCheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SimpleCheckBox.java
@@ -18,6 +18,10 @@
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.InputElement;
+import com.google.gwt.editor.client.IsEditor;
+import com.google.gwt.editor.client.LeafValueEditor;
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
+import com.google.gwt.user.client.TakesValue;
 
 /**
  * A simple checkbox widget, with no label.
@@ -28,7 +32,8 @@
  * <li>.gwt-SimpleCheckBox-disabled { Applied when checkbox is disabled }</li>
  * </ul>
  */
-public class SimpleCheckBox extends FocusWidget implements HasName {
+public class SimpleCheckBox extends FocusWidget implements HasName,
+    TakesValue<Boolean>, IsEditor<LeafValueEditor<Boolean>> {
 
   /**
    * Creates a SimpleCheckBox widget that wraps an existing &lt;input
@@ -53,6 +58,8 @@
     return checkBox;
   }
 
+  private LeafValueEditor<Boolean> editor;
+
   /**
    * Creates a new simple checkbox.
    */
@@ -79,28 +86,66 @@
     }
   }
 
+  public LeafValueEditor<Boolean> asEditor() {
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
+  }
+
+  /**
+   * Returns the value property of the input element that backs this widget.
+   * This is the value that will be associated with the check box name and
+   * submitted to the server if a {@link FormPanel} that holds it is submitted
+   * and the box is checked.
+   * <p>
+   * Don't confuse this with {@link #getValue}, which returns true or false if
+   * the widget is checked.
+   */
+  public String getFormValue() {
+    return getInputElement().getValue();
+  }
+
   public String getName() {
     return getInputElement().getName();
   }
 
   /**
    * Determines whether this check box is currently checked.
+   * <p>
+   * Note that this <em>does not</em> return the value property of the checkbox
+   * input element wrapped by this widget. For access to that property, see
+   * {@link #getFormValue()}
    * 
-   * @return <code>true</code> if the check box is checked
+   * @return <code>true</code> if the check box is checked, false otherwise.
+   *         Will not return null
    */
-  public boolean isChecked() {
+  public Boolean getValue() {
     String propName = isAttached() ? "checked" : "defaultChecked";
     return getInputElement().getPropertyBoolean(propName);
   }
 
   /**
+   * Determines whether this check box is currently checked.
+   * 
+   * @return <code>true</code> if the check box is checked
+   * @deprecated Use {@link #getValue} instead
+   */
+  @Deprecated
+  public boolean isChecked() {
+    // Funny comparison b/c getValue could in theory return null
+    return getValue() == true;
+  }
+
+  /**
    * Checks or unchecks this check box.
    * 
    * @param checked <code>true</code> to check the check box
+   * @deprecated Use {@link #setValue(Boolean)} instead
    */
+  @Deprecated
   public void setChecked(boolean checked) {
-    getInputElement().setChecked(checked);
-    getInputElement().setDefaultChecked(checked);
+    setValue(checked);
   }
 
   @Override
@@ -113,18 +158,50 @@
     }
   }
 
+  /**
+   * Set the value property on the input element that backs this widget. This is
+   * the value that will be associated with the check box's name and submitted
+   * to the server if a {@link FormPanel} that holds it is submitted and the box
+   * is checked.
+   * <p>
+   * Don't confuse this with {@link #setValue}, which actually checks and
+   * unchecks the box.
+   * 
+   * @param value
+   */
+  public void setFormValue(String value) {
+    getInputElement().setAttribute("value", value);
+  }
+
   public void setName(String name) {
     getInputElement().setName(name);
   }
 
   /**
+   * Checks or unchecks the check box.
+   * <p>
+   * Note that this <em>does not</em> set the value property of the checkbox
+   * input element wrapped by this widget. For access to that property, see
+   * {@link #setFormValue(String)}
+   * 
+   * @param value true to check, false to uncheck; null value implies false
+   */
+  public void setValue(Boolean value) {
+    if (value == null) {
+      value = Boolean.FALSE;
+    }
+
+    getInputElement().setChecked(value);
+    getInputElement().setDefaultChecked(value);
+  }
+
+  /**
    * This method is called when a widget is detached from the browser's
-   * document. Overridden because of IE bug that throws away checked state and
-   * in order to clear the event listener off of the <code>inputElem</code>.
+   * document. Overridden because of IE bug that throws away checked state.
    */
   @Override
   protected void onUnload() {
-    setChecked(isChecked());
+    setValue(getValue());
   }
 
   private InputElement getInputElement() {
diff --git a/user/src/com/google/gwt/user/client/ui/SuggestBox.java b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
index 26c63d7..a95bb5a 100644
--- a/user/src/com/google/gwt/user/client/ui/SuggestBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
@@ -674,6 +674,7 @@
   private boolean selectsFirstItem = true;
   private SuggestOracle oracle;
   private String currentText;
+  private LeafValueEditor<String> editor;
   private final SuggestionDisplay display;
   private final TextBoxBase box;
   private final Callback callback = new Callback() {
@@ -831,7 +832,10 @@
    * Returns a {@link TakesValueEditor} backed by the DateBox.
    */
   public LeafValueEditor<String> asEditor() {
-    return TakesValueEditor.of(this);
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
   }
 
   /**
diff --git a/user/src/com/google/gwt/user/client/ui/ToggleButton.java b/user/src/com/google/gwt/user/client/ui/ToggleButton.java
index 3ce977b..b337f3f 100644
--- a/user/src/com/google/gwt/user/client/ui/ToggleButton.java
+++ b/user/src/com/google/gwt/user/client/ui/ToggleButton.java
@@ -16,6 +16,9 @@
 
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.editor.client.IsEditor;
+import com.google.gwt.editor.client.LeafValueEditor;
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
 import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.logical.shared.ValueChangeEvent;
 import com.google.gwt.event.logical.shared.ValueChangeHandler;
@@ -40,9 +43,11 @@
  * <h3>Example</h3> {@example com.google.gwt.examples.ToggleButtonExample}
  * </p>
  */
-public class ToggleButton extends CustomButton implements HasValue<Boolean> {
+public class ToggleButton extends CustomButton implements HasValue<Boolean>, IsEditor<LeafValueEditor<Boolean>> {
   private static String STYLENAME_DEFAULT = "gwt-ToggleButton";
 
+  private LeafValueEditor<Boolean> editor;
+
   {
     setStyleName(STYLENAME_DEFAULT);
   }
@@ -182,6 +187,13 @@
     return addHandler(handler, ValueChangeEvent.getType());
   }
 
+  public LeafValueEditor<Boolean> asEditor() {
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
+  }
+
   /**
    * Determines whether this button is currently down.
    * 
diff --git a/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java b/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java
index d24f2a3..05d416e 100644
--- a/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java
+++ b/user/src/com/google/gwt/user/client/ui/ValueBoxBase.java
@@ -45,7 +45,6 @@
  * 
  * @param <T> the value type
  */
-@SuppressWarnings("deprecation")
 public class ValueBoxBase<T> extends FocusWidget implements
     HasChangeHandlers, HasName, HasDirectionEstimator,
     HasValue<T>, AutoDirectionHandler.Target, IsEditor<ValueBoxEditor<T>> {
@@ -83,6 +82,7 @@
 
   private final Parser<T> parser;
   private final Renderer<T> renderer;
+  private ValueBoxEditor<T> editor;
   private Event currentEvent;
 
   private boolean valueChangeHandlerInitialized;
@@ -125,7 +125,10 @@
    * Editor framework.
    */
   public ValueBoxEditor<T> asEditor() {
-    return ValueBoxEditor.of(this);
+    if (editor == null) {
+      editor = ValueBoxEditor.of(this);
+    }
+    return editor;
   }
 
   /**
diff --git a/user/src/com/google/gwt/user/client/ui/ValueLabel.java b/user/src/com/google/gwt/user/client/ui/ValueLabel.java
new file mode 100644
index 0000000..92e29db
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/ValueLabel.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.editor.client.IsEditor;
+import com.google.gwt.editor.client.LeafValueEditor;
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
+import com.google.gwt.text.shared.Parser;
+import com.google.gwt.text.shared.Renderer;
+import com.google.gwt.uibinder.client.UiConstructor;
+import com.google.gwt.user.client.TakesValue;
+
+import java.text.ParseException;
+
+/**
+ * A label displaying its value through a renderer.
+ * 
+ * @param <T> the value type.
+ */
+public class ValueLabel<T> extends LabelBase<T> implements TakesValue<T>,
+    IsEditor<LeafValueEditor<T>> {
+
+  /**
+   * Creates a ValueLabel widget that wraps an existing &lt;span&gt; element.
+   * <p>
+   * The ValueLabel's value will be <code>null</code>, whether the element being
+   * wrapped has content or not. Use {@link #wrap(Element, Renderer, Parser)} to
+   * parse the initial element's content to initialize the ValueLabel's value.
+   * <p>
+   * This element must already be attached to the document. If the element is
+   * removed from the document, you must call
+   * {@link RootPanel#detachNow(Widget)}.
+   * 
+   * @param element the element to be wrapped
+   * @param renderer the renderer used to render values into the element
+   */
+  public static <T> ValueLabel<T> wrap(Element element,
+      Renderer<? super T> renderer) {
+    // Assert that the element is attached.
+    assert Document.get().getBody().isOrHasChild(element);
+
+    ValueLabel<T> label = new ValueLabel<T>(element, renderer);
+
+    // Mark it attached and remember it for cleanup.
+    label.onAttach();
+    RootPanel.detachOnWindowClose(label);
+
+    return label;
+  }
+
+  /**
+   * Creates a ValueLabel widget that wraps an existing &lt;span&gt; element.
+   * <p>
+   * The ValueLabel's value will be initialized with the element's content,
+   * passed through the <code>parser</code>.
+   * <p>
+   * This element must already be attached to the document. If the element is
+   * removed from the document, you must call
+   * {@link RootPanel#detachNow(Widget)}.
+   * 
+   * @param element the element to be wrapped
+   * @param renderer the renderer used to render values into the element
+   * @param parser the parser used to initialize the ValueLabel's value from the
+   *          element's content
+   */
+  public static <T> ValueLabel<T> wrap(Element element,
+      Renderer<? super T> renderer, Parser<? extends T> parser)
+      throws ParseException {
+    ValueLabel<T> label = wrap(element, renderer);
+
+    label.setValue(parser.parse(element.getInnerText()));
+
+    // Mark it attached and remember it for cleanup.
+    label.onAttach();
+    RootPanel.detachOnWindowClose(label);
+
+    return label;
+  }
+
+  private final Renderer<? super T> renderer;
+  private T value;
+  private LeafValueEditor<T> editor;
+
+  /**
+   * Creates an empty value label.
+   * 
+   * @param inline
+   * @param renderer
+   */
+  @UiConstructor
+  public ValueLabel(Renderer<? super T> renderer) {
+    super(true);
+    this.renderer = renderer;
+  }
+
+  /**
+   * This constructor may be used by subclasses to explicitly use an existing
+   * element. This element must be either a &lt;span&gt; or a &lt;div&gt;
+   * element.
+   * 
+   * @param element the element to be used
+   */
+  protected ValueLabel(Element element, Renderer<? super T> renderer) {
+    super(element);
+    this.renderer = renderer;
+  }
+
+  public LeafValueEditor<T> asEditor() {
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
+  }
+
+  public T getValue() {
+    return value;
+  }
+
+  public void setValue(T value) {
+    this.value = value;
+    directionalTextHelper.setTextOrHtml(renderer.render(value), false);
+    updateHorizontalAlignment();
+  }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/client/ui/ValueListBox.java b/user/src/com/google/gwt/user/client/ui/ValueListBox.java
index 24b8b93..4fffa9a 100644
--- a/user/src/com/google/gwt/user/client/ui/ValueListBox.java
+++ b/user/src/com/google/gwt/user/client/ui/ValueListBox.java
@@ -49,6 +49,7 @@
   private final Renderer<T> renderer;
   private final ProvidesKey<T> keyProvider;
 
+  private TakesValueEditor<T> editor;
   private T value;
 
   public ValueListBox(Renderer<T> renderer) {
@@ -81,7 +82,10 @@
    * Returns a {@link TakesValueEditor} backed by the ValueListBox.
    */
   public TakesValueEditor<T> asEditor() {
-    return TakesValueEditor.of(this);
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
   }
 
   public T getValue() {
diff --git a/user/src/com/google/gwt/user/client/ui/ValuePicker.java b/user/src/com/google/gwt/user/client/ui/ValuePicker.java
index 8003cec..7ec9259 100644
--- a/user/src/com/google/gwt/user/client/ui/ValuePicker.java
+++ b/user/src/com/google/gwt/user/client/ui/ValuePicker.java
@@ -56,6 +56,7 @@
 
   private final CellList<T> cellList;
   private SingleSelectionModel<T> smodel = new SingleSelectionModel<T>();
+  private LeafValueEditor<T> editor;
 
   public ValuePicker(CellList<T> cellList) {
     this.cellList = cellList;
@@ -80,7 +81,10 @@
    * Returns a {@link TakesValueEditor} backed by the ValuePicker.
    */
   public LeafValueEditor<T> asEditor() {
-    return TakesValueEditor.of(this);
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
   }
 
   /**
diff --git a/user/src/com/google/gwt/user/datepicker/client/DateBox.java b/user/src/com/google/gwt/user/datepicker/client/DateBox.java
index c9ebf25..3d6b25b 100644
--- a/user/src/com/google/gwt/user/datepicker/client/DateBox.java
+++ b/user/src/com/google/gwt/user/datepicker/client/DateBox.java
@@ -249,6 +249,7 @@
   private final PopupPanel popup;
   private final TextBox box = new TextBox();
   private final DatePicker picker;
+  private LeafValueEditor<Date> editor;
   private Format format;
   private boolean allowDPShow = true;
 
@@ -298,7 +299,10 @@
    * Returns a {@link TakesValueEditor} backed by the DateBox.
    */
   public LeafValueEditor<Date> asEditor() {
-    return TakesValueEditor.of(this);
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
   }
 
   /**
diff --git a/user/src/com/google/gwt/user/datepicker/client/DatePicker.java b/user/src/com/google/gwt/user/datepicker/client/DatePicker.java
index ddb55a4..439875a 100644
--- a/user/src/com/google/gwt/user/datepicker/client/DatePicker.java
+++ b/user/src/com/google/gwt/user/datepicker/client/DatePicker.java
@@ -253,6 +253,7 @@
   private Date value;
   private Date highlighted;
   private StandardCss css = StandardCss.DEFAULT;
+  private LeafValueEditor<Date> editor;
 
   /**
    * Create a new date picker.
@@ -381,7 +382,10 @@
    * Returns a {@link TakesValueEditor} backed by the DatePicker.
    */
   public LeafValueEditor<Date> asEditor() {
-    return TakesValueEditor.of(this);
+    if (editor == null) {
+      editor = TakesValueEditor.of(this);
+    }
+    return editor;
   }
 
   /**
diff --git a/user/test/com/google/gwt/text/TextSuite.java b/user/test/com/google/gwt/text/TextSuite.java
index cfe30d3..d14d55f 100644
--- a/user/test/com/google/gwt/text/TextSuite.java
+++ b/user/test/com/google/gwt/text/TextSuite.java
@@ -20,6 +20,7 @@
 import com.google.gwt.text.client.DoubleParserTest;
 import com.google.gwt.text.client.IntegerParserTest;
 import com.google.gwt.text.client.LongParserTest;
+import com.google.gwt.text.client.NumberFormatRendererTest;
 
 import junit.framework.Test;
 
@@ -34,6 +35,7 @@
     suite.addTestSuite(DoubleParserTest.class);
     suite.addTestSuite(IntegerParserTest.class);
     suite.addTestSuite(LongParserTest.class);
+    suite.addTestSuite(NumberFormatRendererTest.class);
     return suite;
   }
 }
diff --git a/user/test/com/google/gwt/text/client/NumberFormatRendererTest.java b/user/test/com/google/gwt/text/client/NumberFormatRendererTest.java
new file mode 100644
index 0000000..f57c016
--- /dev/null
+++ b/user/test/com/google/gwt/text/client/NumberFormatRendererTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.text.client;
+
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Eponymous unit test.
+ */
+public class NumberFormatRendererTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.text.TextSuite";
+  }
+
+  public void testDefault() {
+    assertEquals(NumberFormat.getDecimalFormat().format(Math.PI),
+        new NumberFormatRenderer().render(Math.PI));
+  }
+
+  public void testScientific() {
+    assertEquals(
+        NumberFormat.getScientificFormat().format(Math.PI),
+        new NumberFormatRenderer(NumberFormat.getScientificFormat()).render(Math.PI));
+  }
+
+  public void testNull() {
+    assertEquals("", new NumberFormatRenderer().render(null));
+  }
+}
diff --git a/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java b/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
index bdceca6..5436f36 100644
--- a/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
+++ b/user/test/com/google/gwt/uibinder/UiBinderJreSuite.java
@@ -26,6 +26,7 @@
 import com.google.gwt.uibinder.attributeparsers.TextAlignConstantParserTest;
 import com.google.gwt.uibinder.attributeparsers.VerticalAlignmentConstantParserTest;
 import com.google.gwt.uibinder.elementparsers.AbsolutePanelParserTest;
+import com.google.gwt.uibinder.elementparsers.DateLabelParserTest;
 import com.google.gwt.uibinder.elementparsers.DialogBoxParserTest;
 import com.google.gwt.uibinder.elementparsers.DisclosurePanelParserTest;
 import com.google.gwt.uibinder.elementparsers.DockLayoutPanelParserTest;
@@ -36,6 +37,7 @@
 import com.google.gwt.uibinder.elementparsers.ListBoxParserTest;
 import com.google.gwt.uibinder.elementparsers.MenuBarParserTest;
 import com.google.gwt.uibinder.elementparsers.MenuItemParserTest;
+import com.google.gwt.uibinder.elementparsers.NumberLabelParserTest;
 import com.google.gwt.uibinder.elementparsers.StackLayoutPanelParserTest;
 import com.google.gwt.uibinder.elementparsers.StackPanelParserTest;
 import com.google.gwt.uibinder.elementparsers.TabLayoutPanelParserTest;
@@ -88,6 +90,7 @@
 
     // elementparsers
     suite.addTestSuite(AbsolutePanelParserTest.class);
+    suite.addTestSuite(DateLabelParserTest.class);
     suite.addTestSuite(DialogBoxParserTest.class);
     suite.addTestSuite(DisclosurePanelParserTest.class);
     suite.addTestSuite(DockLayoutPanelParserTest.class);
@@ -98,6 +101,7 @@
     suite.addTestSuite(ListBoxParserTest.class);
     suite.addTestSuite(MenuBarParserTest.class);
     suite.addTestSuite(MenuItemParserTest.class);
+    suite.addTestSuite(NumberLabelParserTest.class);
     suite.addTestSuite(StackLayoutPanelParserTest.class);
     suite.addTestSuite(StackPanelParserTest.class);
     suite.addTestSuite(TabLayoutPanelParserTest.class);
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/DateLabelParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/DateLabelParserTest.java
new file mode 100644
index 0000000..131f614
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/elementparsers/DateLabelParserTest.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.uibinder.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.TimeZone;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
+import com.google.gwt.uibinder.rebind.FieldWriter;
+import com.google.gwt.user.client.ui.DateLabel;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Eponymous unit test.
+ */
+public class DateLabelParserTest extends TestCase {
+  private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.DateLabel";
+
+  private static final MockJavaResource DATELABEL_SUBCLASS_NO_CONSTRUCTOR = new MockJavaResource(
+      "my.MyDateLabel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package my;\n");
+      code.append("import com.google.gwt.user.client.ui.DateLabel;\n");
+      code.append("public class MyDateLabel extends DateLabel {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  private static final MockJavaResource DATELABEL_SUBCLASS_FORMAT_CONSTRUCTOR = new MockJavaResource(
+      "my.MyConstructedDateLabel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package my;\n");
+      code.append("import com.google.gwt.user.client.ui.DateLabel;\n");
+      code.append("import com.google.gwt.i18n.client.DateTimeFormat;\n");
+      code.append("public class MyConstructedDateLabel extends DateLabel {\n");
+      code.append("  public MyConstructedDateLabel(DateTimeFormat f) { super(f); }");
+      code.append("}\n");
+      return code;
+    }
+  };
+  private static final MockJavaResource DATELABEL_SUBCLASS_FORMAT_AND_TZ_CONSTRUCTOR = new MockJavaResource(
+      "my.MyConstructedDateLabel2") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package my;\n");
+      code.append("import com.google.gwt.user.client.ui.DateLabel;\n");
+      code.append("import com.google.gwt.i18n.client.DateTimeFormat;\n");
+      code.append("import com.google.gwt.i18n.client.TimeZone;\n");
+      code.append("public class MyConstructedDateLabel2 extends DateLabel {\n");
+      code.append("  public MyConstructedDateLabel2(DateTimeFormat f, TimeZone tz) { super(f, tz); }");
+      code.append("}\n");
+      return code;
+    }
+  };
+  private static final MockJavaResource DATELABEL_SUBCLASS_TZ_CONSTRUCTOR = new MockJavaResource(
+      "my.MyConstructedDateLabel3") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package my;\n");
+      code.append("import com.google.gwt.user.client.ui.DateLabel;\n");
+      code.append("import com.google.gwt.i18n.client.TimeZone;\n");
+      code.append("public class MyConstructedDateLabel3 extends DateLabel {\n");
+      code.append("  public MyConstructedDateLabel3(TimeZone tz) { super(); }");
+      code.append("}\n");
+      return code;
+    }
+  };
+  private ElementParserTester tester;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    tester = new ElementParserTester(PARSED_TYPE, new DateLabelParser());
+  }
+
+  public void testHappyWithDefaultInstantiableSubclass()
+      throws UnableToCompleteException, SAXException {
+    tester = new ElementParserTester("my.MyDateLabel", new DateLabelParser(),
+        DATELABEL_SUBCLASS_NO_CONSTRUCTOR);
+    DateLabelParser parser = new DateLabelParser();
+    StringBuffer b = new StringBuffer();
+
+    b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+    b.append("    xmlns:my='urn:import:my'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <my:MyDateLabel format='{someDateTimeFormat}' timezone='{someTimeZone}' /> ");
+    b.append("</ui:UiBinder>");
+
+    parser.parse(tester.getElem(b.toString(), "my:MyDateLabel"), "fieldName",
+        tester.parsedType, tester.writer);
+    FieldWriter w = tester.fieldManager.lookup("fieldName");
+    assertNull(w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithSubclassWithDateTimeFormatConstructor()
+      throws UnableToCompleteException, SAXException {
+    DateLabelParser parser = new DateLabelParser();
+    tester = new ElementParserTester("my.MyConstructedDateLabel",
+        new DateLabelParser(), DATELABEL_SUBCLASS_FORMAT_CONSTRUCTOR);
+
+    StringBuffer b = new StringBuffer();
+
+    b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+    b.append("    xmlns:my='urn:import:my'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <my:MyConstructedDateLabel format='{someDateTimeFormat}' timezone='{someTimeZone}' /> ");
+    b.append("</ui:UiBinder>");
+
+    parser.parse(tester.getElem(b.toString(), "my:MyConstructedDateLabel"),
+        "fieldName", tester.parsedType, tester.writer);
+    FieldWriter w = tester.fieldManager.lookup("fieldName");
+    assertEquals("new my.MyConstructedDateLabel(someDateTimeFormat)",
+        w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithSubclassWithDateTimeFormatAndTimeZoneConstructor()
+      throws UnableToCompleteException, SAXException {
+    DateLabelParser parser = new DateLabelParser();
+    tester = new ElementParserTester("my.MyConstructedDateLabel2",
+        new DateLabelParser(), DATELABEL_SUBCLASS_FORMAT_AND_TZ_CONSTRUCTOR);
+
+    StringBuffer b = new StringBuffer();
+
+    b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+    b.append("    xmlns:my='urn:import:my'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <my:MyConstructedDateLabel2 format='{someDateTimeFormat}' timezone='{someTimeZone}' /> ");
+    b.append("</ui:UiBinder>");
+
+    parser.parse(tester.getElem(b.toString(), "my:MyConstructedDateLabel2"),
+        "fieldName", tester.parsedType, tester.writer);
+    FieldWriter w = tester.fieldManager.lookup("fieldName");
+    assertEquals(
+        "new my.MyConstructedDateLabel2(someDateTimeFormat, someTimeZone)",
+        w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithSubclassWithTimeZoneFormatConstructor()
+      throws UnableToCompleteException, SAXException {
+    DateLabelParser parser = new DateLabelParser();
+    tester = new ElementParserTester("my.MyConstructedDateLabel3",
+        new DateLabelParser(), DATELABEL_SUBCLASS_TZ_CONSTRUCTOR);
+
+    StringBuffer b = new StringBuffer();
+
+    b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+    b.append("    xmlns:my='urn:import:my'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <my:MyConstructedDateLabel3 format='{someDateTimeFormat}' timezone='{someTimeZone}' /> ");
+    b.append("</ui:UiBinder>");
+
+    parser.parse(tester.getElem(b.toString(), "my:MyConstructedDateLabel3"),
+        "fieldName", tester.parsedType, tester.writer);
+    FieldWriter w = tester.fieldManager.lookup("fieldName");
+    assertNull(w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithNoFormat() throws UnableToCompleteException,
+      SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DateLabel>");
+    b.append("</g:DateLabel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertNull(w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithPredefinedFormat() throws UnableToCompleteException,
+      SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DateLabel predefinedFormat='DATE_MEDIUM'>");
+    b.append("</g:DateLabel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + DateLabel.class.getCanonicalName() + "("
+        + DateTimeFormat.class.getCanonicalName() + ".getFormat("
+        + PredefinedFormat.class.getCanonicalName() + ".DATE_MEDIUM))",
+        w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithTimezoneOffset() throws UnableToCompleteException,
+      SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DateLabel customFormat='zzzz' timezoneOffset='-7200'>");
+    b.append("</g:DateLabel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + DateLabel.class.getCanonicalName() + "("
+        + DateTimeFormat.class.getCanonicalName() + ".getFormat(\"zzzz\"), "
+        + TimeZone.class.getCanonicalName() + ".createTimeZone(-7200))",
+        w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testChokeOnNonDateTimeFormat() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DateLabel format='someString' >");
+    b.append("</g:DateLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect to hear about DateTimeFormat",
+          tester.logger.died.contains("DateTimeFormat"));
+    }
+  }
+
+  public void testChokeOnNonTimeZone() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DateLabel format='{someDateTimeFormat}' timezone='someString' >");
+    b.append("</g:DateLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect to hear about TimeZone",
+          tester.logger.died.contains("TimeZone"));
+    }
+  }
+
+  public void testChokeOnUnknownPredefinedFormat() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DateLabel predefinedFormat='someString' >");
+    b.append("</g:DateLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect to hear about PredefinedFormat",
+          tester.logger.died.contains("PredefinedFormat"));
+    }
+  }
+
+  public void testChokeOnMultipleFormats() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DateLabel predefinedFormat='DATE_FULL' customFormat='MM/dd'>");
+    b.append("</g:DateLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue(
+          tester.logger.died,
+          tester.logger.died.contains(DateLabelParser.AT_MOST_ONE_SPECIFIED_FORMAT));
+    }
+  }
+
+  public void testChokeOnMultipleTimeZones() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DateLabel format='{someDateTimeFormat}' timezone='{someTimeZone}' timezoneOffset='-7200'>");
+    b.append("</g:DateLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue(
+          tester.logger.died,
+          tester.logger.died.contains(DateLabelParser.AT_MOST_ONE_SPECIFIED_TIME_ZONE));
+    }
+  }
+
+  public void testChokeOnTimeZoneWithoutSpecifiedFormat() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:DateLabel timezoneOffset='-7200'>");
+    b.append("</g:DateLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue(
+          tester.logger.died,
+          tester.logger.died.contains(DateLabelParser.NO_TIMEZONE_WITHOUT_SPECIFIED_FORMAT));
+    }
+  }
+}
diff --git a/user/test/com/google/gwt/uibinder/elementparsers/NumberLabelParserTest.java b/user/test/com/google/gwt/uibinder/elementparsers/NumberLabelParserTest.java
new file mode 100644
index 0000000..41fff15
--- /dev/null
+++ b/user/test/com/google/gwt/uibinder/elementparsers/NumberLabelParserTest.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2010 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.uibinder.elementparsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.uibinder.rebind.FieldWriter;
+import com.google.gwt.user.client.ui.NumberLabel;
+
+import junit.framework.TestCase;
+
+import org.xml.sax.SAXException;
+
+/**
+ * Eponymous unit test.
+ */
+public class NumberLabelParserTest extends TestCase {
+  private static final String PARSED_TYPE = "com.google.gwt.user.client.ui.NumberLabel";
+
+  private static final MockJavaResource NUMBERLABEL_SUBCLASS_NO_CONSTRUCTOR = new MockJavaResource(
+      "my.MyNumberLabel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package my;\n");
+      code.append("import com.google.gwt.user.client.ui.NumberLabel;\n");
+      code.append("public class MyNumberLabel extends NumberLabel {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  private static final MockJavaResource NUMBERLABEL_SUBCLASS_FORMAT_CONSTRUCTOR = new MockJavaResource(
+      "my.MyConstructedNumberLabel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package my;\n");
+      code.append("import com.google.gwt.user.client.ui.NumberLabel;\n");
+      code.append("import com.google.gwt.i18n.client.NumberFormat;\n");
+      code.append("public class MyConstructedNumberLabel extends NumberLabel {\n");
+      code.append("  public MyConstructedNumberLabel(NumberFormat f) { super(f); }");
+      code.append("}\n");
+      return code;
+    }
+  };
+  private ElementParserTester tester;
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    tester = new ElementParserTester(PARSED_TYPE, new NumberLabelParser());
+  }
+
+  public void testHappyWithDefaultInstantiableSubclass()
+      throws UnableToCompleteException, SAXException {
+    tester = new ElementParserTester("my.MyNumberLabel",
+        new NumberLabelParser(), NUMBERLABEL_SUBCLASS_NO_CONSTRUCTOR);
+    NumberLabelParser parser = new NumberLabelParser();
+    StringBuffer b = new StringBuffer();
+
+    b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+    b.append("    xmlns:my='urn:import:my'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <my:MyNumberLabel format='{someDateTimeFormat}' currencyData='{someCurrencyData}' /> ");
+    b.append("</ui:UiBinder>");
+
+    parser.parse(tester.getElem(b.toString(), "my:MyNumberLabel"), "fieldName",
+        tester.parsedType, tester.writer);
+    FieldWriter w = tester.fieldManager.lookup("fieldName");
+    assertNull(w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithSubclassWithNumberFormatConstructor()
+      throws UnableToCompleteException, SAXException {
+    NumberLabelParser parser = new NumberLabelParser();
+    tester = new ElementParserTester("my.MyConstructedNumberLabel",
+        new NumberLabelParser(), NUMBERLABEL_SUBCLASS_FORMAT_CONSTRUCTOR);
+
+    StringBuffer b = new StringBuffer();
+
+    b.append("<ui:UiBinder xmlns:ui='" + ElementParserTester.BINDER_URI + "'");
+    b.append("    xmlns:my='urn:import:my'");
+    b.append("    xmlns:g='urn:import:com.google.gwt.user.client.ui'>");
+    b.append("  <my:MyConstructedNumberLabel format='{someDateTimeFormat}' /> ");
+    b.append("</ui:UiBinder>");
+
+    parser.parse(tester.getElem(b.toString(), "my:MyConstructedNumberLabel"),
+        "fieldName", tester.parsedType, tester.writer);
+    FieldWriter w = tester.fieldManager.lookup("fieldName");
+    assertEquals("new my.MyConstructedNumberLabel(someDateTimeFormat)",
+        w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithNoFormat() throws UnableToCompleteException,
+      SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel>");
+    b.append("</g:NumberLabel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertNull(w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithCustomFormatAndCurrency()
+      throws UnableToCompleteException, SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel customFormat='#\u00A0\u00A4' currencyCode='EUR'>");
+    b.append("</g:NumberLabel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + NumberLabel.class.getCanonicalName() + "("
+        + NumberFormat.class.getCanonicalName() + ".getFormat(\"#\u00A0\u00A4\", \"EUR\"))",
+        w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithCurrencyPredefinedFormat()
+      throws UnableToCompleteException, SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel predefinedFormat='CURRENCY'>");
+    b.append("</g:NumberLabel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + NumberLabel.class.getCanonicalName() + "("
+        + NumberFormat.class.getCanonicalName() + ".getCurrencyFormat())",
+        w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testHappyWithCurrencyPredefinedFormatAndCurrencCode()
+      throws UnableToCompleteException, SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel predefinedFormat='CURRENCY' currencyCode='EUR'>");
+    b.append("</g:NumberLabel>");
+
+    FieldWriter w = tester.parse(b.toString());
+    assertEquals("new " + NumberLabel.class.getCanonicalName() + "("
+        + NumberFormat.class.getCanonicalName() + ".getCurrencyFormat(\"EUR\"))",
+        w.getInitializer());
+
+    assertTrue(tester.writer.statements.isEmpty());
+    assertNull(tester.logger.died);
+  }
+
+  public void testChokeOnNonDateTimeFormat() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel format='someString' >");
+    b.append("</g:NumberLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect to hear about DateTimeFormat",
+          tester.logger.died.contains("DateTimeFormat"));
+    }
+  }
+
+  public void testChokeOnNonCurrencyData() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel predefinedFormat='CURRENCY' currencyData='someString' >");
+    b.append("</g:NumberLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue("Expect to hear about CurrencyData",
+          tester.logger.died.contains("CurrencyData"));
+    }
+  }
+
+  public void testChokeOnUnknownPredefinedFormat() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel predefinedFormat='someString' >");
+    b.append("</g:NumberLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue(tester.logger.died, tester.logger.died.contains(String.format(
+          NumberLabelParser.UNKNOWN_PREDEFINED_FORMAT, "someString")));
+    }
+  }
+
+  public void testChokeOnMultipleFormats() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel predefinedFormat='SCIENTIFIC' customFormat='#'>");
+    b.append("</g:NumberLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue(
+          tester.logger.died,
+          tester.logger.died.contains(NumberLabelParser.AT_MOST_ONE_SPECIFIED_FORMAT));
+    }
+  }
+
+  public void testChokeOnMultipleCurrencies() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel predefinedFormat='CURRENCY' currencyData='{someCurrencyData}' currencyCode='EUR'>");
+    b.append("</g:NumberLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue(
+          tester.logger.died,
+          tester.logger.died.contains(NumberLabelParser.AT_MOST_ONE_SPECIFIED_CURRENCY));
+    }
+  }
+
+  public void testChokeOnCurrencyWithoutSpecifiedFormat() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel currencyCode='EUR'>");
+    b.append("</g:NumberLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue(
+          tester.logger.died,
+          tester.logger.died.contains(NumberLabelParser.NO_CURRENCY_WITHOUT_SPECIFIED_FORMAT));
+    }
+  }
+
+  public void testChokeOnCurrencyWithPredefinedFormat() throws SAXException {
+    StringBuffer b = new StringBuffer();
+    b.append("<g:NumberLabel predefinedFormat='PERCENT' currencyCode='EUR'>");
+    b.append("</g:NumberLabel>");
+
+    try {
+      tester.parse(b.toString());
+      fail();
+    } catch (UnableToCompleteException e) {
+      assertTrue(
+          tester.logger.died,
+          tester.logger.died.contains(NumberLabelParser.NO_CURRENCY_WITH_PREDEFINED_FORMAT));
+    }
+  }
+}
diff --git a/user/test/com/google/gwt/uibinder/test/UiJavaResources.java b/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
index 91852ee..ad1280a 100644
--- a/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
+++ b/user/test/com/google/gwt/uibinder/test/UiJavaResources.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2009 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
@@ -19,6 +19,7 @@
 import com.google.gwt.dev.javac.impl.MockJavaResource;
 import com.google.gwt.dev.resource.Resource;
 import com.google.gwt.dev.util.collect.HashSet;
+import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
 
 import java.util.Arrays;
 import java.util.Set;
@@ -95,6 +96,53 @@
       return code;
     }
   };
+  public static final MockJavaResource CURRENCY_DATA = new MockJavaResource(
+      "com.google.gwt.i18n.client.CurrencyData") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.i18n.client;\n");
+      code.append("public class CurrencyData {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  public static final MockJavaResource DATE_LABEL = new MockJavaResource(
+      "com.google.gwt.user.client.ui.DateLabel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("import com.google.gwt.i18n.client.DateTimeFormat;\n");
+      code.append("import com.google.gwt.i18n.client.TimeZone;\n");
+      code.append("public class DateLabel extends ValueLabel {\n");
+      code.append("  public DateLabel() { super(null); } ");
+      code.append("  public DateLabel(DateTimeFormat format) { super(null); } ");
+      code.append("  public DateLabel(DateTimeFormat format, TimeZone timeZone) { super(null); } ");
+      code.append("}\n");
+      return code;
+    }
+  };
+  public static final MockJavaResource DATE_TIME_FORMAT = new MockJavaResource(
+      "com.google.gwt.i18n.client.DateTimeFormat") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.i18n.client;\n");
+      code.append("public class DateTimeFormat {\n");
+      code.append("  public static enum PredefinedFormat {\n");
+      PredefinedFormat[] values = PredefinedFormat.values();
+      for (int i = 0; i < values.length; i++) {
+        code.append("    ").append(values[i].name());
+        if (i < values.length - 1) {
+          code.append(",\n");
+        }
+      }
+      code.append("  }\n");
+      code.append("}\n");
+      return code;
+    }
+  };
   public static final MockJavaResource DIALOG_BOX = new MockJavaResource(
       "com.google.gwt.user.client.ui.DialogBox") {
     @Override
@@ -352,6 +400,42 @@
       return code;
     }
   };
+  public static final MockJavaResource NUMBER_LABEL = new MockJavaResource(
+      "com.google.gwt.user.client.ui.NumberLabel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("import com.google.gwt.i18n.client.NumberFormat;\n");
+      code.append("public class NumberLabel extends ValueLabel {\n");
+      code.append("  public NumberLabel() { super(null); } ");
+      code.append("  public NumberLabel(NumberFormat format) { super(null); } ");
+      code.append("}\n");
+      return code;
+    }
+  };
+  public static final MockJavaResource NUMBER_FORMAT = new MockJavaResource(
+      "com.google.gwt.i18n.client.NumberFormat") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.i18n.client;\n");
+      code.append("public class NumberFormat {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
+  public static final MockJavaResource RENDERER = new MockJavaResource(
+      "com.google.gwt.text.shared.Renderer") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.text.shared;\n");
+      code.append("public class Renderer<T> {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
   public static final MockJavaResource SPLIT_LAYOUT_PANEL = new MockJavaResource(
       "com.google.gwt.user.client.ui.SplitLayoutPanel") {
     @Override
@@ -432,6 +516,17 @@
       return code;
     }
   };
+  public static final MockJavaResource TIME_ZONE = new MockJavaResource(
+      "com.google.gwt.i18n.client.TimeZone") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.i18n.client;\n");
+      code.append("public class TimeZone {\n");
+      code.append("}\n");
+      return code;
+    }
+  };
   public static final MockJavaResource UI_BINDER = new MockJavaResource(
       "com.google.gwt.uibinder.client.UiBinder") {
     @Override
@@ -467,6 +562,19 @@
       return code;
     }
   };
+  public static final MockJavaResource VALUE_LABEL = new MockJavaResource(
+      "com.google.gwt.user.client.ui.ValueLabel") {
+    @Override
+    protected CharSequence getContent() {
+      StringBuffer code = new StringBuffer();
+      code.append("package com.google.gwt.user.client.ui;\n");
+      code.append("import com.google.gwt.text.shared.Renderer;\n");
+      code.append("public class ValueLabel extends Widget {\n");
+      code.append("  public ValueLabel(Renderer renderer) {} ");
+      code.append("}\n");
+      return code;
+    }
+  };
   public static final MockJavaResource WIDGET = new MockJavaResource(
       "com.google.gwt.user.client.ui.Widget") {
     @Override
@@ -491,6 +599,9 @@
     rtn.add(CLICK_EVENT);
     rtn.add(CLICK_HANDLER);
     rtn.add(COMMAND);
+    rtn.add(CURRENCY_DATA);
+    rtn.add(DATE_LABEL);
+    rtn.add(DATE_TIME_FORMAT);
     rtn.add(DIALOG_BOX);
     rtn.add(DISCLOSURE_PANEL);
     rtn.add(DOCK_LAYOUT_PANEL);
@@ -512,6 +623,9 @@
     rtn.add(MENU_ITEM_SEPARATOR);
     rtn.add(MOUSE_OVER_EVENT);
     rtn.add(MOUSE_OVER_HANDLER);
+    rtn.add(NUMBER_LABEL);
+    rtn.add(NUMBER_FORMAT);
+    rtn.add(RENDERER);
     rtn.add(SPLIT_LAYOUT_PANEL);
     rtn.add(STACK_LAYOUT_PANEL);
     rtn.add(STACK_PANEL);
@@ -519,9 +633,11 @@
     rtn.add(TAB_LAYOUT_PANEL);
     rtn.add(TAB_PANEL);
     rtn.add(TEXT_BOX_BASE);
+    rtn.add(TIME_ZONE);
     rtn.add(UI_OBJECT);
     rtn.add(UI_BINDER);
     rtn.add(UI_FACTORY);
+    rtn.add(VALUE_LABEL);
     rtn.add(WIDGET);
     return rtn;
   }
diff --git a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
index 7201ea0..74426a9 100644
--- a/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
+++ b/user/test/com/google/gwt/uibinder/test/client/UiBinderTest.java
@@ -28,14 +28,17 @@
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.ui.AbsolutePanel;
 import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.DateLabel;
 import com.google.gwt.user.client.ui.DisclosurePanel;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.HTMLPanel;
 import com.google.gwt.user.client.ui.Image;
 import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.NamedFrame;
+import com.google.gwt.user.client.ui.NumberLabel;
 import com.google.gwt.user.client.ui.RadioButton;
 import com.google.gwt.user.client.ui.StackPanel;
+import com.google.gwt.user.client.ui.ValueLabel;
 import com.google.gwt.user.client.ui.Widget;
 
 /**
@@ -469,6 +472,21 @@
     assertNotNull("NamedFrame exists", p);
   }
 
+  public void testDateLabel() {
+    DateLabel p = widgetUi.myDateLabel;
+    assertNotNull("DateLabel exists", p);
+  }
+
+  public void testNumberLabel() {
+    NumberLabel<Float> p = widgetUi.myNumberLabel;
+    assertNotNull("NumberLabel exists", p);
+  }
+
+  public void testValueLabel() {
+    ValueLabel<Double> p = widgetUi.myValueLabel;
+    assertNotNull("ValueLabel exists", p);
+  }
+
   public void testStringAttributeIgnoresStaticSetter() {
     // Assumes setPopupText() is overloaded such that there is a static
     // setPopupText(Foo, String) method.
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
index 766ce98..9cd127e 100644
--- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
+++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.java
@@ -27,12 +27,15 @@
 import com.google.gwt.resources.client.DataResource;
 import com.google.gwt.resources.client.ImageResource;
 import com.google.gwt.resources.client.CssResource.Shared;
+import com.google.gwt.text.client.DoubleRenderer;
+import com.google.gwt.text.shared.Renderer;
 import com.google.gwt.uibinder.client.UiBinder;
 import com.google.gwt.uibinder.client.UiFactory;
 import com.google.gwt.uibinder.client.UiField;
 import com.google.gwt.user.client.ui.AbsolutePanel;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.DateLabel;
 import com.google.gwt.user.client.ui.DisclosurePanel;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.HTML;
@@ -45,11 +48,13 @@
 import com.google.gwt.user.client.ui.MenuBar;
 import com.google.gwt.user.client.ui.MenuItem;
 import com.google.gwt.user.client.ui.NamedFrame;
+import com.google.gwt.user.client.ui.NumberLabel;
 import com.google.gwt.user.client.ui.PushButton;
 import com.google.gwt.user.client.ui.RadioButton;
 import com.google.gwt.user.client.ui.StackPanel;
 import com.google.gwt.user.client.ui.ToggleButton;
 import com.google.gwt.user.client.ui.Tree;
+import com.google.gwt.user.client.ui.ValueLabel;
 import com.google.gwt.user.client.ui.Widget;
 
 /**
@@ -171,6 +176,11 @@
   @UiField Widget myAbsolutePanelItemB;
   @UiField Widget myAbsolutePanelItemC;
   @UiField NamedFrame myNamedFrame;
+  @UiField DateLabel myDateLabel;
+  @UiField NumberLabel<Float> myNumberLabel;
+  @UiField(provided = true) @SuppressWarnings("unchecked")
+  Renderer doubleRenderer = DoubleRenderer.instance();
+  @UiField ValueLabel<Double> myValueLabel;
 
   public WidgetBasedUi() {
     external.style().ensureInjected();
diff --git a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
index b4d3710..08a6b83 100644
--- a/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
+++ b/user/test/com/google/gwt/uibinder/test/client/WidgetBasedUi.ui.xml
@@ -72,6 +72,10 @@
   for a resource to provide arbitrary objects to arbitrary attributes (look for FooLabel)
 </ui:with>
 
+<ui:with field='doubleRenderer' type='com.google.gwt.text.shared.Renderer'>
+  Used to test ValueLabel's @UiConstructor
+</ui:with>
+
 <ui:import field='com.google.gwt.uibinder.test.client.Constants.CONST_FOO'>
   Tests the static import of a single constant into the local namespace.
 </ui:import>
@@ -83,6 +87,7 @@
 <ui:import field='com.google.gwt.uibinder.test.client.Constants.MyEnum.*'>
   Tests the static import of an enum into the local namespace.
 </ui:import>
+
 <!--
   Tests creating a CssResource from an external file.
  -->
@@ -303,7 +308,8 @@
         <ui:attribute name="text" description="radio button name"/>
       </demo:PointlessRadioButtonSubclass>
 
-        <gwt:HorizontalPanel ui:field="myHorizontalPanel" horizontalAlignment="ALIGN_LEFT" verticalAlignment="ALIGN_MIDDLE">
+        <gwt:HorizontalPanel ui:field="myHorizontalPanel"
+            horizontalAlignment="ALIGN_LEFT" verticalAlignment="ALIGN_MIDDLE">
           <gwt:Cell><gwt:HTMLPanel>
       <p> ... a StackPanel ... </p>
 
@@ -640,6 +646,12 @@
 
   <gwt:NamedFrame ui:field='myNamedFrame' name='myName'/>
 
+  <gwt:DateLabel ui:field='myDateLabel' predefinedFormat='DATE_FULL' />
+
+  <gwt:NumberLabel ui:field='myNumberLabel' predefinedFormat='SCIENTIFIC' />
+
+  <gwt:ValueLabel ui:field='myValueLabel' renderer='{doubleRenderer}' />
+
    </gwt:HTMLPanel>
   </gwt:Dock>
 </gwt:DockPanel>