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.