Extracts AbstractComposite<W> out of Composite, to allow type safe
calls to gwtWidget(). Deprecates ResizeComposite and replaces it with
RequiresResizeComposite, which moves the "must implement
RequireResize" requirement check to compile time.

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

Review by: jlabanca@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10290 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskListView.java b/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskListView.java
index 69fac21..81ac60a 100644
--- a/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskListView.java
+++ b/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/desktop/DesktopTaskListView.java
@@ -22,7 +22,7 @@
 import com.google.gwt.user.cellview.client.DataGrid;
 import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
 import com.google.gwt.user.cellview.client.TextColumn;
-import com.google.gwt.user.client.ui.ResizeComposite;
+import com.google.gwt.user.client.ui.RequiresResizeComposite;
 import com.google.gwt.view.client.NoSelectionModel;
 import com.google.gwt.view.client.SelectionChangeEvent;
 import com.google.gwt.view.client.SelectionModel;
@@ -33,7 +33,7 @@
 /**
  * View used to display the list of Tasks.
  */
-public class DesktopTaskListView extends ResizeComposite implements TaskListView {
+public class DesktopTaskListView extends RequiresResizeComposite<DataGrid<?>> implements TaskListView {
 
   /**
    * Displays the list of tasks.
diff --git a/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/desktop/MobileWebAppShellDesktop.java b/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/desktop/MobileWebAppShellDesktop.java
index 117dfec..f8e8842 100644
--- a/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/desktop/MobileWebAppShellDesktop.java
+++ b/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/desktop/MobileWebAppShellDesktop.java
@@ -49,7 +49,7 @@
 import com.google.gwt.user.client.ui.IsWidget;
 import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.ResizeComposite;
+import com.google.gwt.user.client.ui.RequiresResizeComposite;
 import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwt.user.client.ui.Widget;
 import com.google.gwt.view.client.SelectionChangeEvent;
@@ -63,7 +63,7 @@
 /**
  * Desktop version of the UI shell.
  */
-public class MobileWebAppShellDesktop extends ResizeComposite implements MobileWebAppShell {
+public class MobileWebAppShellDesktop extends RequiresResizeComposite<DockLayoutPanel> implements MobileWebAppShell {
 
   /**
    * CSS override used for the main menu.
@@ -71,7 +71,7 @@
   interface MainMenuStyle extends CellList.Style {
   }
 
-  interface MobileWebAppShellDesktopUiBinder extends UiBinder<Widget, MobileWebAppShellDesktop> {
+  interface MobileWebAppShellDesktopUiBinder extends UiBinder<DockLayoutPanel, MobileWebAppShellDesktop> {
   }
 
   /**
@@ -147,7 +147,6 @@
 
   /**
    * Construct a new {@link MobileWebAppShellDesktop}.
-   * @param clientFactory the {@link ClientFactory} of shared resources
    */
   public MobileWebAppShellDesktop(EventBus bus, final PlaceController placeController,
       TaskListView taskListView, TaskEditView taskEditView, TaskReadView taskReadView) {
diff --git a/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/mobile/MobileWebAppShellMobile.java b/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/mobile/MobileWebAppShellMobile.java
index 1521ba6..41e11e0 100644
--- a/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/mobile/MobileWebAppShellMobile.java
+++ b/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/mobile/MobileWebAppShellMobile.java
@@ -36,15 +36,15 @@
 import com.google.gwt.user.client.ui.DeckLayoutPanel;
 import com.google.gwt.user.client.ui.IsWidget;
 import com.google.gwt.user.client.ui.LayoutPanel;
-import com.google.gwt.user.client.ui.ResizeComposite;
+import com.google.gwt.user.client.ui.RequiresResizeComposite;
 import com.google.gwt.user.client.ui.Widget;
 
 /**
  * Mobile version of the UI shell.
  */
-public class MobileWebAppShellMobile extends ResizeComposite implements MobileWebAppShell {
+public class MobileWebAppShellMobile extends RequiresResizeComposite<LayoutPanel> implements MobileWebAppShell {
 
-  interface MobileWebAppShellMobileUiBinder extends UiBinder<Widget, MobileWebAppShellMobile> {
+  interface MobileWebAppShellMobileUiBinder extends UiBinder<LayoutPanel, MobileWebAppShellMobile> {
   }
 
   private static MobileWebAppShellMobileUiBinder uiBinder =
diff --git a/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/tablet/MobileWebAppShellTablet.java b/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/tablet/MobileWebAppShellTablet.java
index e98b290..9ede378 100644
--- a/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/tablet/MobileWebAppShellTablet.java
+++ b/samples/mobilewebapp/src/main/java/com/google/gwt/sample/mobilewebapp/client/tablet/MobileWebAppShellTablet.java
@@ -34,7 +34,7 @@
 import com.google.gwt.user.client.ui.DockLayoutPanel;
 import com.google.gwt.user.client.ui.IsWidget;
 import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.ResizeComposite;
+import com.google.gwt.user.client.ui.RequiresResizeComposite;
 import com.google.gwt.user.client.ui.SimplePanel;
 import com.google.gwt.user.client.ui.Widget;
 
@@ -43,9 +43,9 @@
  * 
  * TODO(rjrjr): this thing needs a presenter. Not an activity. A presenter.
  */
-public class MobileWebAppShellTablet extends ResizeComposite implements MobileWebAppShell {
+public class MobileWebAppShellTablet extends RequiresResizeComposite<DockLayoutPanel> implements MobileWebAppShell {
 
-  interface MobileWebAppShellTabletUiBinder extends UiBinder<Widget, MobileWebAppShellTablet> {
+  interface MobileWebAppShellTabletUiBinder extends UiBinder<DockLayoutPanel, MobileWebAppShellTablet> {
   }
 
   private static MobileWebAppShellTabletUiBinder uiBinder =
diff --git a/tools/api-checker/config/gwt23_24userApi.conf b/tools/api-checker/config/gwt23_24userApi.conf
index 595e1e1..741d26a 100644
--- a/tools/api-checker/config/gwt23_24userApi.conf
+++ b/tools/api-checker/config/gwt23_24userApi.conf
@@ -157,3 +157,11 @@
 com.google.gwt.user.client.ui.Image::prefetch(Ljava/lang/String;) OVERLOADED_METHOD_CALL
 com.google.gwt.user.client.ui.Image::setUrl(Ljava/lang/String;) OVERLOADED_METHOD_CALL
 com.google.gwt.user.client.ui.Image::setUrlAndVisibleRect(Ljava/lang/String;IIII) OVERLOADED_METHOD_CALL
+
+# Change StackLayoutPanel and TabLayoutPanel to get new superclass
+com.google.gwt.user.client.ui.StackLayoutPanel::getWidget() OVERRIDABLE_METHOD_RETURN_TYPE_CHANGE  from class com.google.gwt.user.client.ui.Widget to class com.google.gwt.user.client.ui.LayoutPanel
+com.google.gwt.user.client.ui.StackLayoutPanel::initWidget(Lcom/google/gwt/user/client/ui/Widget;) MISSING
+com.google.gwt.user.client.ui.StackLayoutPanel::setWidget(Lcom/google/gwt/user/client/ui/Widget;) MISSING
+com.google.gwt.user.client.ui.TabLayoutPanel::getWidget() OVERRIDABLE_METHOD_RETURN_TYPE_CHANGE  from class com.google.gwt.user.client.ui.Widget to class com.google.gwt.user.client.ui.LayoutPanel
+com.google.gwt.user.client.ui.TabLayoutPanel::initWidget(Lcom/google/gwt/user/client/ui/Widget;) MISSING
+com.google.gwt.user.client.ui.TabLayoutPanel::setWidget(Lcom/google/gwt/user/client/ui/Widget;) MISSING
diff --git a/user/src/com/google/gwt/user/client/ui/AbstractComposite.java b/user/src/com/google/gwt/user/client/ui/AbstractComposite.java
new file mode 100644
index 0000000..2195ac4
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/AbstractComposite.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2011 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client.ui;
+
+import com.google.gwt.event.logical.shared.AttachEvent;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+
+/**
+ * A type of widget that can wrap another widget, hiding the wrapped widget's
+ * methods. When added to a panel, a composite behaves exactly as if the widget
+ * it wraps had been added.
+ * <p>
+ * The composite is useful for creating a single widget out of an aggregate of
+ * multiple other widgets contained in a single panel.
+ * 
+ * @see Composite
+ * 
+ * @param <W> the type of IsWidget this composite wraps
+ */
+public class AbstractComposite<W extends IsWidget> extends Widget {
+
+  private W isWidget;
+
+  @Override
+  public boolean isAttached() {
+    if (isWidget != null) {
+      return isWidget.asWidget().isAttached();
+    }
+    return false;
+  }
+
+  @Override
+  public void onBrowserEvent(Event event) {
+    // Fire any handler added to the composite itself.
+    super.onBrowserEvent(event);
+
+    // Delegate events to the widget.
+    getWidget().asWidget().onBrowserEvent(event);
+  }
+
+  /**
+   * Provides subclasses access to the widget that defines this composite.
+   * 
+   * @return the widget
+   */
+  protected W getWidget() {
+    return isWidget;
+  }
+
+  /**
+   * Sets the widget to be wrapped by the composite. The wrapped widget must be
+   * set before calling any {@link Widget} methods on this object, or adding it
+   * to a panel. This method may only be called once for a given composite.
+   * <p>
+   * The widget returned by the wrapped object's {@link IsWidget#asWidget()} method
+   * must be stable. If it changes, the results are unpredictable.
+   * 
+   * @param isWidget the widget to be wrapped
+   */
+  protected void initWidget(W isWidget) {
+    // Validate. Make sure the widget is not being set twice.
+    if (this.isWidget != null) {
+      throw new IllegalStateException("initWidget() may only be called once.");
+    }
+
+    // TODO rjrjr: avoids breaking some mocked unit tests, should fix the tests instead
+    Widget newChild = isWidget instanceof Widget ? (Widget) isWidget : isWidget.asWidget();
+
+    // Detach the new child.
+    newChild.removeFromParent();
+
+    // Use the contained widget's element as the composite's element,
+    // effectively merging them within the DOM.
+    setElement(newChild.getElement());
+
+    // Logical attach.
+    this.isWidget = isWidget;
+
+    // Adopt.
+    newChild.setParent(this);
+  }
+
+  /**
+   * 
+   */
+  @Override
+  protected void onAttach() {
+    Widget asWidget = getWidget().asWidget();
+
+    if (!isOrWasAttached()) {
+      asWidget.sinkEvents(eventsToSink);
+      eventsToSink = -1;
+    }
+
+    asWidget.onAttach();
+
+    // Clobber the widget's call to setEventListener(), causing all events to
+    // be routed to this composite, which will delegate back to the widget by
+    // default (note: it's not necessary to clear this in onDetach(), because
+    // the widget's onDetach will do so).
+    DOM.setEventListener(getElement(), this);
+
+    // Call onLoad() directly, because we're not calling super.onAttach().
+    onLoad();
+    AttachEvent.fire(this, true);
+  }
+
+  @Override
+  protected void onDetach() {
+    try {
+      onUnload();
+      AttachEvent.fire(this, false);
+    } finally {
+      // We don't want an exception in user code to keep us from calling the
+      // super implementation (or event listeners won't get cleaned up and
+      // the attached flag will be wrong).
+      getWidget().asWidget().onDetach();
+    }
+  }
+}
\ No newline at end of file
diff --git a/user/src/com/google/gwt/user/client/ui/Composite.java b/user/src/com/google/gwt/user/client/ui/Composite.java
index c90cc4e..3fdf5fa 100644
--- a/user/src/com/google/gwt/user/client/ui/Composite.java
+++ b/user/src/com/google/gwt/user/client/ui/Composite.java
@@ -15,115 +15,25 @@
  */
 package com.google.gwt.user.client.ui;
 
-import com.google.gwt.event.logical.shared.AttachEvent;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-
 /**
- * A type of widget that can wrap another widget, hiding the wrapped widget's
- * methods. When added to a panel, a composite behaves exactly as if the widget
- * it wraps had been added.
- * 
- * <p>
- * The composite is useful for creating a single widget out of an aggregate of
- * multiple other widgets contained in a single panel.
- * </p>
- * 
- * <p>
+ * Simple extension of {@link AbstractComposite} that doesn't require type
+ * parameters. This originally was the only implementation of Composite, before
+ * {@link AbstractComposite} was introduced to allow strong typing and deferred
+ * construction.
+ *
  * <h3>Example</h3>
  * {@example com.google.gwt.examples.CompositeExample}
  * </p>
  */
-public abstract class Composite extends Widget {
-
-  private Widget widget;
-
-  @Override
-  public boolean isAttached() {
-    if (widget != null) {
-      return widget.isAttached();
-    }
-    return false;
-  }
-
-  @Override
-  public void onBrowserEvent(Event event) {
-    // Fire any handler added to the composite itself.
-    super.onBrowserEvent(event);
-
-    // Delegate events to the widget.
-    widget.onBrowserEvent(event);
-  }
-
+public abstract class Composite extends AbstractComposite<Widget> {
+  
   /**
-   * Provides subclasses access to the topmost widget that defines this
-   * composite.
-   * 
-   * @return the widget
+   * Provided for compatibility with legacy unit tests that mocked
+   * this specific method.
    */
-  protected Widget getWidget() {
-    return widget;
-  }
-
-  /**
-   * Sets the widget to be wrapped by the composite. The wrapped widget must be
-   * set before calling any {@link Widget} methods on this object, or adding it
-   * to a panel. This method may only be called once for a given composite.
-   * 
-   * @param widget the widget to be wrapped
-   */
-  protected void initWidget(Widget widget) {
-    // Validate. Make sure the widget is not being set twice.
-    if (this.widget != null) {
-      throw new IllegalStateException("Composite.initWidget() may only be "
-          + "called once.");
-    }
-
-    // Detach the new child.
-    widget.removeFromParent();
-
-    // Use the contained widget's element as the composite's element,
-    // effectively merging them within the DOM.
-    setElement(widget.getElement());
-
-    // Logical attach.
-    this.widget = widget;
-
-    // Adopt.
-    widget.setParent(this);
-  }
-
-  @Override
-  protected void onAttach() {
-    if (!isOrWasAttached()) {
-      widget.sinkEvents(eventsToSink);
-      eventsToSink = -1;
-    }
-
-    widget.onAttach();
-
-    // Clobber the widget's call to setEventListener(), causing all events to
-    // be routed to this composite, which will delegate back to the widget by
-    // default (note: it's not necessary to clear this in onDetach(), because
-    // the widget's onDetach will do so).
-    DOM.setEventListener(getElement(), this);
-
-    // Call onLoad() directly, because we're not calling super.onAttach().
-    onLoad();
-    AttachEvent.fire(this, true);
-  }
-
-  @Override
-  protected void onDetach() {
-    try {
-      onUnload();
-      AttachEvent.fire(this, false);
-    } finally {
-      // We don't want an exception in user code to keep us from calling the
-      // super implementation (or event listeners won't get cleaned up and
-      // the attached flag will be wrong).
-      widget.onDetach();
-    }
+  @Deprecated
+  protected void initWidget(Widget widget) { 
+    super.initWidget(widget);
   }
 
   /**
diff --git a/user/src/com/google/gwt/user/client/ui/RequiresResizeComposite.java b/user/src/com/google/gwt/user/client/ui/RequiresResizeComposite.java
new file mode 100644
index 0000000..d1a1003
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/RequiresResizeComposite.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2011 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;
+
+/**
+ * A {@link AbstractComposite} implementation that implements {@link RequiresResize}
+ * and automatically delegates that interface's methods to its wrapped widget,
+ * which must itself implement {@link RequiresResize}.
+ * 
+ * @param <W> the type of widget wrapped
+ */
+public abstract class RequiresResizeComposite<W extends Widget & RequiresResize> extends
+    AbstractComposite<W> implements RequiresResize {
+
+  public void onResize() {
+    getWidget().onResize();
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/ResizeComposite.java b/user/src/com/google/gwt/user/client/ui/ResizeComposite.java
index 7d0bab3..1d2bc1d 100644
--- a/user/src/com/google/gwt/user/client/ui/ResizeComposite.java
+++ b/user/src/com/google/gwt/user/client/ui/ResizeComposite.java
@@ -19,7 +19,9 @@
  * A {@link Composite} implementation that implements {@link RequiresResize} and
  * automatically delegates that interface's methods to its wrapped widget, which
  * must itself implement {@link RequiresResize}.
+ * @deprecated Use {@link RequiresResizeComposite}
  */
+@Deprecated
 public abstract class ResizeComposite extends Composite implements
     RequiresResize {
 
diff --git a/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
index e567de9..f5fe823 100644
--- a/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
@@ -95,7 +95,7 @@
  * &lt;/g:StackLayoutPanel>
  * </pre>
  */
-public class StackLayoutPanel extends ResizeComposite implements HasWidgets,
+public class StackLayoutPanel extends RequiresResizeComposite<LayoutPanel> implements HasWidgets,
     ProvidesResize, IndexedPanel.ForIsWidget, AnimatedLayout,
     HasBeforeSelectionHandlers<Integer>, HasSelectionHandlers<Integer> {
 
diff --git a/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
index 0c90414..365f8ee 100644
--- a/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
@@ -94,7 +94,7 @@
  * &lt;/g:TabLayoutPanel>
  * </pre>
  */
-public class TabLayoutPanel extends ResizeComposite implements HasWidgets,
+public class TabLayoutPanel extends RequiresResizeComposite<LayoutPanel> implements HasWidgets,
     ProvidesResize, IndexedPanel.ForIsWidget, AnimatedLayout,
     HasBeforeSelectionHandlers<Integer>, HasSelectionHandlers<Integer> {