- Changed Requires/ProvidesLayout => Requires/ProvidesResize; some small doc
additions.
- Added RequiresLayout; moved doc into it.
- Added LayoutPanelExample.
- Added DockLayoutPanel.
- A bit of cleanup here and there.

Review: http://gwt-code-reviews.appspot.com/63801

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6080 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java b/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java
new file mode 100644
index 0000000..31fa1ad
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java
@@ -0,0 +1,51 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.examples;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
+import com.google.gwt.user.client.ui.DockLayoutPanel.Direction;
+
+public class DockLayoutPanelExample implements EntryPoint {
+
+  public void onModuleLoad() {
+    // Attach five widgets to a DockLayoutPanel, one in each direction. Lay
+    // them out in 'em' units.
+    DockLayoutPanel p = new DockLayoutPanel(Unit.EM);
+    p.add(new HTML("north"), Direction.NORTH, 2);
+    p.add(new HTML("south"), Direction.SOUTH, 2);
+    p.add(new HTML("east"), Direction.EAST, 2);
+    p.add(new HTML("west"), Direction.WEST, 2);
+    p.add(new HTML("center"), Direction.CENTER, 2);
+
+    // Note the explicit call to layout(). This is required for the layout to
+    // take effect.
+    p.layout();
+
+    // Attach the LayoutPanel to the RootLayoutPanel. The latter will listen for
+    // resize events on the window to ensure that its children are informed of
+    // possible size changes.
+    RootLayoutPanel rp = RootLayoutPanel.get();
+    rp.add(p);
+
+    // The RootLayoutPanel also requires that its layout() method be explicitly
+    // called for the initial layout to take effect.
+    rp.layout();
+  }
+}
diff --git a/user/javadoc/com/google/gwt/examples/LayoutExample.java b/user/javadoc/com/google/gwt/examples/LayoutExample.java
new file mode 100644
index 0000000..6f5fa86
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/LayoutExample.java
@@ -0,0 +1,63 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.examples;
+
+import static com.google.gwt.dom.client.Style.Unit.EM;
+import static com.google.gwt.dom.client.Style.Unit.PCT;
+import static com.google.gwt.dom.client.Style.Unit.PX;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.layout.client.Layout;
+import com.google.gwt.layout.client.Layout.Layer;
+
+public class LayoutExample implements EntryPoint {
+
+  public void onModuleLoad() {
+    // The following is a very simple example, which constructs a layout around
+    // a parent element, and attaches two child elements that split their
+    // parent's space vertically. It then goes on to animate from the first
+    // state to a horizontal stacking that uses EM units rather than
+    // percentages.
+    Document doc = Document.get();
+    Element parent = doc.createDivElement();
+    doc.getBody().appendChild(parent);
+
+    Layout layout = new Layout(parent);
+    layout.onAttach();
+
+    Element topChild = doc.createDivElement(), bottomChild = doc
+        .createDivElement();
+    Layer topLayer = layout.attachChild(topChild);
+    Layer bottomLayer = layout.attachChild(bottomChild);
+
+    // Stack the two children vertically, meeting at 50%.
+    topLayer.setLeftRight(0, PX, 0, PX);
+    bottomLayer.setLeftRight(0, PX, 0, PX);
+    topLayer.setTopHeight(0, PCT, 50, PCT);
+    bottomLayer.setBottomHeight(0, PCT, 50, PCT);
+    layout.layout();
+
+    // Update the two children to stack horizontally, meeting at 10em.
+    // Also have them animate for 500ms.
+    topLayer.setTopBottom(0, PX, 0, PX);
+    bottomLayer.setTopBottom(0, PX, 0, PX);
+    topLayer.setLeftWidth(0, EM, 10, EM);
+    bottomLayer.setLeftRight(10, EM, 0, EM);
+    layout.layout(500);
+  }
+}
diff --git a/user/javadoc/com/google/gwt/examples/LayoutPanelExample.java b/user/javadoc/com/google/gwt/examples/LayoutPanelExample.java
index f1300f9..3fc43d1 100644
--- a/user/javadoc/com/google/gwt/examples/LayoutPanelExample.java
+++ b/user/javadoc/com/google/gwt/examples/LayoutPanelExample.java
@@ -52,4 +52,4 @@
     // called for the initial layout to take effect.
     rp.layout();
   }
-}
\ No newline at end of file
+}
diff --git a/user/src/com/google/gwt/layout/client/Layout.java b/user/src/com/google/gwt/layout/client/Layout.java
index 032f571..a4efe5e 100644
--- a/user/src/com/google/gwt/layout/client/Layout.java
+++ b/user/src/com/google/gwt/layout/client/Layout.java
@@ -328,11 +328,46 @@
    * </p>
    * 
    * @param child the child to be attached
+   * @param before the child element before which to insert
+   * @return the {@link Layer} associated with the element
+   */
+  public Layer attachChild(Element child, Element before) {
+    return attachChild(child, before, null);
+  }
+
+  /**
+   * Attaches a child element to this layout.
+   * 
+   * <p>
+   * This method will attach the child to the layout, removing it from its
+   * current parent element. Use the {@link Layer} it returns to manipulate the
+   * child.
+   * </p>
+   * 
+   * @param child the child to be attached
    * @param userObject an arbitrary object to be associated with this layer
    * @return the {@link Layer} associated with the element
    */
   public Layer attachChild(Element child, Object userObject) {
-    Element container = impl.attachChild(parentElem, child);
+    return attachChild(child, null, userObject);
+  }
+
+  /**
+   * Attaches a child element to this layout.
+   * 
+   * <p>
+   * This method will attach the child to the layout, removing it from its
+   * current parent element. Use the {@link Layer} it returns to manipulate the
+   * child.
+   * </p>
+   * 
+   * @param child the child to be attached
+   * @param before the child element before which to insert
+   * @param userObject an arbitrary object to be associated with this layer
+   * @return the {@link Layer} associated with the element
+   */
+  public Layer attachChild(Element child, Element before, Object userObject) {
+    Element container = impl.attachChild(parentElem, child, before);
     Layer layer = new Layer(container, child, userObject);
     layers.add(layer);
     return layer;
diff --git a/user/src/com/google/gwt/layout/client/LayoutImpl.java b/user/src/com/google/gwt/layout/client/LayoutImpl.java
index 9eccd0d..cf423fa 100644
--- a/user/src/com/google/gwt/layout/client/LayoutImpl.java
+++ b/user/src/com/google/gwt/layout/client/LayoutImpl.java
@@ -24,6 +24,7 @@
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Overflow;
 import com.google.gwt.dom.client.Style.Position;
 import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.layout.client.Layout.Layer;
@@ -60,20 +61,21 @@
 
   protected DivElement relativeRuler;
 
-  public Element attachChild(Element parent, Element child) {
+  public Element attachChild(Element parent, Element child, Element before) {
     DivElement container = Document.get().createDivElement();
     container.appendChild(child);
 
-    container.getStyle().setProperty("position", "absolute");
-    container.getStyle().setProperty("overflow", "hidden");
+    container.getStyle().setPosition(Position.ABSOLUTE);
+    container.getStyle().setOverflow(Overflow.HIDDEN);
 
     fillParent(child);
 
-    Style style = child.getStyle();
-    style.setWidth(100, Unit.PCT);
-    style.setHeight(100, Unit.PCT);
-
-    parent.appendChild(container);
+    Element beforeContainer = null;
+    if (before != null) {
+      beforeContainer = before.getParentElement();
+      assert beforeContainer.getParentElement() == parent : "Element to insert before must be a sibling";
+    }
+    parent.insertBefore(container, beforeContainer);
     return container;
   }
 
@@ -118,7 +120,7 @@
   }
 
   public void initParent(Element parent) {
-    parent.getStyle().setProperty("position", "relative");
+    parent.getStyle().setPosition(Position.RELATIVE);
     parent.appendChild(relativeRuler = createRuler(EM, EX));
   }
 
diff --git a/user/src/com/google/gwt/layout/client/LayoutImplIE6.java b/user/src/com/google/gwt/layout/client/LayoutImplIE6.java
index d5e3c5d..4a9be19 100644
--- a/user/src/com/google/gwt/layout/client/LayoutImplIE6.java
+++ b/user/src/com/google/gwt/layout/client/LayoutImplIE6.java
@@ -38,6 +38,30 @@
  */
 class LayoutImplIE6 extends LayoutImpl {
 
+  private static boolean isIE6 = isIE6();
+
+  // Stolen and modified from UserAgent.gwt.xml.
+  // TODO(jgw): Get rid of this method, and switch to using soft permutations
+  // once they land in trunk.
+  private static native boolean isIE6() /*-{
+     function makeVersion(result) {
+       return (parseInt(result[1]) * 1000) + parseInt(result[2]);
+     }
+
+     var ua = navigator.userAgent.toLowerCase();
+     if (ua.indexOf("msie") != -1) {
+       var result = /msie ([0-9]+)\.([0-9]+)/.exec(ua);
+       if (result && result.length == 3) {
+         var v = makeVersion(result);
+         if (v < 7000) {
+           return true;
+         }
+       }
+     }
+
+     return false;
+   }-*/;
+
   private static Element createStyleRuler(Element parent) {
     DivElement styleRuler = Document.get().createDivElement();
     DivElement styleInner = Document.get().createDivElement();
@@ -111,13 +135,14 @@
     elem[name] = value;
   }-*/;
 
-  public Element attachChild(Element parent, Element child) {
-    if (!UserAgent.isIE6()) {
-      return super.attachChild(parent, child);
+  @Override
+  public Element attachChild(Element parent, Element child, Element before) {
+    if (!isIE6) {
+      return super.attachChild(parent, child, before);
     }
 
     DivElement container = Document.get().createDivElement();
-    container.appendChild(child);
+    container.insertBefore(child, before);
 
     container.getStyle().setPosition(Position.ABSOLUTE);
     container.getStyle().setOverflow(Overflow.HIDDEN);
@@ -127,13 +152,18 @@
     // the child element, so that measureDecoration(child) will work.
     setPropertyElement(child, "__styleRuler", createStyleRuler(container));
 
-    parent.appendChild(container);
+    Element beforeContainer = null;
+    if (before != null) {
+      beforeContainer = before.getParentElement();
+      assert beforeContainer.getParentElement() == parent : "Element to insert before must be a sibling";
+    }
+    parent.insertBefore(container, beforeContainer);
     return container;
   }
 
   @Override
   public void fillParent(Element elem) {
-    if (!UserAgent.isIE6()) {
+    if (!isIE6) {
       super.fillParent(elem);
       return;
     }
@@ -143,7 +173,7 @@
 
   @Override
   public void finalizeLayout(Element parent) {
-    if (!UserAgent.isIE6()) {
+    if (!isIE6) {
       super.finalizeLayout(parent);
       return;
     }
@@ -156,13 +186,13 @@
   public void initParent(Element parent) {
     super.initParent(parent);
 
-    if (UserAgent.isIE6()) {
+    if (isIE6) {
       setPropertyElement(parent, "__styleRuler", createStyleRuler(parent));
     }
   }
 
   public void layout(Layer layer) {
-    if (!UserAgent.isIE6()) {
+    if (!isIE6) {
       super.layout(layer);
       return;
     }
@@ -173,7 +203,7 @@
 
   @Override
   public void onAttach(Element parent) {
-    if (UserAgent.isIE6()) {
+    if (isIE6) {
       // No need to re-connect layer refs. This will be taken care of
       // automatically in layout().
       initResizeHandler(parent);
@@ -183,7 +213,7 @@
 
   @Override
   public void onDetach(Element parent) {
-    if (UserAgent.isIE6()) {
+    if (isIE6) {
       removeLayerRefs(parent);
       removeResizeHandler(parent);
       removeUnitChangeHandler(relativeRuler);
diff --git a/user/src/com/google/gwt/layout/client/UserAgent.java b/user/src/com/google/gwt/layout/client/UserAgent.java
deleted file mode 100644
index 2127a59..0000000
--- a/user/src/com/google/gwt/layout/client/UserAgent.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.layout.client;
-
-/**
- * User-Agent utility methods used by {@link LayoutImplIE6}.
- * 
- * TODO: Generalize this, move it into a common place, and make it available for
- * use by other classes.
- */
-class UserAgent {
-
-  // Stolen and modified from UserAgent.gwt.xml.
-  public static native boolean isIE6() /*-{
-     function makeVersion(result) {
-       return (parseInt(result[1]) * 1000) + parseInt(result[2]);
-     }
-
-     var ua = navigator.userAgent.toLowerCase();
-     if (ua.indexOf("msie") != -1) {
-       var result = /msie ([0-9]+)\.([0-9]+)/.exec(ua);
-       if (result && result.length == 3) {
-         var v = makeVersion(result);
-         if (v < 7000) {
-           return true;
-         }
-       }
-     }
-
-     return false;
-   }-*/;
-}
diff --git a/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
new file mode 100644
index 0000000..27b2400
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
@@ -0,0 +1,296 @@
+/*
+ * 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
+ * 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.dom.client.Style.Unit;
+import com.google.gwt.layout.client.Layout;
+import com.google.gwt.layout.client.Layout.Layer;
+
+/**
+ * A panel that lays its child widgets out "docked" at its outer edges, and
+ * allows its last widget to take up the remaining space in its center.
+ * 
+ * <p>
+ * Whenever children are added to, or removed from, this panel, you must call
+ * one of {@link #layout()}, {@link #layout(int)}, or
+ * {@link #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)}
+ * to update the panel's layout.
+ * </p>
+ * 
+ * <p>
+ * This widget will <em>only</em> work in standards mode, which requires
+ * that the HTML page in which it is run have an explicit &lt;!DOCTYPE&gt;
+ * declaration.
+ * </p>
+ * 
+ * <p>
+ * NOTE: This class is still very new, and its interface may change without
+ * warning. Use at your own risk.
+ * </p>
+ * 
+ * <p>
+ * <h3>Example</h3>
+ * {@example com.google.gwt.examples.DockLayoutPanelExample}
+ * </p>
+ * 
+ * TODO(jgw): RTL support.
+ */
+public class DockLayoutPanel extends ComplexPanel implements RequiresLayout,
+    RequiresResize, ProvidesResize {
+
+  /**
+   * Used in {@link DockLayoutPanel#add(Widget, Direction, double)} to specify
+   * the direction in which a child widget will be added.
+   */
+  public enum Direction {
+    NORTH, EAST, SOUTH, WEST, CENTER, LINE_START, LINE_END
+  }
+
+  protected static class LayoutData {
+    public Direction direction;
+    public double oldSize, size;
+    public double originalSize;
+    public boolean hidden;
+    public Layer layer;
+
+    public LayoutData(Direction direction, double size, Layer layer) {
+      this.direction = direction;
+      this.size = size;
+      this.layer = layer;
+    }
+  }
+
+  private final Unit unit;
+  private Widget center;
+  private final Layout layout;
+
+  /**
+   * Creates an empty dock panel.
+   * 
+   * @param unit the unit to be used for layout
+   */
+  public DockLayoutPanel(Unit unit) {
+    this.unit = unit;
+
+    setElement(Document.get().createDivElement());
+    layout = new Layout(getElement());
+  }
+
+  /**
+   * Adds a widget to the specified edge of the dock. If the widget is already a
+   * child of this panel, this method behaves as though {@link #remove(Widget)}
+   * had already been called.
+   * 
+   * @param widget the widget to be added
+   * @param direction the widget's direction in the dock
+   * 
+   * @throws IllegalArgumentException when adding to the {@link #CENTER} and
+   *           there is already a different widget there
+   */
+  public void add(Widget widget, Direction direction, double size) {
+    insert(widget, direction, size, null);
+  }
+
+  /**
+   * Adds a widget to the specified edge of the dock. If the widget is already a
+   * child of this panel, this method behaves as though {@link #remove(Widget)}
+   * had already been called.
+   * 
+   * @param widget the widget to be added
+   * @param direction the widget's direction in the dock
+   * @param before the widget before which to insert the new child, or
+   *          <code>null</code> to append
+   * 
+   * @throws IllegalArgumentException when adding to the {@link #CENTER} and
+   *           there is already a different widget there
+   */
+  public void insert(Widget widget, Direction direction, double size,
+      Widget before) {
+    assertIsChild(before);
+
+    // Validation.
+    if (before == null) {
+      assert center == null : "No widget may be added after the CENTER widget";
+    } else {
+      assert direction != Direction.CENTER : "A CENTER widget must always be added last";
+    }
+
+    // Detach new child.
+    widget.removeFromParent();
+
+    // Logical attach.
+    getChildren().add(widget);
+    if (direction == Direction.CENTER) {
+      center = widget;
+    }
+
+    // Physical attach.
+    Layer layer = layout.attachChild(widget.getElement(),
+        (before != null) ? before.getElement() : null, widget);
+    LayoutData data = new LayoutData(direction, size, layer);
+    widget.setLayoutData(data);
+
+    // Adopt.
+    adopt(widget);
+  }
+
+  /**
+   * Gets the layout direction of the given child widget.
+   * 
+   * @param w the widget to be queried
+   * @return the widget's layout direction, or <code>null</code> if it is not a
+   *         child of this panel
+   */
+  public Direction getWidgetDirection(Widget w) {
+    if (w.getParent() != this) {
+      return null;
+    }
+    return ((LayoutData) w.getLayoutData()).direction;
+  }
+
+  public void onResize() {
+    for (Widget child : getChildren()) {
+      if (child instanceof RequiresResize) {
+        ((RequiresResize) child).onResize();
+      }
+    }
+  }
+
+  @Override
+  public boolean remove(Widget w) {
+    boolean removed = super.remove(w);
+    if (removed) {
+      // Clear the center widget.
+      if (w == center) {
+        center = null;
+      }
+
+      LayoutData data = (LayoutData) w.getLayoutData();
+      layout.removeChild(data.layer);
+    }
+
+    return removed;
+  }
+
+  protected Widget getCenter() {
+    return center;
+  }
+
+  protected Unit getUnit() {
+    return unit;
+  }
+
+  @Override
+  protected void onLoad() {
+    layout.onAttach();
+  }
+
+  @Override
+  protected void onUnload() {
+    layout.onDetach();
+  }
+
+  public void layout() {
+    layout(0);
+  }
+
+  public void layout(int duration) {
+    layout(0, null);
+  }
+
+  public void layout(int duration, final Layout.AnimationCallback callback) {
+    int left = 0, top = 0, right = 0, bottom = 0;
+
+    for (Widget child : getChildren()) {
+      LayoutData data = (LayoutData) child.getLayoutData();
+      Layer layer = data.layer;
+
+      switch (data.direction) {
+        case NORTH:
+          layer.setLeftRight(left, unit, right, unit);
+          layer.setTopHeight(top, unit, data.size, unit);
+          top += data.size;
+          break;
+
+        case SOUTH:
+          layer.setLeftRight(left, unit, right, unit);
+          layer.setBottomHeight(bottom, unit, data.size, unit);
+          bottom += data.size;
+          break;
+
+        case WEST:
+          layer.setTopBottom(top, unit, bottom, unit);
+          layer.setLeftWidth(left, unit, data.size, unit);
+          left += data.size;
+          break;
+
+        case EAST:
+          layer.setTopBottom(top, unit, bottom, unit);
+          layer.setRightWidth(right, unit, data.size, unit);
+          right += data.size;
+          break;
+
+        case CENTER:
+          layer.setLeftRight(left, unit, right, unit);
+          layer.setTopBottom(top, unit, bottom, unit);
+          break;
+      }
+    }
+
+    layout.layout(duration, new Layout.AnimationCallback() {
+      public void onAnimationComplete() {
+        for (Widget child : getChildren()) {
+          LayoutData data = (LayoutData) child.getLayoutData();
+          if (data.size != data.oldSize) {
+            data.oldSize = data.size;
+            if (child instanceof RequiresResize) {
+              ((RequiresResize) child).onResize();
+            }
+          }
+
+          if (callback != null) {
+            callback.onAnimationComplete();
+          }
+        }
+      }
+
+      public void onLayout(Layer layer, double progress) {
+        Widget child = (Widget) layer.getUserObject();
+        if (child instanceof RequiresResize) {
+          ((RequiresResize) child).onResize();
+        }
+
+        if (callback != null) {
+          callback.onLayout(layer, progress);
+        }
+      }
+    });
+  }
+
+  /**
+   * TODO(jgw): Is this really the best way to do this?
+   */
+  public Element getContainerElementFor(Widget widget) {
+    assertIsChild(widget);
+    return ((LayoutData)widget.getLayoutData()).layer.getContainerElement();
+  }
+
+  private void assertIsChild(Widget widget) {
+    assert (widget == null) || (widget.getParent() == this) : "TODO";
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/LayoutComposite.java b/user/src/com/google/gwt/user/client/ui/LayoutComposite.java
index f4f5067..f6c9af9 100644
--- a/user/src/com/google/gwt/user/client/ui/LayoutComposite.java
+++ b/user/src/com/google/gwt/user/client/ui/LayoutComposite.java
@@ -16,20 +16,20 @@
 package com.google.gwt.user.client.ui;
 
 /**
- * A {@link Composite} implementation that implements {@link RequiresLayout} and
+ * A {@link Composite} implementation that implements {@link RequiresResize} and
  * automatically delegates that interface's methods to its wrapped widget, which
- * must itself implement {@link RequiresLayout}.
+ * must itself implement {@link RequiresResize}.
  */
-public abstract class LayoutComposite extends Composite implements RequiresLayout {
+public abstract class LayoutComposite extends Composite implements RequiresResize {
 
   @Override
   protected void initWidget(Widget widget) {
-    assert widget instanceof RequiresLayout :
+    assert widget instanceof RequiresResize :
       "LayoutComposite requires that its wrapped widget implement HasLayout";
     super.initWidget(widget);
   }
 
-  public void onLayout() {
-    ((RequiresLayout) getWidget()).onLayout();
+  public void onResize() {
+    ((RequiresResize) getWidget()).onResize();
   }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/LayoutPanel.java b/user/src/com/google/gwt/user/client/ui/LayoutPanel.java
index ddfe76b..4adccbc 100644
--- a/user/src/com/google/gwt/user/client/ui/LayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/LayoutPanel.java
@@ -24,8 +24,15 @@
  * using the {@link Layout} class.
  * 
  * <p>
- * NOTE: This widget will <em>only</em> work in standards mode, which requires
- * that the HTML page in which it is run have an explicit &lt;!DOCTYPE&gt;
+ * Whenever children are added to, or removed from, this panel, you must call
+ * one of {@link #layout()}, {@link #layout(int)}, or
+ * {@link #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)}
+ * to update the panel's layout.
+ * </p>
+ * 
+ * <p>
+ * This widget will <em>only</em> work in standards mode, which requires that
+ * the HTML page in which it is run have an explicit &lt;!DOCTYPE&gt;
  * declaration.
  * </p>
  * 
@@ -40,7 +47,7 @@
  * </p>
  */
 public class LayoutPanel extends ComplexPanel implements RequiresLayout,
-    ProvidesLayout {
+    RequiresResize, ProvidesResize {
 
   private final Layout layout;
 
@@ -84,7 +91,7 @@
    * 
    * <p>
    * After you have made changes to any of the child widgets' constraints, you
-   * must call one of the {@link HasAnimatedLayout} methods for those changes to
+   * must call one of the {@link RequiresLayout} methods for those changes to
    * be reflected visually.
    * </p>
    * 
@@ -96,52 +103,14 @@
     return (Layout.Layer) child.getLayoutData();
   }
 
-  /**
-   * This method, or one of its overloads, must be called whenever any of the
-   * {@link Layout.Layer layers} associated with its children is modified.
-   * 
-   * @see #layout(int)
-   * @see #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)
-   */
   public void layout() {
     layout.layout();
   }
 
-  /**
-   * This method, or one of its overloads, must be called whenever any of the
-   * {@link Layout.Layer layers} associated with its children is modified.
-   * 
-   * <p>
-   * This overload will cause the layout to be updated by animating over a
-   * specified period of time.
-   * </p>
-   * 
-   * @param duration the animation duration, in milliseconds
-   * 
-   * @see #layout()
-   * @see #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)
-   */
   public void layout(int duration) {
     layout.layout(duration);
   }
 
-  /**
-   * This method, or one of its overloads, must be called whenever any of the
-   * {@link Layout.Layer layers} associated with its children is modified.
-   * 
-   * <p>
-   * This overload will cause the layout to be updated by animating over a
-   * specified period of time. In addition, it provides a callback that will be
-   * informed of updates to the layers. This can be used to create more complex
-   * animation effects.
-   * </p>
-   * 
-   * @param duration the animation duration, in milliseconds
-   * @param callback the animation callback
-   * 
-   * @see #layout()
-   * @see #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)
-   */
   public void layout(int duration, final Layout.AnimationCallback callback) {
     layout.layout(duration, new Layout.AnimationCallback() {
       public void onAnimationComplete() {
@@ -155,8 +124,8 @@
         // Inform the child associated with this layer that its size may have
         // changed.
         Widget child = (Widget) layer.getUserObject();
-        if (child instanceof RequiresLayout) {
-          ((RequiresLayout) child).onLayout();
+        if (child instanceof RequiresResize) {
+          ((RequiresResize) child).onResize();
         }
 
         // Chain to the passed callback.
@@ -167,10 +136,10 @@
     });
   }
 
-  public void onLayout() {
+  public void onResize() {
     for (Widget child : getChildren()) {
-      if (child instanceof RequiresLayout) {
-        ((RequiresLayout) child).onLayout();
+      if (child instanceof RequiresResize) {
+        ((RequiresResize) child).onResize();
       }
     }
   }
diff --git a/user/src/com/google/gwt/user/client/ui/ProvidesLayout.java b/user/src/com/google/gwt/user/client/ui/ProvidesResize.java
similarity index 71%
rename from user/src/com/google/gwt/user/client/ui/ProvidesLayout.java
rename to user/src/com/google/gwt/user/client/ui/ProvidesResize.java
index f6e6d07..543eae3 100644
--- a/user/src/com/google/gwt/user/client/ui/ProvidesLayout.java
+++ b/user/src/com/google/gwt/user/client/ui/ProvidesResize.java
@@ -17,24 +17,24 @@
 
 /**
  * This tag interface specifies that the implementing widget will call
- * {@link RequiresLayout#onLayout()} on its children whenever their size may
+ * {@link RequiresResize#onResize()} on its children whenever their size may
  * have changed.
  * 
  * <p>
  * With limited exceptions (such as {@link RootLayoutPanel}), widgets that
- * implement this interface will also implement {@link RequiresLayout}. A typical
- * widget will implement {@link RequiresLayout#onLayout()} like this:
+ * implement this interface will also implement {@link RequiresResize}. A typical
+ * widget will implement {@link RequiresResize#onResize()} like this:
  * 
  * <code>
- * public void onLayout() {
+ * public void onResize() {
  *   for (Widget child : getChildren()) {
- *     if (child instanceof RequiresLayout) {
- *       ((RequiresLayout) child).onLayout();
+ *     if (child instanceof RequiresResize) {
+ *       ((RequiresResize) child).onResize();
  *     }
  *   }
  * }
  * </code>
  * </p>
  */
-public interface ProvidesLayout {
+public interface ProvidesResize {
 }
diff --git a/user/src/com/google/gwt/user/client/ui/RequiresLayout.java b/user/src/com/google/gwt/user/client/ui/RequiresLayout.java
index be81be6..680c9a6 100644
--- a/user/src/com/google/gwt/user/client/ui/RequiresLayout.java
+++ b/user/src/com/google/gwt/user/client/ui/RequiresLayout.java
@@ -15,20 +15,54 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.layout.client.Layout;
+
 /**
- * This interface designates that its implementor needs to be informed whenever
- * its size is modified.
+ * Designates that a widget requires a method to be explicitly called after its
+ * children are modified.
  * 
  * <p>
- * Widgets that implement this interface should only be added to those that
- * implement {@link ProvidesLayout}. Failure to do so will usually result in
- * {@link #onLayout()} not being called.
+ * Widgets that implement this interface perform some layout work that will not
+ * be fully realized until {@link #layout()} or one of its overloads is called.
+ * This is required after adding or removing child widgets, and after any other
+ * operations that the implementor designates as requiring layout. Note that
+ * only <em>one</em> call to {@link #layout()} is required after any number of
+ * modifications.
  * </p>
  */
 public interface RequiresLayout {
 
   /**
-   * Update the layout immediately.
+   * Layout children immediately.
+   * 
+   * @see #layout(int)
+   * @see #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)
    */
-  void onLayout();
+  void layout();
+
+  /**
+   * Layout children, animating over the specified period of time.
+   * 
+   * @param duration the animation duration, in milliseconds
+   * 
+   * @see #layout()
+   * @see #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)
+   */
+  void layout(int duration);
+
+  /**
+   * Layout children, animating over the specified period of time.
+   * 
+   * <p>
+   * This method provides a callback that will be informed of animation updates.
+   * This can be used to create more complex animation effects.
+   * </p>
+   * 
+   * @param duration the animation duration, in milliseconds
+   * @param callback the animation callback
+   * 
+   * @see #layout()
+   * @see #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)
+   */
+  void layout(int duration, final Layout.AnimationCallback callback);
 }
diff --git a/user/src/com/google/gwt/user/client/ui/RequiresResize.java b/user/src/com/google/gwt/user/client/ui/RequiresResize.java
new file mode 100644
index 0000000..7193a2d
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/RequiresResize.java
@@ -0,0 +1,35 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+/**
+ * This interface designates that its implementor needs to be informed whenever
+ * its size is modified.
+ * 
+ * <p>
+ * Widgets that implement this interface should only be added to those that
+ * implement {@link ProvidesResize}. Failure to do so will usually result in
+ * {@link #onResize()} not being called.
+ * </p>
+ */
+public interface RequiresResize {
+
+  /**
+   * This method must be called whenever the implementor's size has been
+   * modified.
+   */
+  void onResize();
+}
diff --git a/user/src/com/google/gwt/user/client/ui/RootLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/RootLayoutPanel.java
index 88969e0..9351ec1 100644
--- a/user/src/com/google/gwt/user/client/ui/RootLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/RootLayoutPanel.java
@@ -24,7 +24,7 @@
  * to the document body (i.e. {@link RootPanel#get()}).
  * 
  * <p>
- * This panel automatically calls {@link RequiresLayout#layout()} on itself when
+ * This panel automatically calls {@link RequiresResize#layout()} on itself when
  * initially created, and whenever the window is resized.
  * </p>
  * 
@@ -44,7 +44,7 @@
  * {@example com.google.gwt.examples.LayoutPanelExample}
  * </p>
  */
-public class RootLayoutPanel extends LayoutPanel implements ProvidesLayout {
+public class RootLayoutPanel extends LayoutPanel {
 
   private static RootLayoutPanel singleton;
 
@@ -70,11 +70,11 @@
   private RootLayoutPanel() {
     Window.addResizeHandler(new ResizeHandler() {
       public void onResize(ResizeEvent event) {
-        onLayout();
+        RootLayoutPanel.this.onResize();
       }
     });
 
-    // TODO: We need notification of font-size changes as well.
+    // TODO(jgw): We need notification of font-size changes as well.
     // I believe there's a hidden iframe trick that we can use to get
     // a font-size-change event (really an em-definition-change event).
   }