Author: jlaba...@google.com
Date: Thu Jan 15 12:38:29 2009
New Revision: 4474

Modified:
     
releases/1.6/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
     
releases/1.6/user/src/com/google/gwt/event/logical/shared/ResizeEvent.java
     
releases/1.6/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
     
releases/1.6/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java
    releases/1.6/user/src/com/google/gwt/event/shared/HandlerManager.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/Window.java
    releases/1.6/user/src/com/google/gwt/user/client/ui/FormPanel.java
     
releases/1.6/user/test/com/google/gwt/event/shared/HandlerManagerTest.java
    releases/1.6/user/test/com/google/gwt/user/client/EventTest.java

Log:
Adds an option to HandlerManager to fire handlers in reverse order, and  
converts NativePreviewEvent to use the HandlerManager instead of an  
ArrayList.  The HandlerManager automatically handles concurrent adds and  
removes, which caused a problem in MenuBar.

Patch by: jlabanca
Review by: ecc (desk)
Issue: 3289



Modified:  
releases/1.6/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
==============================================================================
---  
releases/1.6/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
      
(original)
+++  
releases/1.6/user/src/com/google/gwt/event/logical/shared/BeforeSelectionEvent.java
      
Thu Jan 15 12:38:29 2009
@@ -91,7 +91,7 @@
    // field itself does not, so we have to do an unsafe cast here.
    @SuppressWarnings("unchecked")
    @Override
-  public Type<BeforeSelectionHandler<I>> getAssociatedType() {
+  public final Type<BeforeSelectionHandler<I>> getAssociatedType() {
      return (Type) TYPE;
    }


Modified:  
releases/1.6/user/src/com/google/gwt/event/logical/shared/ResizeEvent.java
==============================================================================
---  
releases/1.6/user/src/com/google/gwt/event/logical/shared/ResizeEvent.java      
 
(original)
+++  
releases/1.6/user/src/com/google/gwt/event/logical/shared/ResizeEvent.java      
 
Thu Jan 15 12:38:29 2009
@@ -76,7 +76,7 @@
    }

    @Override
-  public Type<ResizeHandler> getAssociatedType() {
+  public final Type<ResizeHandler> getAssociatedType() {
      return TYPE;
    }


Modified:  
releases/1.6/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java
==============================================================================
---  
releases/1.6/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java   
 
(original)
+++  
releases/1.6/user/src/com/google/gwt/event/logical/shared/SelectionEvent.java   
 
Thu Jan 15 12:38:29 2009
@@ -76,7 +76,7 @@
    // field itself does not, so we have to do an unsafe cast here.
    @SuppressWarnings("unchecked")
    @Override
-  public Type<SelectionHandler<I>> getAssociatedType() {
+  public final Type<SelectionHandler<I>> getAssociatedType() {
      return (Type) TYPE;
    }


Modified:  
releases/1.6/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java
==============================================================================
---  
releases/1.6/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java 
 
(original)
+++  
releases/1.6/user/src/com/google/gwt/event/logical/shared/ValueChangeEvent.java 
 
Thu Jan 15 12:38:29 2009
@@ -54,7 +54,6 @@
     * safe handling of null.
     *
     * @param <I> the old value type
-   * @param <S> The event source
     * @param source the source of the handlers
     * @param oldValue the oldValue, may be null
     * @param newValue the newValue, may be null
@@ -110,7 +109,7 @@
    // field itself does not, so we have to do an unsafe cast here.
    @SuppressWarnings("unchecked")
    @Override
-  public Type<ValueChangeHandler<I>> getAssociatedType() {
+  public final Type<ValueChangeHandler<I>> getAssociatedType() {
      return (Type) TYPE;
    }


Modified:  
releases/1.6/user/src/com/google/gwt/event/shared/HandlerManager.java
==============================================================================
--- releases/1.6/user/src/com/google/gwt/event/shared/HandlerManager.java       
 
(original)
+++ releases/1.6/user/src/com/google/gwt/event/shared/HandlerManager.java       
 
Thu Jan 15 12:38:29 2009
@@ -44,12 +44,20 @@
        l.add(handler);
      }

-    private <H extends EventHandler> void fireEvent(GwtEvent<H> event) {
+    private <H extends EventHandler> void fireEvent(GwtEvent<H> event,
+        boolean isReverseOrder) {
        Type<H> type = event.getAssociatedType();
        int count = getHandlerCount(type);
-      for (int i = 0; i < count; i++) {
-        H handler = this.<H> getHandler(type, i);
-        event.dispatch(handler);
+      if (isReverseOrder) {
+        for (int i = count - 1; i >= 0; i--) {
+          H handler = this.<H> getHandler(type, i);
+          event.dispatch(handler);
+        }
+      } else {
+        for (int i = 0; i < count; i++) {
+          H handler = this.<H> getHandler(type, i);
+          event.dispatch(handler);
+        }
        }
      }

@@ -79,6 +87,7 @@
    }

    private int firingDepth = 0;
+  private boolean isReverseOrder;

    // map storing the actual handlers
    private HandlerRegistry registry;
@@ -90,13 +99,26 @@
    private List<Command> deferredDeltas;

    /**
-   * Creates a handler manager with the given source.
+   * Creates a handler manager with the given source. Handlers will be  
fired in
+   * the order that they are added.
     *
     * @param source the event source
     */
    public HandlerManager(Object source) {
+    this(source, false);
+  }
+
+  /**
+   * 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
+   */
+  public HandlerManager(Object source, boolean fireInReverseOrder) {
      registry = new HandlerRegistry();
      this.source = source;
+    this.isReverseOrder = fireInReverseOrder;
    }

    /**
@@ -140,7 +162,7 @@
      try {
        firingDepth++;

-      registry.fireEvent(event);
+      registry.fireEvent(event, isReverseOrder);

      } finally {
        firingDepth--;

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  
12:38:29 2009
@@ -20,11 +20,9 @@
  import com.google.gwt.event.dom.client.HasNativeEvent;
  import com.google.gwt.event.shared.EventHandler;
  import com.google.gwt.event.shared.GwtEvent;
+import com.google.gwt.event.shared.HandlerManager;
  import com.google.gwt.event.shared.HandlerRegistration;

-import java.util.ArrayList;
-import java.util.List;
-
  /**
   * <p>
   * An opaque handle to a native DOM Event. An <code>Event</code> cannot be
@@ -67,29 +65,18 @@
      /**
       * Fire a {...@link NativePreviewEvent} for the native event.
       *
-     * @param handlers the list of {...@link NativePreviewHandler}
+     * @param handlers the {...@link HandlerManager}
       * @param nativeEvent the native event
       * @return true to fire the event normally, false to cancel the event
       */
-    static boolean fire(List<NativePreviewHandler> handlers, Event  
nativeEvent) {
+    private static boolean fire(HandlerManager handlers, Event  
nativeEvent) {
        if (TYPE != null && handlers != null) {
          // Revive the event
-        if (singleton == null) {
-          singleton = new NativePreviewEvent();
-        } else {
-          singleton.revive();
-        }
+        singleton.revive();
          singleton.setNativeEvent(nativeEvent);

-        // Fire the event to all handlers
-        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
-        singleton.kill();
+        // Fire the event
+        handlers.fireEvent(singleton);
          return !(singleton.isCanceled() && !singleton.isConsumed());
        }
        return true;
@@ -139,7 +126,7 @@
      }

      @Override
-    public Type<NativePreviewHandler> getAssociatedType() {
+    public final Type<NativePreviewHandler> getAssociatedType() {
        return TYPE;
      }

@@ -181,6 +168,7 @@
      @Override
      protected void dispatch(NativePreviewHandler handler) {
        handler.onPreviewNativeEvent(this);
+      singleton.isFirstHandler = false;
      }

      @Override
@@ -360,7 +348,7 @@
     * 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.
     */
-  static ArrayList<NativePreviewHandler> handlers;
+  static HandlerManager handlers;

    /**
     * Adds an event preview to the preview stack. As long as this preview  
remains
@@ -403,20 +391,10 @@
      // Initialize the type
      NativePreviewEvent.getType();
      if (handlers == null) {
-      handlers = new ArrayList<NativePreviewHandler>();
+      handlers = new HandlerManager(null, true);
+      NativePreviewEvent.singleton = new NativePreviewEvent();
      }
-    handlers.add(handler);
-    return new HandlerRegistration() {
-      public void removeHandler() {
-        if (handlers != null) {
-          handlers.remove(handler);
-          if (handlers.size() == 0) {
-            // Set handlers to null so we can optimize  
fireNativePreviewEvent
-            handlers = null;
-          }
-        }
-      }
-    };
+    return handlers.addHandler(NativePreviewEvent.TYPE, handler);
    }

    /**

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 12:38:29 2009
@@ -27,8 +27,6 @@
  import com.google.gwt.event.shared.GwtEvent.Type;
  import com.google.gwt.user.client.Event.NativePreviewEvent;

-import java.util.EventListener;
-
  /**
   * 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
@@ -66,19 +64,7 @@
      }

      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;
-        }
-      }
+      baseRemove(Event.handlers, listener, NativePreviewEvent.getType());
      }

      private NativePreview(EventPreview listener) {
@@ -175,7 +161,7 @@
    // This is a direct copy of the baseRemove from
    // com.google.gwt.user.client.ui.ListenerWrapper. Change in parallel.
    static <H extends EventHandler> void baseRemove(HandlerManager manager,
-      EventListener listener, Type... keys) {
+      Object listener, Type... keys) {
      if (manager != null) {
        for (Type<H> key : keys) {
          int handlerCount = manager.getHandlerCount(key);

Modified: releases/1.6/user/src/com/google/gwt/user/client/Window.java
==============================================================================
--- releases/1.6/user/src/com/google/gwt/user/client/Window.java        
(original)
+++ releases/1.6/user/src/com/google/gwt/user/client/Window.java        Thu Jan 
15  
12:38:29 2009
@@ -64,7 +64,7 @@
      private String message = null;

      @Override
-    public Type<ClosingHandler> getAssociatedType() {
+    public final Type<ClosingHandler> getAssociatedType() {
        return TYPE;
      }

@@ -332,7 +332,7 @@
      }

      @Override
-    public Type<ScrollHandler> getAssociatedType() {
+    public final Type<ScrollHandler> getAssociatedType() {
        return TYPE;
      }


Modified: releases/1.6/user/src/com/google/gwt/user/client/ui/FormPanel.java
==============================================================================
--- releases/1.6/user/src/com/google/gwt/user/client/ui/FormPanel.java   
(original)
+++ releases/1.6/user/src/com/google/gwt/user/client/ui/FormPanel.java  Thu  
Jan 15 12:38:29 2009
@@ -87,7 +87,7 @@
      private String resultHtml;

      /**
-     * Create a submit complete event
+     * Create a submit complete event.
       *
       * @param resultsHtml the results from submitting the form
       */
@@ -96,7 +96,7 @@
      }

      @Override
-    public Type<SubmitCompleteHandler> getAssociatedType() {
+    public final Type<SubmitCompleteHandler> getAssociatedType() {
        return TYPE;
      }

@@ -162,7 +162,7 @@
      }

      @Override
-    public Type<FormPanel.SubmitHandler> getAssociatedType() {
+    public final Type<FormPanel.SubmitHandler> getAssociatedType() {
        return TYPE;
      }


Modified:  
releases/1.6/user/test/com/google/gwt/event/shared/HandlerManagerTest.java
==============================================================================
---  
releases/1.6/user/test/com/google/gwt/event/shared/HandlerManagerTest.java      
 
(original)
+++  
releases/1.6/user/test/com/google/gwt/event/shared/HandlerManagerTest.java      
 
Thu Jan 15 12:38:29 2009
@@ -223,7 +223,6 @@
      assertFired(one, mouse1);
    }

-  @SuppressWarnings("deprecation")
    public void testMultiFiring() {

      HandlerManager manager = new HandlerManager("source1");
@@ -260,5 +259,39 @@
      manager.fireEvent(new MouseDownEvent() {
      });
      assertFired(mouse1, adaptor1, mouse3);
+  }
+
+  public void testReverseOrder() {
+    // Add some handlers to a manager
+    final HandlerManager manager = new HandlerManager("source1", true);
+    final MouseDownHandler handler0 = new MouseDownHandler() {
+      public void onMouseDown(MouseDownEvent event) {
+        add(this);
+      }
+    };
+    final MouseDownHandler handler1 = new MouseDownHandler() {
+      public void onMouseDown(MouseDownEvent event) {
+        assertNotFired(handler0);
+        add(this);
+      }
+    };
+    final MouseDownHandler handler2 = new MouseDownHandler() {
+      public void onMouseDown(MouseDownEvent event) {
+        assertNotFired(handler0, handler1);
+        add(this);
+      }
+    };
+    HandlerRegistration reg0 = manager.addHandler(MouseDownEvent.getType(),
+        handler0);
+    HandlerRegistration reg1 = manager.addHandler(MouseDownEvent.getType(),
+        handler1);
+    HandlerRegistration reg2 = manager.addHandler(MouseDownEvent.getType(),
+        handler2);
+
+    // Fire the event
+    reset();
+    manager.fireEvent(new MouseDownEvent() {
+    });
+    assertFired(handler0, handler1, handler2);
    }
  }

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 12:38:29 2009
@@ -94,6 +94,36 @@
    }

    /**
+   * Test that concurrent removal of a {...@link NativePreviewHandler} does  
not
+   * trigger an exception. The handler should not actually be removed  
until the
+   * end of the event loop.
+   */
+  public void testConcurrentRemovalOfNativePreviewHandler() {
+    // Add handler0
+    final TestNativePreviewHandler handler0 = new TestNativePreviewHandler(
+        false, false);
+    final HandlerRegistration reg0 =  
Event.addNativePreviewHandler(handler0);
+
+    // Add handler 1
+    final TestNativePreviewHandler handler1 = new TestNativePreviewHandler(
+        false, false) {
+      @Override
+      public void onPreviewNativeEvent(NativePreviewEvent event) {
+        super.onPreviewNativeEvent(event);
+        handler0.assertIsFired(false);
+        reg0.removeHandler();
+      }
+    };
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+    assertTrue(Event.fireNativePreviewEvent(null));
+
+    // Verify both handlers fired even though one was removed
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(true);
+    reg1.removeHandler();
+  }
+
+  /**
     * Test that {...@link Event#fireNativePreviewEvent(Event)} returns the  
correct
     * value if the native event is canceled.
     */
@@ -146,6 +176,7 @@
          super.onPreviewNativeEvent(event);
          preview0.assertIsFired(false);
          preview1.assertIsFired(true);
+        assertFalse(event.isFirstHandler());
        }
      };
      final TestNativePreviewHandler handler1 = new TestNativePreviewHandler(
@@ -156,6 +187,7 @@
          handler0.assertIsFired(false);
          preview0.assertIsFired(false);
          preview1.assertIsFired(true);
+        assertFalse(event.isFirstHandler());
        }
      };
      final TestNativePreviewHandler handler2 = new TestNativePreviewHandler(
@@ -167,6 +199,7 @@
          handler1.assertIsFired(false);
          preview0.assertIsFired(false);
          preview1.assertIsFired(true);
+        assertFalse(event.isFirstHandler());
        }
      };
      final TestNativePreviewHandler handler3 = new TestNativePreviewHandler(
@@ -179,6 +212,7 @@
          handler2.assertIsFired(false);
          preview0.assertIsFired(false);
          preview1.assertIsFired(true);
+        assertFalse(event.isFirstHandler());
        }
      };
      DOM.addEventPreview(preview0);
@@ -408,6 +442,7 @@
        public void onPreviewNativeEvent(NativePreviewEvent event) {
          assertFalse(event.isCanceled());
          assertFalse(event.isConsumed());
+        assertTrue(event.isFirstHandler());
          super.onPreviewNativeEvent(event);
        }
      };

--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to