Introduces Widget.LoadingDelegate, to allow a widget owner to act when
a widget is added to or removed from the document without subclassing
it. E.g. to attach to an event bus, or fire RPC requests.
Review at http://gwt-code-reviews.appspot.com/866801
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8770 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/event/logical/shared/AttachEvent.java b/user/src/com/google/gwt/event/logical/shared/AttachEvent.java
new file mode 100644
index 0000000..7723ac5
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/shared/AttachEvent.java
@@ -0,0 +1,107 @@
+/*
+ * 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.event.logical.shared;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.google.gwt.event.shared.GwtEvent;
+
+/**
+ * Fired when the event source is attached to the browser's document
+ * or detached from it.
+ */
+public class AttachEvent extends GwtEvent<AttachEvent.Handler> {
+
+ /**
+ * Implemented by objects that handle {@link AttachEvent}.
+ */
+ public interface Handler extends EventHandler {
+ void onAttach(AttachEvent event);
+ void onDetach(AttachEvent event);
+ }
+
+ /**
+ * The event type.
+ */
+ static Type<AttachEvent.Handler> TYPE;
+
+ /**
+ * Fires a {@link AttachEvent} on all registered handlers in the handler source.
+ *
+ * @param <S> The handler source type
+ * @param source the source of the handlers
+ * @param attached whether to announce an attach or detach
+ */
+ public static <S extends HasAttachHandlers> void fire(S source,
+ boolean attached) {
+ if (TYPE != null) {
+ AttachEvent event = new AttachEvent(attached);
+ source.fireEvent(event);
+ }
+ }
+
+ /**
+ * Ensures the existence of the handler hook and then returns it.
+ *
+ * @return returns a handler hook
+ */
+ public static Type<AttachEvent.Handler> getType() {
+ if (TYPE == null) {
+ TYPE = new Type<AttachEvent.Handler>();
+ }
+ return TYPE;
+ }
+
+ private final boolean attached;
+
+ /**
+ * Construct a new {@link AttachEvent}.
+ *
+ * @param width the new width
+ * @param height the new height
+ */
+ protected AttachEvent(boolean loaded) {
+ this.attached = loaded;
+ }
+
+ @Override
+ public final Type<AttachEvent.Handler> getAssociatedType() {
+ return TYPE;
+ }
+
+ /**
+ * @return true if this event announces that the source has been attached,
+ * false if it has been detached
+ */
+ public boolean isAttached() {
+ return attached;
+ }
+
+ @Override
+ public String toDebugString() {
+ assertLive();
+ return super.toDebugString() + " attached = " + attached;
+ }
+
+ @Override
+ protected void dispatch(AttachEvent.Handler handler) {
+ if (attached) {
+ handler.onAttach(this);
+ } else {
+ handler.onDetach(this);
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/event/logical/shared/HasAttachHandlers.java b/user/src/com/google/gwt/event/logical/shared/HasAttachHandlers.java
new file mode 100644
index 0000000..c01efe3
--- /dev/null
+++ b/user/src/com/google/gwt/event/logical/shared/HasAttachHandlers.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.event.logical.shared;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.event.shared.HasHandlers;
+
+/**
+ * A widget that implements this interface is a public source of
+ * {@link AttachEvent} events.
+ */
+public interface HasAttachHandlers extends HasHandlers {
+ /**
+ * Adds a {@link AttachEvent} handler.
+ *
+ * @param handler the handler
+ * @return the handler registration
+ */
+ HandlerRegistration addAttachHandler(AttachEvent.Handler handler);
+}
diff --git a/user/src/com/google/gwt/event/shared/HandlerManager.java b/user/src/com/google/gwt/event/shared/HandlerManager.java
index 82e0565..9a8776d 100644
--- a/user/src/com/google/gwt/event/shared/HandlerManager.java
+++ b/user/src/com/google/gwt/event/shared/HandlerManager.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,15 +19,15 @@
/**
* Manager responsible for adding handlers to event sources and firing those
- * handlers on passed in events. Primitive ancestor of {@link EventBus},
+ * handlers on passed in events. Primitive ancestor of {@link EventBus},
* and used at the core of {com.google.gwt.user.client.ui.Widget}.
- *
+ *
* @deprecated use {@link SimpleEventBus}.
*/
@Deprecated
public class HandlerManager implements HasHandlers {
- private SimpleEventBus eventBus;
+ private final SimpleEventBus eventBus;
// source of the events
private final Object source;
@@ -36,7 +36,7 @@
* Creates a handler manager with a source to be set on all events fired via
* {@link #fireEvent(GwtEvent)}. Handlers will be fired in the order that they
* are added.
- *
+ *
* @param source the default event source
*/
public HandlerManager(Object source) {
@@ -46,10 +46,11 @@
/**
* Creates a handler manager with the given source, specifying the order in
* which handlers are fired.
- *
+ *
* @param source the event source
* @param fireInReverseOrder true to fire handlers in reverse order
*/
+ @SuppressWarnings("deprecation")
public HandlerManager(Object source, boolean fireInReverseOrder) {
eventBus = new SimpleEventBus(fireInReverseOrder);
this.source = source;
@@ -57,7 +58,7 @@
/**
* Adds a handler.
- *
+ *
* @param <H> The type of handler
* @param type the event type associated with this handler
* @param handler the handler
@@ -76,11 +77,11 @@
* {@link UmbrellaException} and then re-thrown after all handlers have
* completed. An exception thrown by a handler will not prevent other handlers
* from executing.
- * <p>
+ * <p>
* Note, any subclass should be very careful about overriding this method, as
* adds/removes of handlers will not be safe except within this
* implementation.
- *
+ *
* @param event the event
*/
public void fireEvent(GwtEvent<?> event) {
@@ -108,41 +109,44 @@
/**
* Gets the handler at the given index.
- *
+ *
* @param <H> the event handler type
* @param index the index
* @param type the handler's event type
* @return the given handler
*/
+ @SuppressWarnings("deprecation")
public <H extends EventHandler> H getHandler(GwtEvent.Type<H> type, int index) {
return eventBus.getHandler(type, index);
}
/**
* Gets the number of handlers listening to the event type.
- *
+ *
* @param type the event type
* @return the number of registered handlers
*/
+ @SuppressWarnings("deprecation")
public int getHandlerCount(Type<?> type) {
return eventBus.getHandlerCount(type);
}
/**
* Does this handler manager handle the given event type?
- *
+ *
* @param e the event type
* @return whether the given event type is handled
*/
+ @SuppressWarnings("deprecation")
public boolean isEventHandled(Type<?> e) {
return eventBus.isEventHandled(e);
}
/**
* Removes the given handler from the specified event type.
- *
+ *
* @param <H> handler type
- *
+ *
* @param type the event type
* @param handler the handler
*/
diff --git a/user/src/com/google/gwt/user/client/ui/Widget.java b/user/src/com/google/gwt/user/client/ui/Widget.java
index 6b6df98..43191cd 100644
--- a/user/src/com/google/gwt/user/client/ui/Widget.java
+++ b/user/src/com/google/gwt/user/client/ui/Widget.java
@@ -17,11 +17,14 @@
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.DomEvent;
+import com.google.gwt.event.logical.shared.AttachEvent;
+import com.google.gwt.event.logical.shared.AttachEvent.Handler;
+import com.google.gwt.event.logical.shared.HasAttachHandlers;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.event.shared.HasHandlers;
import com.google.gwt.event.shared.GwtEvent.Type;
+import com.google.gwt.event.shared.HandlerManager;
+import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
@@ -31,7 +34,8 @@
* support for receiving events from the browser and being added directly to
* {@link com.google.gwt.user.client.ui.Panel panels}.
*/
-public class Widget extends UIObject implements EventListener, HasHandlers, IsWidget {
+public class Widget extends UIObject implements EventListener, HasAttachHandlers,
+ IsWidget {
/**
* This convenience method makes a null-safe call to
@@ -52,10 +56,14 @@
int eventsToSink;
private boolean attached;
@SuppressWarnings("deprecation")
- private com.google.gwt.event.shared.HandlerManager handlerManager;
+ private HandlerManager handlerManager;
private Object layoutData;
private Widget parent;
+ public HandlerRegistration addAttachHandler(Handler handler) {
+ return addHandler(handler, AttachEvent.getType());
+ }
+
/**
* Adds a native event handler to the widget and sinks the corresponding
* native event. If you do not want to sink the native event, use the generic
@@ -286,8 +294,8 @@
* </p>
* <p>
* It is strongly recommended that you override {@link #onLoad()} or
- * {@link #doAttachChildren()} instead of this method to avoid
- * inconsistencies between logical and physical attachment states.
+ * {@link #doAttachChildren()} instead of this method to avoid inconsistencies
+ * between logical and physical attachment states.
* </p>
* <p>
* Subclasses that override this method must call
@@ -330,8 +338,8 @@
* </p>
* <p>
* It is strongly recommended that you override {@link #onUnload()} or
- * {@link #doDetachChildren()} instead of this method to avoid
- * inconsistencies between logical and physical attachment states.
+ * {@link #doDetachChildren()} instead of this method to avoid inconsistencies
+ * between logical and physical attachment states.
* </p>
* <p>
* Subclasses that override this method must call
@@ -369,16 +377,20 @@
/**
* This method is called immediately after a widget becomes attached to the
- * browser's document.
+ * browser's document. This default implementation notifies the widgets
+ * {@link AttachEvent.Handler}s.
*/
protected void onLoad() {
+ AttachEvent.fire(this, true);
}
/**
* This method is called immediately before a widget will be detached from the
- * browser's document.
+ * browser's document. This default implementation notifies the widgets
+ * {@link AttachEvent.Handler}s.
*/
protected void onUnload() {
+ AttachEvent.fire(this, false);
}
/**
diff --git a/user/test/com/google/gwt/user/client/ui/WidgetOnLoadTest.java b/user/test/com/google/gwt/user/client/ui/WidgetOnLoadTest.java
index 430deda..af02983 100644
--- a/user/test/com/google/gwt/user/client/ui/WidgetOnLoadTest.java
+++ b/user/test/com/google/gwt/user/client/ui/WidgetOnLoadTest.java
@@ -1,12 +1,12 @@
/*
* Copyright 2007 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
@@ -15,6 +15,7 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
@@ -24,16 +25,6 @@
*/
public class WidgetOnLoadTest extends GWTTestCase {
- public String getModuleName() {
- return "com.google.gwt.user.User";
- }
-
- static int orderIndex;
-
- static boolean isElementAttached(Element elem) {
- return DOM.isOrHasChild(RootPanel.getBodyElement(), elem);
- }
-
static class TestPanel extends FlowPanel {
int onAttachOrder;
int onLoadOrder;
@@ -42,22 +33,26 @@
boolean domAttachedOnLoad;
boolean domAttachedOnUnload;
+ @Override
protected void onAttach() {
onAttachOrder = ++orderIndex;
super.onAttach();
}
+ @Override
+ protected void onDetach() {
+ onDetachOrder = ++orderIndex;
+ super.onDetach();
+ }
+
+ @Override
protected void onLoad() {
onLoadOrder = ++orderIndex;
domAttachedOnLoad = isElementAttached(getElement());
super.onLoad();
}
- protected void onDetach() {
- onDetachOrder = ++orderIndex;
- super.onDetach();
- }
-
+ @Override
protected void onUnload() {
onUnloadOrder = ++orderIndex;
domAttachedOnUnload = isElementAttached(getElement());
@@ -73,22 +68,26 @@
boolean domAttachedOnLoad;
boolean domAttachedOnUnload;
+ @Override
protected void onAttach() {
onAttachOrder = ++orderIndex;
super.onAttach();
}
+ @Override
+ protected void onDetach() {
+ onDetachOrder = ++orderIndex;
+ super.onDetach();
+ }
+
+ @Override
protected void onLoad() {
domAttachedOnLoad = isElementAttached(getElement());
onLoadOrder = ++orderIndex;
super.onLoad();
}
- protected void onDetach() {
- onDetachOrder = ++orderIndex;
- super.onDetach();
- }
-
+ @Override
protected void onUnload() {
onUnloadOrder = ++orderIndex;
domAttachedOnUnload = isElementAttached(getElement());
@@ -96,9 +95,34 @@
}
}
+ static int orderIndex;
+
+ static boolean isElementAttached(Element elem) {
+ return DOM.isOrHasChild(RootPanel.getBodyElement(), elem);
+ }
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.user.User";
+ }
+
public void testOnLoadAndUnloadOrder() {
+ class TestAttachHandler implements AttachEvent.Handler {
+ int delegateAttachOrder;
+ int delegateDetachOrder;
+
+ public void onAttach(AttachEvent event) {
+ delegateAttachOrder = ++orderIndex;
+ }
+ public void onDetach(AttachEvent event) {
+ delegateDetachOrder = ++orderIndex;
+ }
+ }
+
TestPanel tp = new TestPanel();
TestWidget tw = new TestWidget();
+ TestAttachHandler ta = new TestAttachHandler();
+ tw.addAttachHandler(ta);
tp.add(tw);
RootPanel.get().add(tp);
@@ -109,7 +133,9 @@
assertTrue(tp.onAttachOrder < tp.onLoadOrder);
assertTrue(tp.onDetachOrder < tp.onUnloadOrder);
assertTrue(tw.onAttachOrder < tw.onLoadOrder);
+ assertTrue(tw.onLoadOrder < ta.delegateAttachOrder);
assertTrue(tw.onDetachOrder < tw.onUnloadOrder);
+ assertTrue(tw.onUnloadOrder < ta.delegateDetachOrder);
// Also trivial. Ensure that the panel's onAttach/onDetach is called before
// its child's onAttach/onDetach.