Merges RenderableComposite into Composite. Version that adds a setResolver method to PotentialElement.
Review at http://gwt-code-reviews.appspot.com/1449813
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10294 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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..78cca37 100644
--- a/user/src/com/google/gwt/user/client/ui/Composite.java
+++ b/user/src/com/google/gwt/user/client/ui/Composite.java
@@ -15,6 +15,11 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.safehtml.client.SafeHtmlTemplates;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
@@ -23,21 +28,34 @@
* 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>
* <h3>Example</h3>
* {@example com.google.gwt.examples.CompositeExample}
* </p>
+ *
+ * TODO(rdcastro): Remove the final qualifier from IsRenderable overrides.
*/
-public abstract class Composite extends Widget {
+public abstract class Composite extends Widget implements IsRenderable {
+
+ interface HTMLTemplates extends SafeHtmlTemplates {
+ @Template("<span id=\"{0}\"></span>")
+ SafeHtml renderWithId(String id);
+ }
+ private static final HTMLTemplates TEMPLATE =
+ GWT.create(HTMLTemplates.class);
private Widget widget;
+ private IsRenderable renderable;
+
+ private Element elementToWrap;
+
@Override
public boolean isAttached() {
if (widget != null) {
@@ -55,6 +73,45 @@
widget.onBrowserEvent(event);
}
+ @Override
+ public final void performDetachedInitialization() {
+ if (renderable != null) {
+ renderable.performDetachedInitialization();
+ } else {
+ elementToWrap.getParentNode().replaceChild(widget.getElement(), elementToWrap);
+ }
+ }
+
+ @Override
+ public final SafeHtml render(String id) {
+ if (renderable != null) {
+ return renderable.render(id);
+ } else {
+ SafeHtmlBuilder builder = new SafeHtmlBuilder();
+ render(id, builder);
+ return builder.toSafeHtml();
+ }
+ }
+
+ @Override
+ public final void render(String id, SafeHtmlBuilder builder) {
+ if (renderable != null) {
+ renderable.render(id, builder);
+ } else {
+ builder.append(TEMPLATE.renderWithId(id));
+ }
+ }
+
+ @Override
+ public final void wrapElement(Element element) {
+ if (renderable != null) {
+ renderable.wrapElement(element);
+ setElement(widget.getElement());
+ } else {
+ this.elementToWrap = element;
+ }
+ }
+
/**
* Provides subclasses access to the topmost widget that defines this
* composite.
@@ -79,12 +136,22 @@
+ "called once.");
}
+ if (widget instanceof IsRenderable) {
+ // In case the Widget being wrapped is an IsRenderable, we save that fact.
+ this.renderable = (IsRenderable) widget;
+ }
+
// 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());
+ Element elem = widget.getElement();
+ setElement(elem);
+
+ if (PotentialElement.isPotential(elem)) {
+ PotentialElement.as(elem).setResolver(this);
+ }
// Logical attach.
this.widget = widget;
@@ -126,6 +193,12 @@
}
}
+ @Override
+ protected Element resolvePotentialElement() {
+ setElement(widget.resolvePotentialElement());
+ return getElement();
+ }
+
/**
* This method was for initializing the Widget to be wrapped by this
* Composite, but has been deprecated in favor of {@link #initWidget(Widget)}.
diff --git a/user/src/com/google/gwt/user/client/ui/PotentialElement.java b/user/src/com/google/gwt/user/client/ui/PotentialElement.java
index bee2484..58f5a83 100644
--- a/user/src/com/google/gwt/user/client/ui/PotentialElement.java
+++ b/user/src/com/google/gwt/user/client/ui/PotentialElement.java
@@ -37,6 +37,11 @@
*/
public class PotentialElement extends Element {
+ public static PotentialElement as(Element e) {
+ assert isPotential(e);
+ return (PotentialElement) e;
+ }
+
/**
* Builds a new PotentialElement. This element keeps track of the
* {@link UIObject} so that it can call
@@ -66,10 +71,7 @@
},
src: '',
style: {},
- __gwt_resolve: function() {
- this.__gwt_resolve = @com.google.gwt.user.client.ui.PotentialElement::cannotResolveTwice();
- return o.@com.google.gwt.user.client.ui.UIObject::resolvePotentialElement()();
- },
+ __gwt_resolve: @com.google.gwt.user.client.ui.PotentialElement::buildResolveCallback(Lcom/google/gwt/user/client/ui/UIObject;)(o),
title: ''
});
}-*/;
@@ -94,6 +96,13 @@
return maybePotential.<PotentialElement>cast().resolve();
}
+ private static native JavaScriptObject buildResolveCallback(UIObject resolver) /*-{
+ return function() {
+ this.__gwt_resolve = @com.google.gwt.user.client.ui.PotentialElement::cannotResolveTwice();
+ return resolver.@com.google.gwt.user.client.ui.UIObject::resolvePotentialElement()();
+ };
+ }-*/;
+
private static final native void cannotResolveTwice() /*-{
throw "A PotentialElement cannot be resolved twice.";
}-*/;
@@ -101,6 +110,10 @@
protected PotentialElement() {
}
+ final native Element setResolver(UIObject resolver) /*-{
+ this.__gwt_resolve = @com.google.gwt.user.client.ui.PotentialElement::buildResolveCallback(Lcom/google/gwt/user/client/ui/UIObject;)(resolver);
+ }-*/;
+
/**
* Calls the <code>__gwt_resolve</code> method on the underlying
* JavaScript object if it exists. On objects created via {@link #build}, this
diff --git a/user/src/com/google/gwt/user/client/ui/RenderableComposite.java b/user/src/com/google/gwt/user/client/ui/RenderableComposite.java
index fae9b06..2c32155 100644
--- a/user/src/com/google/gwt/user/client/ui/RenderableComposite.java
+++ b/user/src/com/google/gwt/user/client/ui/RenderableComposite.java
@@ -15,15 +15,6 @@
*/
package com.google.gwt.user.client.ui;
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.event.logical.shared.AttachEvent;
-import com.google.gwt.safehtml.client.SafeHtmlTemplates;
-import com.google.gwt.safehtml.shared.SafeHtml;
-import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-
/**
* EXPERIMENTAL and subject to change. Do not use this in production code.
* <p>
@@ -32,193 +23,9 @@
* itself, but is still under active development.
* The only reason why this isn't a subclass of {@link Composite} is to avoid
* messing up it's API, since {@link Composite} is very often subclassed.
+ *
+ * TODO(rdcastro): Delete this as soon as all references have been updated to
+ * use Composite directly.
*/
-public abstract class RenderableComposite extends Widget implements IsRenderable {
-
- interface HTMLTemplates extends SafeHtmlTemplates {
- @Template("<span id=\"{0}\"></span>")
- SafeHtml renderWithId(String id);
- }
- private static final HTMLTemplates TEMPLATE =
- GWT.create(HTMLTemplates.class);
-
- private Widget widget;
-
- private IsRenderable renderable;
-
- private Element elementToWrap;
-
- private boolean initFinished = false;
-
- @Override
- public com.google.gwt.user.client.Element getElement() {
- if (!initFinished) {
- // if we're trying to get the element but we haven't finished the
- // initialization, do it now.
- initWidgetInternal();
- }
- return super.getElement();
- }
-
- @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);
- }
-
- @Override
- public void performDetachedInitialization() {
- if (renderable != null) {
- assert (initFinished == false);
- renderable.performDetachedInitialization();
- initWidgetInternal();
- } else {
- elementToWrap.getParentNode().replaceChild(widget.getElement(), elementToWrap);
- }
- }
-
- @Override
- public SafeHtml render(String id) {
- if (renderable != null) {
- return renderable.render(id);
- } else {
- SafeHtmlBuilder builder = new SafeHtmlBuilder();
- render(id, builder);
- return builder.toSafeHtml();
- }
- }
-
- @Override
- public void render(String id, SafeHtmlBuilder builder) {
- if (renderable != null) {
- renderable.render(id, builder);
- } else {
- builder.append(TEMPLATE.renderWithId(id));
- }
- }
-
- @Override
- public void setStyleName(String styleName) {
- if (this.widget == null) {
- throw new IllegalStateException("setStyleName called before initWidget.");
- }
- widget.setStyleName(styleName);
- }
-
- @Override
- public void wrapElement(Element element) {
- if (renderable != null) {
- assert (initFinished == false);
- renderable.wrapElement(element);
- } else {
- this.elementToWrap = element;
- }
- }
-
- /**
- * Provides subclasses access to the topmost widget that defines this
- * composite.
- *
- * @return the widget
- */
- 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();
-
- // Logical attach.
- this.widget = widget;
-
- if (widget instanceof IsRenderable) {
- // In case the Widget being wrapped is an IsRenderable, we delay finishing
- // the initialization until the performDetachedInitialization() is called.
- this.renderable = (IsRenderable) widget;
- return;
- }
-
- initWidgetInternal();
- }
-
- @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();
- }
- }
-
- /**
- * This method was for initializing the Widget to be wrapped by this
- * Composite, but has been deprecated in favor of {@link #initWidget(Widget)}.
- *
- * @deprecated Use {@link #initWidget(Widget)} instead
- */
- @Deprecated
- protected void setWidget(Widget widget) {
- initWidget(widget);
- }
-
- private void initWidgetInternal() {
- // Use the contained widget's element as the composite's element,
- // effectively merging them within the DOM.
- setElement(PotentialElement.resolve(widget.getElement()));
-
- // Adopt.
- widget.setParent(this);
-
- // Mark initialization as finished, as this only needs to be run once.
- this.initFinished = true;
- }
+public abstract class RenderableComposite extends Composite {
}