Author: jlaba...@google.com Date: Thu Jan 15 07:01:51 2009 New Revision: 4464
Modified: releases/1.6/user/src/com/google/gwt/user/client/DOM.java releases/1.6/user/src/com/google/gwt/user/client/Event.java releases/1.6/user/src/com/google/gwt/user/client/ListenerWrapper.java releases/1.6/user/src/com/google/gwt/user/client/impl/DOMImpl.java releases/1.6/user/src/com/google/gwt/user/client/ui/PopupPanel.java releases/1.6/user/test/com/google/gwt/user/client/EventTest.java Log: Merged the legecy EventPreview stack into the new NativePreviewHandler stack so legacy EventPreviews will only fire if they are at the top of the combined stack. A previous change took PopupPanels off the legacy stack, which promoted other EventPreview to the top and broke legacy code. Patch by: jlabanca Review by: ecc (desk) Issue: 3285 Modified: releases/1.6/user/src/com/google/gwt/user/client/DOM.java ============================================================================== --- releases/1.6/user/src/com/google/gwt/user/client/DOM.java (original) +++ releases/1.6/user/src/com/google/gwt/user/client/DOM.java Thu Jan 15 07:01:51 2009 @@ -23,8 +23,6 @@ import com.google.gwt.dom.client.SelectElement; import com.google.gwt.user.client.impl.DOMImpl; -import java.util.ArrayList; - /** * This class provides a set of static methods that allow you to manipulate the * browser's Document Object Model (DOM). It contains methods for manipulating @@ -32,16 +30,11 @@ * {...@link com.google.gwt.user.client.Event events}. */ public class DOM { - // The current event being fired private static Event currentEvent = null; private static final DOMImpl impl = GWT.create(DOMImpl.class); private static Element sCaptureElem; - // <BrowserEventPreview> - @SuppressWarnings("deprecation") - private static ArrayList<EventPreview> sEventPreviewStack; - /** * Adds an event preview to the preview stack. As long as this preview remains * on the top of the stack, it will receive all events before they are fired @@ -55,14 +48,7 @@ */ @Deprecated public static void addEventPreview(EventPreview preview) { - impl.maybeInitializeEventSystem(); - - // Add the event preview to the stack. It will automatically - // begin receiving events. - if (sEventPreviewStack == null) { - sEventPreviewStack = new ArrayList<EventPreview>(); - } - sEventPreviewStack.add(preview); + ListenerWrapper.NativePreview.add(preview); } /** @@ -532,7 +518,7 @@ } /** - * Gets the key-repeat state of this event. Only IE supports this attribute. + * Gets the key-repeat state of this event. Only IE supports this attribute. * * @param evt the event to be tested * @return <code>true</code> if this key event was an auto-repeat @@ -909,8 +895,8 @@ * * @param parent the parent element * @param child the child element to add to <code>parent</code> - * @param before an existing child element of <code>parent</code> before - * which <code>child</code> will be inserted + * @param before an existing child element of <code>parent</code> before which + * <code>child</code> will be inserted */ public static void insertBefore(Element parent, Element child, Element before) { parent.insertBefore(child, before); @@ -930,10 +916,10 @@ } /** - * Creates an <code><option></code> element and inserts it as a child - * of the specified <code><select></code> element. If the index is - * less than zero, or greater than or equal to the length of the list, then - * the option element will be appended to the end of the list. + * Creates an <code><option></code> element and inserts it as a child of + * the specified <code><select></code> element. If the index is less + * than zero, or greater than or equal to the length of the list, then the + * option element will be appended to the end of the list. * * @param selectElem the <code><select></code> element * @param item the text of the new item; cannot be <code>null</code> @@ -1012,12 +998,7 @@ */ @Deprecated public static void removeEventPreview(EventPreview preview) { - // Remove the event preview from the stack. If it was on top, - // any preview underneath it will automatically begin to - // receive events. - if (sEventPreviewStack != null) { - sEventPreviewStack.remove(preview); - } + ListenerWrapper.NativePreview.remove(preview); } /** @@ -1270,6 +1251,13 @@ } /** + * Initialize the event system if it has not already been initialized. + */ + static void maybeInitializeEventSystem() { + impl.maybeInitializeEventSystem(); + } + + /** * This method is called directly by native code when event preview is being * used. * @@ -1280,12 +1268,6 @@ static boolean previewEvent(Event evt) { // Fire a NativePreviewEvent to NativePreviewHandlers boolean ret = Event.fireNativePreviewEvent(evt); - - // If event previews are present, redirect events to the topmost of them. - if (sEventPreviewStack != null && sEventPreviewStack.size() > 0) { - EventPreview preview = sEventPreviewStack.get(sEventPreviewStack.size() - 1); - ret = preview.onEventPreview(evt) && ret; - } // If the preview cancels the event, stop it from bubbling and performing // its default action. Check for a null evt to allow unit tests to run. Modified: releases/1.6/user/src/com/google/gwt/user/client/Event.java ============================================================================== --- releases/1.6/user/src/com/google/gwt/user/client/Event.java (original) +++ releases/1.6/user/src/com/google/gwt/user/client/Event.java Thu Jan 15 07:01:51 2009 @@ -30,9 +30,9 @@ * An opaque handle to a native DOM Event. An <code>Event</code> cannot be * created directly. Instead, use the <code>Event</code> type when returning a * native DOM event from JSNI methods. An <code>Event</code> passed back into - * JSNI becomes the original DOM event the <code>Event</code> was created - * from, and can be accessed in JavaScript code as expected. This is typically - * done by calling methods in the {...@link com.google.gwt.user.client.DOM} class. + * JSNI becomes the original DOM event the <code>Event</code> was created from, + * and can be accessed in JavaScript code as expected. This is typically done by + * calling methods in the {...@link com.google.gwt.user.client.DOM} class. * </p> */ public class Event extends JavaScriptObject { @@ -85,6 +85,7 @@ int numHandlers = handlers.size(); for (int i = numHandlers - 1; i >= 0; i--) { handlers.get(i).onPreviewNativeEvent(singleton); + singleton.isFirstHandler = false; } // Kill the event and return @@ -106,6 +107,12 @@ private boolean isConsumed = false; /** + * A boolean indicating that the current handler is at the top of the event + * preview stack. + */ + private boolean isFirstHandler = false; + + /** * The event being previewed. */ private Event nativeEvent; @@ -162,6 +169,15 @@ return isConsumed; } + /** + * Is the current handler the first to preview this event? + * + * @return true if the current handler is the first to preview the event + */ + public boolean isFirstHandler() { + return isFirstHandler; + } + @Override protected void dispatch(NativePreviewHandler handler) { handler.onPreviewNativeEvent(this); @@ -172,6 +188,7 @@ super.revive(); isCanceled = false; isConsumed = false; + isFirstHandler = true; nativeEvent = null; } @@ -304,7 +321,8 @@ public static final int ONSCROLL = 0x04000; /** - * Fired when the user requests an element's context menu (usually by right-clicking). + * Fired when the user requests an element's context menu (usually by + * right-clicking). * * Note that not all browsers will fire this event (notably Opera, as of 9.5). */ @@ -328,7 +346,7 @@ | ONMOUSEOVER | ONMOUSEOUT; /** - * Value returned by accessors when the actual integer value is undefined. In + * Value returned by accessors when the actual integer value is undefined. In * hosted mode, most accessors assert that the requested attribute is reliable * across all supported browsers. * @@ -338,12 +356,11 @@ public static final int UNDEFINED = 0; /** - * The list of {...@link NativePreviewHandler}. We use a list instead of a + * The list of {...@link NativePreviewHandler}. We use a list instead of a * handler manager for efficiency and because we want to fire the handlers in - * reverse order. When the last handler is removed, handlers is reset to - * null. + * reverse order. When the last handler is removed, handlers is reset to null. */ - private static ArrayList<NativePreviewHandler> handlers; + static ArrayList<NativePreviewHandler> handlers; /** * Adds an event preview to the preview stack. As long as this preview remains @@ -381,12 +398,14 @@ public static HandlerRegistration addNativePreviewHandler( final NativePreviewHandler handler) { assert handler != null : "Cannot add a null handler"; + DOM.maybeInitializeEventSystem(); + // Initialize the type NativePreviewEvent.getType(); if (handlers == null) { handlers = new ArrayList<NativePreviewHandler>(); } - handlers.add(handler); + handlers.add(handler); return new HandlerRegistration() { public void removeHandler() { if (handlers != null) { @@ -430,7 +449,7 @@ * @see #setCapture(Element) */ public static void releaseCapture(Element elem) { - DOM.releaseCapture(elem.<com.google.gwt.user.client.Element>cast()); + DOM.releaseCapture(elem.<com.google.gwt.user.client.Element> cast()); } /** @@ -453,7 +472,7 @@ * @param elem the element on which to set mouse capture */ public static void setCapture(Element elem) { - DOM.setCapture(elem.<com.google.gwt.user.client.Element>cast()); + DOM.setCapture(elem.<com.google.gwt.user.client.Element> cast()); } /** Modified: releases/1.6/user/src/com/google/gwt/user/client/ListenerWrapper.java ============================================================================== --- releases/1.6/user/src/com/google/gwt/user/client/ListenerWrapper.java (original) +++ releases/1.6/user/src/com/google/gwt/user/client/ListenerWrapper.java Thu Jan 15 07:01:51 2009 @@ -25,21 +25,21 @@ import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.event.shared.GwtEvent.Type; +import com.google.gwt.user.client.Event.NativePreviewEvent; import java.util.EventListener; /** - * Legacy listener support hierarchy for <code>com.google.gwt.user.client</code>. - * Gathers the bulk of the legacy glue code in one place, for easy deletion when - * Listener methods are deleted. + * Legacy listener support for <code>com.google.gwt.user.client</code>. Gathers + * the bulk of the legacy glue code in one place, for easy deletion when + * Listener methods are deleted. * - * @see com.google.gwt.user.ListenerWrapper * @param <T> listener type */ @Deprecated abstract class ListenerWrapper<T> implements EventHandler { - public static class HistoryChange extends ListenerWrapper<HistoryListener> implements - ValueChangeHandler<String> { + public static class HistoryChange extends ListenerWrapper<HistoryListener> + implements ValueChangeHandler<String> { @Deprecated public static void add(HistoryListener listener) { History.addValueChangeHandler(new HistoryChange(listener)); @@ -58,8 +58,46 @@ } } - public static class WindowClose extends ListenerWrapper<WindowCloseListener> implements - Window.ClosingHandler, CloseHandler<Window> { + public static class NativePreview extends ListenerWrapper<EventPreview> + implements Event.NativePreviewHandler { + @Deprecated + public static void add(EventPreview listener) { + Event.addNativePreviewHandler(new NativePreview(listener)); + } + + public static void remove(EventPreview listener) { + if (Event.handlers == null) { + return; + } + int handlerCount = Event.handlers.size(); + // We only want to remove the first instance, as the legacy listener does + for (int i = 0; i < handlerCount; i++) { + Event.NativePreviewHandler handler = Event.handlers.get(i); + if (handler instanceof NativePreview + && ((NativePreview) handler).listener.equals(listener)) { + Event.handlers.remove(handler); + return; + } + } + } + + private NativePreview(EventPreview listener) { + super(listener); + } + + public void onPreviewNativeEvent(NativePreviewEvent event) { + // The legacy EventHandler should only fire if it is on the top of the + // stack (ie. the last one added). + if (event.isFirstHandler()) { + if (!listener.onEventPreview(event.getNativeEvent())) { + event.cancel(); + } + } + } + } + + public static class WindowClose extends ListenerWrapper<WindowCloseListener> + implements Window.ClosingHandler, CloseHandler<Window> { @Deprecated public static void add(WindowCloseListener listener) { WindowClose handler = new WindowClose(listener); @@ -89,8 +127,8 @@ } } - public static class WindowResize extends ListenerWrapper<WindowResizeListener> implements - ResizeHandler { + public static class WindowResize extends + ListenerWrapper<WindowResizeListener> implements ResizeHandler { @Deprecated public static void add(WindowResizeListener listener) { Window.addResizeHandler(new WindowResize(listener)); @@ -110,8 +148,8 @@ } } - public static class WindowScroll extends ListenerWrapper<WindowScrollListener> implements - Window.ScrollHandler { + public static class WindowScroll extends + ListenerWrapper<WindowScrollListener> implements Window.ScrollHandler { @Deprecated public static void add(WindowScrollListener listener) { Window.addWindowScrollHandler(new WindowScroll(listener)); @@ -131,7 +169,6 @@ } } - // This is an internal helper method with the current formulation, we have // lost the info needed to make it safe by this point. @SuppressWarnings("unchecked") @@ -153,7 +190,7 @@ } } } - + /** * Listener being wrapped. */ Modified: releases/1.6/user/src/com/google/gwt/user/client/impl/DOMImpl.java ============================================================================== --- releases/1.6/user/src/com/google/gwt/user/client/impl/DOMImpl.java (original) +++ releases/1.6/user/src/com/google/gwt/user/client/impl/DOMImpl.java Thu Jan 15 07:01:51 2009 @@ -157,9 +157,6 @@ public abstract void insertChild(Element parent, Element child, int index); - /** - * Initialize the event system if it has not already been initialized. - */ public void maybeInitializeEventSystem() { if (!eventSystemIsInitialized) { initEventSystem(); Modified: releases/1.6/user/src/com/google/gwt/user/client/ui/PopupPanel.java ============================================================================== --- releases/1.6/user/src/com/google/gwt/user/client/ui/PopupPanel.java (original) +++ releases/1.6/user/src/com/google/gwt/user/client/ui/PopupPanel.java Thu Jan 15 07:01:51 2009 @@ -829,7 +829,7 @@ @SuppressWarnings("deprecation") protected void onPreviewNativeEvent(NativePreviewEvent event) { // Cancel the event based on the deprecated onEventPreview() method - if (!event.isCanceled() && !onEventPreview(event.getNativeEvent())) { + if (event.isFirstHandler() && !onEventPreview(event.getNativeEvent())) { event.cancel(); } } Modified: releases/1.6/user/test/com/google/gwt/user/client/EventTest.java ============================================================================== --- releases/1.6/user/test/com/google/gwt/user/client/EventTest.java (original) +++ releases/1.6/user/test/com/google/gwt/user/client/EventTest.java Thu Jan 15 07:01:51 2009 @@ -132,17 +132,20 @@ /** * Test that {...@link Event#fireNativePreviewEvent(Event)} fires handlers in - * reverse order. Also verify that the legacy EventPreview fires last. + * reverse order, and that the legacy EventPreview fires only if it is at the + * top of the stack. */ @SuppressWarnings("deprecation") public void testFireNativePreviewEventReverseOrder() { - final TestEventPreview preview = new TestEventPreview(false); + final TestEventPreview preview0 = new TestEventPreview(false); + final TestEventPreview preview1 = new TestEventPreview(false); final TestNativePreviewHandler handler0 = new TestNativePreviewHandler( false, false) { @Override public void onPreviewNativeEvent(NativePreviewEvent event) { super.onPreviewNativeEvent(event); - preview.assertIsFired(false); + preview0.assertIsFired(false); + preview1.assertIsFired(true); } }; final TestNativePreviewHandler handler1 = new TestNativePreviewHandler( @@ -151,7 +154,8 @@ public void onPreviewNativeEvent(NativePreviewEvent event) { super.onPreviewNativeEvent(event); handler0.assertIsFired(false); - preview.assertIsFired(false); + preview0.assertIsFired(false); + preview1.assertIsFired(true); } }; final TestNativePreviewHandler handler2 = new TestNativePreviewHandler( @@ -161,7 +165,8 @@ super.onPreviewNativeEvent(event); handler0.assertIsFired(false); handler1.assertIsFired(false); - preview.assertIsFired(false); + preview0.assertIsFired(false); + preview1.assertIsFired(true); } }; final TestNativePreviewHandler handler3 = new TestNativePreviewHandler( @@ -172,25 +177,29 @@ handler0.assertIsFired(false); handler1.assertIsFired(false); handler2.assertIsFired(false); - preview.assertIsFired(false); + preview0.assertIsFired(false); + preview1.assertIsFired(true); } }; + DOM.addEventPreview(preview0); HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0); HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1); HandlerRegistration reg2 = Event.addNativePreviewHandler(handler2); HandlerRegistration reg3 = Event.addNativePreviewHandler(handler3); - DOM.addEventPreview(preview); + DOM.addEventPreview(preview1); assertTrue(DOM.previewEvent(null)); handler0.assertIsFired(true); handler1.assertIsFired(true); handler2.assertIsFired(true); handler3.assertIsFired(true); - preview.assertIsFired(true); + preview0.assertIsFired(false); + preview1.assertIsFired(true); reg0.removeHandler(); reg1.removeHandler(); reg2.removeHandler(); reg3.removeHandler(); - DOM.removeEventPreview(preview); + DOM.removeEventPreview(preview0); + DOM.removeEventPreview(preview1); } /** --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---