Merging releases/1.6@4366 :4385 into trunk.

svn merge -r4366:4385 https://google-web-toolkit.googlecode.com/svn/releases/1.6 .



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4386 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
index 6b7d755..3acd448 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JClassType.java
@@ -27,14 +27,22 @@
     HasMetaData {
 
   /**
+   * Cached set of supertypes for this type (including itself).  If null,
+   * the set has not been calculated yet.
+   */
+  private Set<JClassType> flattenedSupertypes;
+  
+  /**
    * Returns all of the superclasses and superinterfaces for a given type
    * including the type itself.
    */
   protected static Set<JClassType> getFlattenedSuperTypeHierarchy(
       JClassType type) {
-    Set<JClassType> typesSeen = new HashSet<JClassType>();
-    getFlattenedSuperTypeHierarchyRecursive(type, typesSeen);
-    return typesSeen;
+    if (type.flattenedSupertypes == null) {
+      type.flattenedSupertypes = new HashSet<JClassType>();
+      getFlattenedSuperTypeHierarchyRecursive(type, type.flattenedSupertypes);
+    }
+    return type.flattenedSupertypes;
   }
 
   /**
@@ -309,13 +317,13 @@
     // Superclass
     JClassType superclass = type.getSuperclass();
     if (superclass != null) {
-      getFlattenedSuperTypeHierarchyRecursive(superclass, typesSeen);
+      typesSeen.addAll(getFlattenedSuperTypeHierarchy(superclass));
     }
 
     // Check the interfaces
     JClassType[] intfs = type.getImplementedInterfaces();
     for (JClassType intf : intfs) {
-      getFlattenedSuperTypeHierarchyRecursive(intf, typesSeen);
+      typesSeen.addAll(getFlattenedSuperTypeHierarchy(intf));
     }
   }
 
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
index 75e8e2e..424a3ca 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
@@ -22,6 +22,7 @@
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -167,7 +168,11 @@
     }
   }
 
-  private final Set<JRealClassType> allTypes = new HashSet<JRealClassType>();
+  /**
+   * A map of fully-qualify source names (ie, use "." rather than "$" for nested
+   * classes) to JRealClassTypes.
+   */
+  private final Map<String, JRealClassType> allTypes = new HashMap<String, JRealClassType>();
 
   private final Map<JType, JArrayType> arrayTypes = new IdentityHashMap<JType, JArrayType>();
 
@@ -210,33 +215,16 @@
   }
 
   /**
-   * Finds a class or interface given its fully-qualified name. For nested
+   * Finds a class or interface given its fully-qualified name.
+   *
+   * @param name fully-qualified class/interface name -  for nested
    * classes, use its source name rather than its binary name (that is, use a
-   * "." rather than a "$").
+   * "." rather than a "$")
    * 
    * @return <code>null</code> if the type is not found
    */
   public JClassType findType(String name) {
-    // Try the dotted pieces, right to left.
-    //
-    int i = name.length() - 1;
-    while (i >= 0) {
-      int dot = name.lastIndexOf('.', i);
-      String pkgName = "";
-      String typeName = name;
-      if (dot != -1) {
-        pkgName = name.substring(0, dot);
-        typeName = name.substring(dot + 1);
-        i = dot - 1;
-      } else {
-        i = -1;
-      }
-      JClassType result = findType(pkgName, typeName);
-      if (result != null) {
-        return result;
-      }
-    }
-    return null;
+    return allTypes.get(name);
   }
 
   /**
@@ -482,7 +470,8 @@
    * @return an array of types, possibly of zero length
    */
   public JClassType[] getTypes() {
-    return allTypes.toArray(NO_JCLASSES);
+    Collection<JRealClassType> values = allTypes.values();
+    return values.toArray(new JClassType[values.size()]);
   }
 
   public JWildcardType getWildcardType(JWildcardType.BoundType boundType,
@@ -611,7 +600,8 @@
   }
 
   void addNewType(JRealClassType newType) {
-    allTypes.add(newType);
+    String fqcn = newType.getQualifiedSourceName();
+    allTypes.put(fqcn, newType);
     recentTypes.add(newType);
   }
 
@@ -990,9 +980,9 @@
    */
   private void removeTypes(Set<JRealClassType> invalidTypes) {
     for (Iterator<JRealClassType> iter = invalidTypes.iterator(); iter.hasNext();) {
-      JClassType classType = iter.next();
-
-      allTypes.remove(classType);
+      JRealClassType classType = iter.next();
+      String fqcn = classType.getQualifiedSourceName();
+      allTypes.remove(fqcn);
 
       JPackage pkg = classType.getPackage();
       if (pkg != null) {
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
index 666b1e6..6076260 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileClassPathEntry.java
@@ -52,6 +52,7 @@
 
   private Set<ZipFileResource> allZipFileResources;
   private Set<AbstractResource> cachedAnswers;
+  private String cachedLocation;
   private PathPrefixSet lastPrefixSet;
   private final ZipFile zipFile;
 
@@ -80,7 +81,10 @@
 
   @Override
   public String getLocation() {
-    return new File(zipFile.getName()).toURI().toString();
+    if (cachedLocation == null) {
+      cachedLocation = new File(zipFile.getName()).toURI().toString();
+    }
+    return cachedLocation;
   }
 
   public ZipFile getZipFile() {
diff --git a/eclipse/settings/code-style/gwt-checkstyle-tests.xml b/eclipse/settings/code-style/gwt-checkstyle-tests.xml
index ea2aa98..87f66b2 100644
--- a/eclipse/settings/code-style/gwt-checkstyle-tests.xml
+++ b/eclipse/settings/code-style/gwt-checkstyle-tests.xml
@@ -89,7 +89,7 @@
         </module>
         <module name="RegexpHeader">
             <property name="severity" value="error"/>
-            <property name="header" value="/\*\n \* Copyright 200[678] Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the &quot;License&quot;\); you may not\n \* use this file except in compliance with the License\. You may obtain a copy of\n \* the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software\n \* distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT\n \* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the\n \* License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>
+            <property name="header" value="/\*\n \* Copyright 200[6789] Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the &quot;License&quot;\); you may not\n \* use this file except in compliance with the License\. You may obtain a copy of\n \* the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software\n \* distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT\n \* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the\n \* License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>
         </module>
         <module name="ImportOrder">
             <property name="severity" value="error"/>
diff --git a/eclipse/settings/code-style/gwt-checkstyle.xml b/eclipse/settings/code-style/gwt-checkstyle.xml
index a2c9272..17aa99c 100644
--- a/eclipse/settings/code-style/gwt-checkstyle.xml
+++ b/eclipse/settings/code-style/gwt-checkstyle.xml
@@ -82,7 +82,7 @@
         </module>
         <module name="RegexpHeader">
             <property name="severity" value="error"/>
-            <property name="header" value="/\*\n \* Copyright 200[678] Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the &quot;License&quot;\); you may not\n \* use this file except in compliance with the License\. You may obtain a copy of\n \* the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software\n \* distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT\n \* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the\n \* License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>            
+            <property name="header" value="/\*\n \* Copyright 200[6789] Google Inc\.\n \*[ ]*\n \* Licensed under the Apache License, Version 2\.0 \(the &quot;License&quot;\); you may not\n \* use this file except in compliance with the License\. You may obtain a copy of\n \* the License at\n \*[ ]*\n \* http://www\.apache\.org/licenses/LICENSE-2\.0\n \*[ ]*\n \* Unless required by applicable law or agreed to in writing, software\n \* distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT\n \* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\. See the\n \* License for the specific language governing permissions and limitations under\n \* the License\.\n \*/"/>            
         </module>
         <module name="ImportOrder">
             <property name="severity" value="error"/>
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java
index 67b5d33..e51c222 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue1932.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -21,8 +21,9 @@
 import com.google.gwt.museum.client.common.AbstractIssue;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.EventPreview;
 import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.Event.NativePreviewHandler;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.Composite;
 import com.google.gwt.user.client.ui.Grid;
@@ -116,29 +117,29 @@
     sandbox.getElement().getStyle().setProperty("cursor", "crosshair");
 
     // Keep the crosshair under the cursor
-    DOM.addEventPreview(new EventPreview() {
-      public boolean onEventPreview(Event event) {
+    Event.addNativePreviewHandler(new NativePreviewHandler() {
+      public void onPreviewNativeEvent(NativePreviewEvent event) {
         // Ignore events outside of the sandbox
-        Element target = DOM.eventGetTarget(event);
+        Event nativeEvent = event.getNativeEvent();
+        Element target = nativeEvent.getTarget();
         if (!sandbox.getElement().isOrHasChild(target)
             && !positioner.getElement().isOrHasChild(target)) {
           positioner.removeFromParent();
-          return true;
+          return;
         }
 
-        switch (DOM.eventGetType(event)) {
+        switch (nativeEvent.getTypeInt()) {
           case Event.ONMOUSEMOVE:
-            int absX = event.getClientX() + Window.getScrollLeft();
-            int absY = event.getClientY() + Window.getScrollTop();
+            int absX = nativeEvent.getClientX() + Window.getScrollLeft();
+            int absY = nativeEvent.getClientY() + Window.getScrollTop();
             RootPanel.get().add(positioner, absX, absY);
 
-            echo.setHTML("event.clientX: " + event.getClientX() + "<br>"
-                + "event.clientY: " + event.getClientY() + "<br>"
+            echo.setHTML("event.clientX: " + nativeEvent.getClientX() + "<br>"
+                + "event.clientY: " + nativeEvent.getClientY() + "<br>"
                 + "absolute left: " + positioner.getAbsoluteLeft() + "<br>"
                 + "absolute top: " + positioner.getAbsoluteTop());
             break;
         }
-        return true;
       }
     });
 
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDialogBox.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDialogBox.java
index 403d7be..40df95a 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDialogBox.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForDialogBox.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -17,13 +17,18 @@
 
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
 import com.google.gwt.event.dom.client.MouseDownEvent;
 import com.google.gwt.event.dom.client.MouseDownHandler;
 import com.google.gwt.museum.client.common.AbstractIssue;
 import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.DialogBox;
 import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
 import com.google.gwt.user.client.ui.Widget;
 
 import java.util.HashMap;
@@ -80,12 +85,14 @@
             maybeClose = true;
             return;
           }
+          break;
         case Event.ONMOUSEUP:
           if (maybeClose && isCloseBoxEvent(event)) {
             maybeClose = false;
             hide();
             return;
           }
+          break;
       }
       maybeClose = false;
       super.onBrowserEvent(event);
@@ -149,22 +156,46 @@
 
   @Override
   public Widget createIssue() {
+    // Create a few extra dialog boxes
+    final DialogBox dialog0 = showCustomDialog(true, true, false, "Dialog 0",
+        "I cannot be dragged or closed until Dialog 2 is closed", 0, 100);
+    final DialogBox dialog1 = showCustomDialog(true, false, false, "Dialog 1",
+        "I cannot be dragged or closed until Dialog 2 is closed", 0, 200);
+    final DialogBox dialog2 = showCustomDialog(false, false, true, "Dialog 2",
+        "I can be dragged", 0, 300);
+    final DialogBox dialog3 = showCustomDialog(
+        true,
+        false,
+        false,
+        "Dialog 3",
+        "I should auto close as soon as you click outside of me and Dialog 4 or greater",
+        0, 400);
+    final DialogBox dialog4 = showCustomDialog(false, false, false, "Dialog 4",
+        "I can be dragged", 0, 500);
+
     final VisibleDialogBox dialog = showVisibleDialog();
 
     SimplePanel panel = new SimplePanel() {
       @Override
       protected void onUnload() {
-        dialog.hide();
+        if (dialog.isAttached()) {
+          dialog.hide();
+          dialog0.hide();
+          dialog1.hide();
+          dialog2.hide();
+          dialog3.hide();
+          dialog4.hide();
+        }
       }
     };
-
     return panel;
   }
 
   @Override
   public String getInstructions() {
     return "Confirm color change on mouse over caption, that the "
-        + "custom close box works, and that each mouse event fires.";
+        + "custom close box works, and that each mouse event fires.  "
+        + "Verify that the text in each DialogBox is true.";
   }
 
   @Override
@@ -177,6 +208,37 @@
     return false;
   }
 
+  private DialogBox showCustomDialog(boolean autoHide,
+      boolean previewAllEvents, boolean modal, String caption, String message,
+      int left, int top) {
+    final DialogBox dialog = new DialogBox(autoHide, modal);
+    dialog.setPreviewingAllNativeEvents(previewAllEvents);
+
+    // Set the caption
+    caption += " (autoHide=" + dialog.isAutoHideEnabled();
+    caption += ", previewAllEvents=" + dialog.isPreviewingAllNativeEvents();
+    caption += ", modal=" + dialog.isModal() + ")";
+    dialog.setText(caption);
+
+    // Set the content
+    Label content = new Label(message);
+    if (autoHide || previewAllEvents) {
+      dialog.setWidget(content);
+    } else {
+      VerticalPanel vPanel = new VerticalPanel();
+      vPanel.add(content);
+      vPanel.add(new Button("Close", new ClickHandler() {
+        public void onClick(ClickEvent event) {
+          dialog.hide();
+        }
+      }));
+      dialog.setWidget(vPanel);
+    }
+    dialog.setPopupPosition(left, top);
+    dialog.show();
+    return dialog;
+  }
+
   private VisibleDialogBox showVisibleDialog() {
     final VisibleDialogBox dialog = new VisibleDialogBox();
     dialog.setModal(false);
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java
index aadc408..ca8e319 100644
--- a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/VisualsForTree.java
@@ -18,7 +18,9 @@
 
 import com.google.gwt.museum.client.common.AbstractIssue;
 import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.Label;
 import com.google.gwt.user.client.ui.RadioButton;
+import com.google.gwt.user.client.ui.SimplePanel;
 import com.google.gwt.user.client.ui.Tree;
 import com.google.gwt.user.client.ui.TreeItem;
 import com.google.gwt.user.client.ui.VerticalPanel;
@@ -41,6 +43,9 @@
     TreeItem d = new TreeItem(new RadioButton("myradio",
         "I should line up nicely"));
     TreeItem e = new TreeItem(new CheckBox("I should line up nicely"));
+    SimplePanel panel = new SimplePanel();
+    panel.setWidget(new Label("There should not be any space above me"));
+    TreeItem f = new TreeItem(panel);
 
     t.setSelectedItem(b);
     t.addItem(a);
@@ -48,6 +53,7 @@
     t.addItem(c);
     t.addItem(d);
     t.addItem(e);
+    t.addItem(f);
     b.addItem(ba);
     b.addItem(bb);
     bb.addItem(bba);
diff --git a/user/src/com/google/gwt/event/dom/client/DomEvent.java b/user/src/com/google/gwt/event/dom/client/DomEvent.java
index d751bdf..7e2df65 100644
--- a/user/src/com/google/gwt/event/dom/client/DomEvent.java
+++ b/user/src/com/google/gwt/event/dom/client/DomEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -29,7 +29,8 @@
  * @param <H> handler type
  * 
  */
-public abstract class DomEvent<H extends EventHandler> extends GwtEvent<H> {
+public abstract class DomEvent<H extends EventHandler> extends GwtEvent<H>
+    implements HasNativeEvent {
   /**
    * Type class used by dom event subclasses. Type is specialized for dom in
    * order to carry information about the native event.
@@ -61,10 +62,10 @@
      * 
      * 
      * @param eventToSink the integer value used by sink events to set up event
-     * handling for this dom type
+     *          handling for this dom type
      * @param eventName the raw native event name
      * @param flyweight the instance that will be used as a flyweight to wrap a
-     * native event
+     *          native event
      */
     protected Type(int eventToSink, String eventName, DomEvent<H> flyweight) {
       this.flyweight = flyweight;
@@ -100,7 +101,7 @@
   }
 
   private static PrivateMap<Type<?>> registered;
- 
+
   /**
    * Fires the given native event on the specified handlers.
    * 
@@ -122,7 +123,7 @@
       }
     }
   }
- 
+
   // This method can go away once we have eager clinits.
   static void init() {
     registered = new PrivateMap<Type<?>>();
@@ -130,11 +131,6 @@
 
   private Event nativeEvent;
 
-  /**
-   * Gets the underlying native event for this {@link DomEvent}.
-   * 
-   * @return gets the native event
-   */
   public final Event getNativeEvent() {
     assertLive();
     return nativeEvent;
diff --git a/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java b/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java
new file mode 100644
index 0000000..510c273
--- /dev/null
+++ b/user/src/com/google/gwt/event/dom/client/HasNativeEvent.java
@@ -0,0 +1,32 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.event.dom.client;
+
+import com.google.gwt.user.client.Event;
+
+/**
+ * An object that implements this interface has a native event associated with
+ * it.
+ */
+public interface HasNativeEvent {
+  /**
+   * Gets the underlying native event.
+   * 
+   * @return the native event
+   */
+  Event getNativeEvent();
+}
diff --git a/user/src/com/google/gwt/event/shared/GwtEvent.java b/user/src/com/google/gwt/event/shared/GwtEvent.java
index 8eaba34..33787e2 100644
--- a/user/src/com/google/gwt/event/shared/GwtEvent.java
+++ b/user/src/com/google/gwt/event/shared/GwtEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -137,18 +137,19 @@
   }
 
   /**
-   * Revives the event. Used when recycling event instances.
+   * Kill the event.  After the event has been killed, users cannot really on
+   * its values or functions being available.
    */
-  protected void revive() {
-    dead = false;
+  protected void kill() {
+    dead = true;
     source = null;
   }
 
   /**
-   * Called after the event manager has finished processing the event.
+   * Revives the event. Used when recycling event instances.
    */
-  void onRelease() {
-    dead = true;
+  protected void revive() {
+    dead = false;
     source = null;
   }
 
diff --git a/user/src/com/google/gwt/event/shared/HandlerManager.java b/user/src/com/google/gwt/event/shared/HandlerManager.java
index 898ad91..ca4138e 100644
--- a/user/src/com/google/gwt/event/shared/HandlerManager.java
+++ b/user/src/com/google/gwt/event/shared/HandlerManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -378,7 +378,7 @@
     }
     if (oldSource == null) {
       // This was my event, so I should kill it now that I'm done.
-      event.onRelease();
+      event.kill();
     } else {
       // Restoring the source for the next handler to use.
       event.setSource(oldSource);
diff --git a/user/src/com/google/gwt/user/client/DOM.java b/user/src/com/google/gwt/user/client/DOM.java
index b7865d5..8ddd25b 100644
--- a/user/src/com/google/gwt/user/client/DOM.java
+++ b/user/src/com/google/gwt/user/client/DOM.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -39,6 +39,7 @@
   private static Element sCaptureElem;
 
   // <BrowserEventPreview>
+  @SuppressWarnings("deprecation")
   private static ArrayList<EventPreview> sEventPreviewStack;
 
   /**
@@ -49,7 +50,10 @@
    * handlers only receive explicitly sunk events.
    * 
    * @param preview the event preview to be added to the stack.
+   * @deprecated replaced by
+   *             {@link Event#addNativePreviewHandler(Event.NativePreviewHandler)}
    */
+  @Deprecated
   public static void addEventPreview(EventPreview preview) {
     impl.maybeInitializeEventSystem();
 
@@ -90,6 +94,7 @@
    * @return <code>true</code> if they are in fact the same element
    * @deprecated Use identity comparison.
    */
+  @Deprecated
   public static boolean compare(Element elem1, Element elem2) {
     return elem1 == elem2;
   }
@@ -376,8 +381,7 @@
   }
 
   /**
-   * Generates a unique DOM id. The id is of the form "gwt-id-<unique
-   * integer>".
+   * Generates a unique DOM id. The id is of the form "gwt-id-<unique integer>".
    * 
    * @return a unique DOM id
    */
@@ -934,8 +938,8 @@
    *          <code>&lt;option&gt;</code>; cannot be <code>null</code>
    * @param index the index at which to insert the child
    */
-  public static void insertListItem(Element selectElem, String item, String value,
-      int index) {
+  public static void insertListItem(Element selectElem, String item,
+      String value, int index) {
     SelectElement select = selectElem.<SelectElement> cast();
     OptionElement option = Document.get().createOptionElement();
     option.setText(item);
@@ -999,7 +1003,11 @@
    * capture events, though any preview underneath it will begin to do so.
    * 
    * @param preview the event preview to be removed from the stack
+   * @deprecated use {@link com.google.gwt.event.shared.HandlerRegistration}
+   *             returned from
+   *             {@link Event#addNativePreviewHandler(Event.NativePreviewHandler)}
    */
+  @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
@@ -1265,17 +1273,22 @@
    * @param evt a handle to the event being previewed
    * @return <code>false</code> to cancel the event
    */
+  @SuppressWarnings("deprecation")
   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.
-    boolean ret = true;
     if (sEventPreviewStack != null && sEventPreviewStack.size() > 0) {
       EventPreview preview = sEventPreviewStack.get(sEventPreviewStack.size() - 1);
-      if (!(ret = preview.onEventPreview(evt))) {
-        // If the preview cancels the event, stop it from bubbling and
-        // performing its default action.
-        eventCancelBubble(evt, true);
-        eventPreventDefault(evt);
-      }
+      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.
+    if (!ret && evt != null) {
+      eventCancelBubble(evt, true);
+      eventPreventDefault(evt);
     }
 
     return ret;
diff --git a/user/src/com/google/gwt/user/client/Event.java b/user/src/com/google/gwt/user/client/Event.java
index f4dccd6..4ec22fe 100644
--- a/user/src/com/google/gwt/user/client/Event.java
+++ b/user/src/com/google/gwt/user/client/Event.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -17,6 +17,13 @@
 
 import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.dom.client.Element;
+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.HandlerRegistration;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * <p>
@@ -42,6 +49,166 @@
  * </p>
  */
 public class Event extends JavaScriptObject {
+  /**
+   * Represents a preview of a native {@link Event}.
+   */
+  public static class NativePreviewEvent extends GwtEvent<NativePreviewHandler>
+      implements HasNativeEvent {
+
+    /**
+     * Handler type.
+     */
+    private static Type<NativePreviewHandler> TYPE;
+
+    /**
+     * The singleton instance of {@link NativePreviewEvent}.
+     */
+    private static NativePreviewEvent singleton;
+
+    /**
+     * Gets the type associated with this event.
+     * 
+     * @return returns the handler type
+     */
+    public static Type<NativePreviewHandler> getType() {
+      if (TYPE == null) {
+        TYPE = new Type<NativePreviewHandler>();
+      }
+      return TYPE;
+    }
+
+    /**
+     * Fire a {@link NativePreviewEvent} for the native event.
+     * 
+     * @param handlers the list of {@link NativePreviewHandler}
+     * @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) {
+      if (TYPE != null && handlers != null) {
+        // Revive the event
+        if (singleton == null) {
+          singleton = new NativePreviewEvent();
+        } else {
+          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);
+        }
+
+        // Kill the event and return
+        singleton.kill();
+        return !(singleton.isCanceled() && !singleton.isConsumed());
+      }
+      return true;
+    }
+
+    /**
+     * A boolean indicating that the native event should be canceled.
+     */
+    private boolean isCanceled = false;
+
+    /**
+     * A boolean indicating whether or not canceling the native event should be
+     * prevented. This supercedes {@link #isCanceled}.
+     */
+    private boolean isConsumed = false;
+
+    /**
+     * The event being previewed.
+     */
+    private Event nativeEvent;
+
+    /**
+     * Cancel the native event and prevent it from firing. Note that the event
+     * can still fire if another handler calls {@link #consume()}.
+     * 
+     * Classes overriding this method should still call super.cancel().
+     */
+    public void cancel() {
+      isCanceled = true;
+    }
+
+    /**
+     * Consume the native event and prevent it from being canceled, even if it
+     * has already been canceled by another handler.
+     * {@link NativePreviewHandler} that fire first have priority over later
+     * handlers, so all handlers should check if the event has already been
+     * canceled before calling this method.
+     */
+    public void consume() {
+      isConsumed = true;
+    }
+
+    public Event getNativeEvent() {
+      return nativeEvent;
+    }
+
+    /**
+     * Has the event already been canceled? Note that {@link #isConsumed()} will
+     * still return true if the native event has also been consumed.
+     * 
+     * @return true if the event has been canceled
+     * @see #cancel()
+     */
+    public boolean isCanceled() {
+      return isCanceled;
+    }
+
+    /**
+     * Has the native event been consumed? Note that {@link #isCanceled()} will
+     * still return true if the native event has also been canceled.
+     * 
+     * @return true if the event has been consumed
+     * @see #consume()
+     */
+    public boolean isConsumed() {
+      return isConsumed;
+    }
+
+    @Override
+    protected void dispatch(NativePreviewHandler handler) {
+      handler.onPreviewNativeEvent(this);
+    }
+
+    @Override
+    protected Type<NativePreviewHandler> getAssociatedType() {
+      return TYPE;
+    }
+
+    @Override
+    protected void revive() {
+      super.revive();
+      isCanceled = false;
+      isConsumed = false;
+      nativeEvent = null;
+    }
+
+    /**
+     * Set the native event.
+     * 
+     * @param nativeEvent the native {@link Event} being previewed.
+     */
+    private void setNativeEvent(Event nativeEvent) {
+      this.nativeEvent = nativeEvent;
+    }
+  }
+
+  /**
+   * Handler interface for {@link NativePreviewEvent} events.
+   */
+  public static interface NativePreviewHandler extends EventHandler {
+    /**
+     * Called when {@link NativePreviewEvent} is fired.
+     * 
+     * @param event the {@link NativePreviewEvent} that was fired
+     */
+    void onPreviewNativeEvent(NativePreviewEvent event);
+  }
 
   /**
    * The left mouse button (used in {@link DOM#eventGetButton(Event)}).
@@ -184,6 +351,14 @@
   public static final int UNDEFINED = 0;
 
   /**
+   * 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.
+   */
+  private static ArrayList<NativePreviewHandler> handlers;
+
+  /**
    * 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
    * to their listeners. Note that the event preview will receive <u>all </u>
@@ -191,12 +366,54 @@
    * handlers only receive explicitly sunk events.
    * 
    * @param preview the event preview to be added to the stack.
+   * @deprecated replaced by
+   *             {@link #addNativePreviewHandler(NativePreviewHandler)}
    */
+  @Deprecated
   public static void addEventPreview(EventPreview preview) {
     DOM.addEventPreview(preview);
   }
 
   /**
+   * <p>
+   * Adds a {@link NativePreviewHandler} that will receive all events before
+   * they are fired to their handlers. Note that the handler will receive
+   * <u>all</u> native events, including those received due to bubbling, whereas
+   * normal event handlers only receive explicitly sunk events.
+   * </p>
+   * 
+   * <p>
+   * Unlike other event handlers, {@link NativePreviewHandler} are fired in the
+   * reverse order that they are added, such that the last
+   * {@link NativePreviewEvent} that was added is the first to be fired.
+   * </p>
+   * 
+   * @param handler the {@link NativePreviewHandler}
+   * @return {@link HandlerRegistration} used to remove this handler
+   */
+  public static HandlerRegistration addNativePreviewHandler(
+      final NativePreviewHandler handler) {
+    assert handler != null : "Cannot add a null handler";
+    // Initialize the type
+    NativePreviewEvent.getType();
+    if (handlers == null) {
+      handlers = new ArrayList<NativePreviewHandler>();
+    }
+    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;
+          }
+        }
+      }
+    };
+  }
+
+  /**
    * Gets the current event that is being fired. The current event is only
    * available within the lifetime of the onBrowserEvent function. Once the
    * onBrowserEvent method returns, the current event is reset to null.
@@ -234,7 +451,10 @@
    * capture events, though any preview underneath it will begin to do so.
    * 
    * @param preview the event preview to be removed from the stack
+   * @deprecated use {@link HandlerRegistration} returned from
+   *             {@link Event#addNativePreviewHandler(NativePreviewHandler)}
    */
+  @Deprecated
   public static void removeEventPreview(EventPreview preview) {
     DOM.removeEventPreview(preview);
   }
@@ -263,6 +483,16 @@
   }
 
   /**
+   * Fire a {@link NativePreviewEvent} for the native event.
+   * 
+   * @param nativeEvent the native event
+   * @return true to fire the event normally, false to cancel the event
+   */
+  static boolean fireNativePreviewEvent(Event nativeEvent) {
+    return NativePreviewEvent.fire(handlers, nativeEvent);
+  }
+
+  /**
    * Not directly instantiable. Subclasses should also define a protected no-arg
    * constructor to prevent client code from directly instantiating the class.
    */
@@ -355,7 +585,7 @@
    * </p>
    * 
    * @return the Unicode character or key code.
-   * @see com.google.gwt.user.client.ui.KeyboardListener
+   * @see com.google.gwt.event.dom.client.KeyCodes
    */
   public final int getKeyCode() {
     return DOM.eventGetKeyCode(this);
diff --git a/user/src/com/google/gwt/user/client/EventPreview.java b/user/src/com/google/gwt/user/client/EventPreview.java
index 3b2503d..a419256 100644
--- a/user/src/com/google/gwt/user/client/EventPreview.java
+++ b/user/src/com/google/gwt/user/client/EventPreview.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Google Inc.
+ * 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
@@ -19,7 +19,10 @@
  * A listener interface for previewing browser events.
  * 
  * @see com.google.gwt.user.client.DOM#addEventPreview(EventPreview)
+ * @deprecated replaced by
+ *             {@link com.google.gwt.user.client.Event.NativePreviewHandler}
  */
+@Deprecated
 public interface EventPreview {
 
   /**
@@ -29,6 +32,9 @@
    * @param event the browser event
    * @return <code>false</code> to cancel the event
    * @see DOM#addEventPreview(EventPreview)
+   * @deprecated replaced by
+   *             {@link com.google.gwt.user.client.Event.NativePreviewHandler#onPreviewNativeEvent(com.google.gwt.user.client.Event.NativePreviewEvent)}
    */
+  @Deprecated
   boolean onEventPreview(Event event);
 }
diff --git a/user/src/com/google/gwt/user/client/ui/ChangeListener.java b/user/src/com/google/gwt/user/client/ui/ChangeListener.java
index 29e1bc4..cf75a46 100644
--- a/user/src/com/google/gwt/user/client/ui/ChangeListener.java
+++ b/user/src/com/google/gwt/user/client/ui/ChangeListener.java
@@ -19,6 +19,8 @@
 
 /**
  * Event listener interface for 'change' events.
+ * 
+ * @deprecated use {@link com.google.gwt.event.dom.client.ChangeHandler} instead
  */
 @Deprecated
 public interface ChangeListener extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/ChangeListenerCollection.java b/user/src/com/google/gwt/user/client/ui/ChangeListenerCollection.java
index 12ce182..ea4ca5a 100644
--- a/user/src/com/google/gwt/user/client/ui/ChangeListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/ChangeListenerCollection.java
@@ -21,6 +21,9 @@
  * A helper class for implementers of the SourcesChangeEvents interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.ChangeListener}.
+ * 
+ * @deprecated use <code>addDomHandler(myHandler, ChangeEvent.getType())</code>
+ *             instead to manage handlers for your widget
  */
 @Deprecated
 public class ChangeListenerCollection extends ArrayList<ChangeListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/ClickListener.java b/user/src/com/google/gwt/user/client/ui/ClickListener.java
index 4c34bb6..cf998cc 100644
--- a/user/src/com/google/gwt/user/client/ui/ClickListener.java
+++ b/user/src/com/google/gwt/user/client/ui/ClickListener.java
@@ -19,6 +19,7 @@
 
 /**
  * Event listener interface for click events.
+ * @deprecated use {@link com.google.gwt.event.dom.client.ClickHandler} instead
  */
 @Deprecated
 public interface ClickListener extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/ClickListenerCollection.java b/user/src/com/google/gwt/user/client/ui/ClickListenerCollection.java
index 3f150ff..9d13313 100644
--- a/user/src/com/google/gwt/user/client/ui/ClickListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/ClickListenerCollection.java
@@ -21,6 +21,9 @@
  * A helper class for implementers of the SourcesClickEvents interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.ClickListener}.
+ * 
+ * @deprecated use <code>addDomHandler(myHandler, ClickEvent.getType())</code>
+ *             to manage handlers for your widget instead
  */
 @Deprecated
 public class ClickListenerCollection extends ArrayList<ClickListener> {
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 1bb5a3e..c7ed3bd 100644
--- a/user/src/com/google/gwt/user/client/ui/Composite.java
+++ b/user/src/com/google/gwt/user/client/ui/Composite.java
@@ -47,6 +47,9 @@
 
   @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);
   }
diff --git a/user/src/com/google/gwt/user/client/ui/DialogBox.java b/user/src/com/google/gwt/user/client/ui/DialogBox.java
index f4b328e..e1d3e34 100644
--- a/user/src/com/google/gwt/user/client/ui/DialogBox.java
+++ b/user/src/com/google/gwt/user/client/ui/DialogBox.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -34,6 +34,7 @@
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
 
 /**
  * A form of popup that has a caption area at the top and can be dragged by the
@@ -229,18 +230,6 @@
     super.onBrowserEvent(event);
   }
 
-  @Override
-  public boolean onEventPreview(Event event) {
-    // We need to preventDefault() on mouseDown events (outside of the
-    // DialogBox content) to keep text from being selected when it
-    // is dragged.
-    if (DOM.eventGetType(event) == Event.ONMOUSEDOWN && isCaptionEvent(event)) {
-      DOM.eventPreventDefault(event);
-    }
-
-    return super.onEventPreview(event);
-  }
-
   /**
    * @deprecated Use {@link #beginDragging} instead and {@link #getCaption}
    * instead
@@ -401,6 +390,20 @@
     ensureDebugId(getCellElement(1, 1), baseID, "content");
   }
 
+  @Override
+  protected void onPreviewNativeEvent(NativePreviewEvent event) {
+    // We need to preventDefault() on mouseDown events (outside of the
+    // DialogBox content) to keep text from being selected when it
+    // is dragged.
+    Event nativeEvent = event.getNativeEvent();
+    if (!event.isCanceled() && nativeEvent.getTypeInt() == Event.ONMOUSEDOWN
+        && isCaptionEvent(nativeEvent)) {
+      nativeEvent.preventDefault();
+    }
+
+    super.onPreviewNativeEvent(event);
+  }
+
   private boolean isCaptionEvent(Event event) {
     return getCellElement(0, 1).getParentElement().isOrHasChild(
         event.getTarget());
diff --git a/user/src/com/google/gwt/user/client/ui/DisclosureHandler.java b/user/src/com/google/gwt/user/client/ui/DisclosureHandler.java
index 5d09bd0..dd283e5 100644
--- a/user/src/com/google/gwt/user/client/ui/DisclosureHandler.java
+++ b/user/src/com/google/gwt/user/client/ui/DisclosureHandler.java
@@ -14,12 +14,14 @@
  * the License.
  */
 package com.google.gwt.user.client.ui;
-
+ 
 import java.util.EventListener;
 
 /**
  * Event handler interface for {@link DisclosureEvent}.
  * 
+ * @deprecated use {@link com.google.gwt.event.logical.shared.CloseHandler}
+ *             and/or {@link com.google.gwt.event.logical.shared.OpenHandler} instead
  * @see DisclosurePanel
  */
 @Deprecated
@@ -39,4 +41,4 @@
    */
   @Deprecated
   void onOpen(DisclosureEvent event);
-}
\ No newline at end of file
+}
diff --git a/user/src/com/google/gwt/user/client/ui/FocusListener.java b/user/src/com/google/gwt/user/client/ui/FocusListener.java
index e89ceed..23b707d 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusListener.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusListener.java
@@ -19,6 +19,9 @@
 
 /**
  * Event listener for focus events.
+ * 
+ * @deprecated use {@link com.google.gwt.event.dom.client.FocusHandler} and/or
+ *             {@link com.google.gwt.event.dom.client.BlurHandler} instead
  */
 @Deprecated
 public interface FocusListener extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/FocusListenerAdapter.java b/user/src/com/google/gwt/user/client/ui/FocusListenerAdapter.java
index 121269c..c72d948 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusListenerAdapter.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusListenerAdapter.java
@@ -18,6 +18,9 @@
 /**
  * An adapter to simplify focus event listeners that do not need all events
  * defined on the FocusListener interface.
+ * 
+ * @deprecated use {@link com.google.gwt.event.dom.client.FocusHandler} and
+ *             {@link com.google.gwt.event.dom.client.BlurHandler} instead
  */
 @Deprecated
 public abstract class FocusListenerAdapter implements FocusListener {
diff --git a/user/src/com/google/gwt/user/client/ui/FocusListenerCollection.java b/user/src/com/google/gwt/user/client/ui/FocusListenerCollection.java
index cfa0409..b2981aa 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusListenerCollection.java
@@ -24,7 +24,11 @@
  * A helper class for implementers of the
  * {@link com.google.gwt.user.client.ui.SourcesFocusEvents} interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
- * type {@link com.google.gwt.user.client.ui.FocusListener}.
+ * type {@link com.google.gwt.user.client.ui.FocusListener}
+ * 
+ * @deprecated use <code>addDomHandler(myHandler, FocusEvent.getType())</code>
+ *             and <code>addDomHandler(myHandler, BlurEvent.getType())</code>
+ *             to manage your widget's handlers instead
  */
 @Deprecated
 public class FocusListenerCollection extends ArrayList<FocusListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/FormHandler.java b/user/src/com/google/gwt/user/client/ui/FormHandler.java
index 4c5faec..f4f8ab8 100644
--- a/user/src/com/google/gwt/user/client/ui/FormHandler.java
+++ b/user/src/com/google/gwt/user/client/ui/FormHandler.java
@@ -19,6 +19,7 @@
 
 /**
  * Handler interface for form submit events.
+ * @deprecated use {@link FormPanel.SubmitCompleteHandler} and/or {@link FormPanel.SubmitHandler} instead
  */
 @Deprecated
 public interface FormHandler extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/FormHandlerCollection.java b/user/src/com/google/gwt/user/client/ui/FormHandlerCollection.java
index ecb31b8..66c6a4c 100644
--- a/user/src/com/google/gwt/user/client/ui/FormHandlerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/FormHandlerCollection.java
@@ -22,6 +22,8 @@
  * {@link com.google.gwt.user.client.ui.FormHandler FormHandlers}. This
  * subclass of ArrayList assumes that all items added to it will be of type
  * {@link com.google.gwt.user.client.ui.FormHandler}.
+ * 
+ * @deprecated {@link FormPanel} now handles all handler management internally
  */
 @Deprecated
 public class FormHandlerCollection extends ArrayList<FormHandler> {
diff --git a/user/src/com/google/gwt/user/client/ui/Hyperlink.java b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
index c4ceead..7bb6109 100644
--- a/user/src/com/google/gwt/user/client/ui/Hyperlink.java
+++ b/user/src/com/google/gwt/user/client/ui/Hyperlink.java
@@ -138,13 +138,10 @@
 
   @Override
   public void onBrowserEvent(Event event) {
-    if (DOM.eventGetType(event) == Event.ONCLICK) {
-      super.onBrowserEvent(event);
-      
-      if (impl.handleAsClick(event)) {
-        History.newItem(getTargetHistoryToken());
-        DOM.eventPreventDefault(event);
-      }
+    super.onBrowserEvent(event);
+    if (DOM.eventGetType(event) == Event.ONCLICK && impl.handleAsClick(event)) {
+      History.newItem(getTargetHistoryToken());
+      DOM.eventPreventDefault(event);
     }
   }
 
diff --git a/user/src/com/google/gwt/user/client/ui/KeyboardListener.java b/user/src/com/google/gwt/user/client/ui/KeyboardListener.java
index 2680f96..e0a90d1 100644
--- a/user/src/com/google/gwt/user/client/ui/KeyboardListener.java
+++ b/user/src/com/google/gwt/user/client/ui/KeyboardListener.java
@@ -19,6 +19,9 @@
 
 /**
  * Event listener interface for keyboard events.
+ * 
+ * @deprecated use {@link com.google.gwt.event.dom.client.KeyDownHandler}, {@link com.google.gwt.event.dom.client.KeyUpHandler} and/or {@link com.google.gwt.event.dom.client.KeyPressHandler}
+ *             instead
  */
 @Deprecated
 public interface KeyboardListener extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/KeyboardListenerAdapter.java b/user/src/com/google/gwt/user/client/ui/KeyboardListenerAdapter.java
index 1a2d6b1..52cc564 100644
--- a/user/src/com/google/gwt/user/client/ui/KeyboardListenerAdapter.java
+++ b/user/src/com/google/gwt/user/client/ui/KeyboardListenerAdapter.java
@@ -18,6 +18,10 @@
 /**
  * An adapter to simplify keyboard event listeners that do not need all events
  * defined on the KeyboardListener interface.
+ * 
+ * @deprecated use {@link com.google.gwt.event.dom.client.KeyDownHandler},
+ *             {@link com.google.gwt.event.dom.client.KeyUpHandler} and/or
+ *             {@link com.google.gwt.event.dom.client.KeyPressHandler} instead
  */
 @Deprecated
 public class KeyboardListenerAdapter implements KeyboardListener {
diff --git a/user/src/com/google/gwt/user/client/ui/KeyboardListenerCollection.java b/user/src/com/google/gwt/user/client/ui/KeyboardListenerCollection.java
index 74a1945..315913a 100644
--- a/user/src/com/google/gwt/user/client/ui/KeyboardListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/KeyboardListenerCollection.java
@@ -24,6 +24,10 @@
  * A helper class for implementers of the SourcesKeyboardEvents interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.KeyboardListener}.
+ * 
+ * @deprecated use
+ *             <code>addDomHandler(myHandler, Key(Down/Up/Press)Event.getType())</code>
+ *             to manage handlers within your widget
  */
 @Deprecated
 public class KeyboardListenerCollection extends ArrayList<KeyboardListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/LoadListener.java b/user/src/com/google/gwt/user/client/ui/LoadListener.java
index 149259c..fed7374 100644
--- a/user/src/com/google/gwt/user/client/ui/LoadListener.java
+++ b/user/src/com/google/gwt/user/client/ui/LoadListener.java
@@ -19,6 +19,10 @@
 
 /**
  * Event listener interface for 'load' events.
+ * 
+ * @deprecated use {@link com.google.gwt.event.dom.client.LoadHandler}
+ *             and/or {@link com.google.gwt.event.dom.client.ErrorHandler}
+ *             instead
  */
 @Deprecated
 public interface LoadListener extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/LoadListenerCollection.java b/user/src/com/google/gwt/user/client/ui/LoadListenerCollection.java
index ffebb8c..e39b182 100644
--- a/user/src/com/google/gwt/user/client/ui/LoadListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/LoadListenerCollection.java
@@ -21,6 +21,10 @@
  * A helper class for implementers of the SourcesLoadEvents interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.LoadListener}.
+ * 
+ * @deprecated use
+ *             <code>addDomHandler(myHandler, (Load/Error)Event.getType())</code>
+ *             to manage handlers within your widget instead
  */
 @Deprecated
 public class LoadListenerCollection extends ArrayList<LoadListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/MenuBar.java b/user/src/com/google/gwt/user/client/ui/MenuBar.java
index 04dc6b3..a8b00b6 100644
--- a/user/src/com/google/gwt/user/client/ui/MenuBar.java
+++ b/user/src/com/google/gwt/user/client/ui/MenuBar.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -27,6 +27,7 @@
 import com.google.gwt.user.client.DeferredCommand;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
 import com.google.gwt.user.client.ui.PopupPanel.AnimationType;
 
 import java.util.ArrayList;
@@ -395,8 +396,6 @@
 
   @Override
   public void onBrowserEvent(Event event) {
-    super.onBrowserEvent(event);
-
     MenuItem item = findItem(DOM.eventGetTarget(event));
     switch (DOM.eventGetType(event)) {
       case Event.ONCLICK: {
@@ -469,6 +468,7 @@
         break;
       } // end case Event.ONKEYDOWN
     } // end switch (DOM.eventGetType(event))
+    super.onBrowserEvent(event);
   }
 
   /**
@@ -959,29 +959,34 @@
     popup = new DecoratedPopupPanel(true, false, "menuPopup") {
       {
         setWidget(item.getSubMenu());
+        setPreviewingAllNativeEvents(true);
         item.getSubMenu().onShow();
       }
 
       @Override
-      public boolean onEventPreview(Event event) {
+      protected void onPreviewNativeEvent(NativePreviewEvent event) {
         // Hook the popup panel's event preview. We use this to keep it from
         // auto-hiding when the parent menu is clicked.
-        switch (DOM.eventGetType(event)) {
-          case Event.ONMOUSEDOWN:
-            // If the event target is part of the parent menu, suppress the
-            // event altogether.
-            Element target = DOM.eventGetTarget(event);
-            Element parentMenuElement = item.getParentMenu().getElement();
-            if (DOM.isOrHasChild(parentMenuElement, target)) {
-              return false;
-            }
-            boolean cancel = super.onEventPreview(event);
-            if (cancel) {
-              selectItem(null);
-            }
-            return cancel;
+        if (!event.isCanceled()) {
+          Event nativeEvent = event.getNativeEvent();
+          switch (nativeEvent.getTypeInt()) {
+            case Event.ONMOUSEDOWN:
+              // If the event target is part of the parent menu, suppress the
+              // event altogether.
+              com.google.gwt.dom.client.Element target = nativeEvent.getTarget();
+              Element parentMenuElement = item.getParentMenu().getElement();
+              if (parentMenuElement.isOrHasChild(target)) {
+                event.cancel();
+                return;
+              }
+              super.onPreviewNativeEvent(event);
+              if (event.isCanceled()) {
+                selectItem(null);
+              }
+              return;
+          }
         }
-        return super.onEventPreview(event);
+        super.onPreviewNativeEvent(event);
       }
     };
     popup.setAnimationType(AnimationType.ONE_WAY_CORNER);
diff --git a/user/src/com/google/gwt/user/client/ui/MouseListener.java b/user/src/com/google/gwt/user/client/ui/MouseListener.java
index 9c250b2..f80c5c8 100644
--- a/user/src/com/google/gwt/user/client/ui/MouseListener.java
+++ b/user/src/com/google/gwt/user/client/ui/MouseListener.java
@@ -19,6 +19,13 @@
 
 /**
  * Event listener interface for mouse events.
+ * 
+ * @deprecated use
+ *             {@link com.google.gwt.event.dom.client.MouseDownHandler},
+ *             {@link com.google.gwt.event.dom.client.MouseUpHandler},
+ *             {@link com.google.gwt.event.dom.client.MouseOverHandler},
+ *             {@link com.google.gwt.event.dom.client.MouseMoveHandler}, and/or
+ *             {@link com.google.gwt.event.dom.client.MouseOutHandler} instead
  */
 @Deprecated
 public interface MouseListener extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/MouseListenerAdapter.java b/user/src/com/google/gwt/user/client/ui/MouseListenerAdapter.java
index bceee83..10b5018 100644
--- a/user/src/com/google/gwt/user/client/ui/MouseListenerAdapter.java
+++ b/user/src/com/google/gwt/user/client/ui/MouseListenerAdapter.java
@@ -18,6 +18,13 @@
 /**
  * An adapter to simplify mouse event listeners that do not need all events
  * defined on the MouseListener interface.
+ * 
+ * @deprecated use
+ *             {@link com.google.gwt.event.dom.client.MouseDownHandler},
+ *             {@link com.google.gwt.event.dom.client.MouseUpHandler},
+ *             {@link com.google.gwt.event.dom.client.MouseOverHandler},
+ *             {@link com.google.gwt.event.dom.client.MouseMoveHandler}, and/or
+ *             {@link com.google.gwt.event.dom.client.MouseOutHandler} instead
  */
 @Deprecated
 public class MouseListenerAdapter implements MouseListener {
diff --git a/user/src/com/google/gwt/user/client/ui/MouseListenerCollection.java b/user/src/com/google/gwt/user/client/ui/MouseListenerCollection.java
index 9d201b9..08c1336 100644
--- a/user/src/com/google/gwt/user/client/ui/MouseListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/MouseListenerCollection.java
@@ -26,6 +26,10 @@
  * A helper class for implementers of the SourcesMouseEvents interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.MouseListener}.
+ * 
+ * @deprecated use
+ *             <code>addDomHandler(myHandler, Mouse(Down/Up/Move/Over/Out)Event.getType())</code>
+ *             to manage handlers within your widget
  */
 @Deprecated
 public class MouseListenerCollection extends ArrayList<MouseListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/MouseWheelListener.java b/user/src/com/google/gwt/user/client/ui/MouseWheelListener.java
index a74b3cc..b60bd93 100644
--- a/user/src/com/google/gwt/user/client/ui/MouseWheelListener.java
+++ b/user/src/com/google/gwt/user/client/ui/MouseWheelListener.java
@@ -19,6 +19,10 @@
 
 /**
  * Event listener interface for mouse wheel events.
+ * 
+ * @deprecated use
+ *             {@link com.google.gwt.event.dom.client.MouseWheelHandler} instead
+ *             
  */
 @Deprecated
 public interface MouseWheelListener extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/MouseWheelListenerCollection.java b/user/src/com/google/gwt/user/client/ui/MouseWheelListenerCollection.java
index 6bf8be5..16d10a1 100644
--- a/user/src/com/google/gwt/user/client/ui/MouseWheelListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/MouseWheelListenerCollection.java
@@ -24,6 +24,10 @@
  * A helper class for implementers of the SourcesMouseWheelEvents interface.
  * This subclass of {@link ArrayList} assumes that all objects added to it will
  * be of type {@link com.google.gwt.user.client.ui.MouseWheelListener}.
+ * 
+ * @deprecated use
+ *             <code>addDomHandler(myHandler, MouseWheelEvent.getType())</code>
+ *             to manage handlers within your widget
  */
 @Deprecated
 public class MouseWheelListenerCollection extends ArrayList<MouseWheelListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/PopupListener.java b/user/src/com/google/gwt/user/client/ui/PopupListener.java
index bcae3c1..98cef26 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupListener.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupListener.java
@@ -19,6 +19,9 @@
 
 /**
  * Event listener interface for popup events.
+ * 
+ * @deprecated use
+ *             {@link com.google.gwt.event.logical.shared.CloseHandler} instead
  */
 @Deprecated
 public interface PopupListener extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/PopupListenerCollection.java b/user/src/com/google/gwt/user/client/ui/PopupListenerCollection.java
index b17e1b6..0c18403 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupListenerCollection.java
@@ -21,6 +21,8 @@
  * A helper class for implementers of the SourcesPopupEvents interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.PopupListener}.
+ * @deprecated use <code>addHandler(myHandler,  CloseEvent.getType())</code>
+ *             to manage handlers within your widget instead
  */
 @Deprecated
 public class PopupListenerCollection extends ArrayList<PopupListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/PopupPanel.java b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
index 8cfeeba..105b3be 100644
--- a/user/src/com/google/gwt/user/client/ui/PopupPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -18,6 +18,7 @@
 import com.google.gwt.animation.client.Animation;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
 import com.google.gwt.event.logical.shared.CloseEvent;
 import com.google.gwt.event.logical.shared.CloseHandler;
 import com.google.gwt.event.logical.shared.HasCloseHandlers;
@@ -26,10 +27,11 @@
 import com.google.gwt.user.client.Command;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.DeferredCommand;
-import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.EventPreview;
 import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.Event.NativePreviewHandler;
 import com.google.gwt.user.client.ui.impl.PopupImpl;
 
 /**
@@ -55,10 +57,12 @@
  * {@example com.google.gwt.examples.PopupPanelExample}
  * </p>
  * <h3>CSS Style Rules</h3>
- * <ul class='css'>
- * <li>.gwt-PopupPanel { the outside of the popup }</li>
- * <li>.gwt-PopupPanel .popupContent { the wrapper around the content }</li>
- * </ul>
+ * <dl>
+ * <dt>.gwt-PopupPanel</dt>
+ * <dd>the outside of the popup</dd>
+ * <dt>.gwt-PopupPanel .popupContent</dt>
+ * <dd>the wrapper around the content</dd>
+ * </dl>
  */
 @SuppressWarnings("deprecation")
 public class PopupPanel extends SimplePanel implements SourcesPopupEvents,
@@ -265,7 +269,9 @@
    */
   private AnimationType animType = AnimationType.CENTER;
 
-  private boolean autoHide, modal, showing;
+  private HandlerRegistration nativePreviewHandlerRegistration;
+
+  private boolean autoHide, previewAllNativeEvents, modal, showing;
 
   // Used to track requested size across changing child widgets
   private String desiredHeight;
@@ -273,7 +279,7 @@
   private String desiredWidth;
 
   private boolean isAnimationEnabled = false;
-  
+
   private Element autoHidePartner;
 
   /**
@@ -357,7 +363,7 @@
 
     if (!initiallyShowing) {
       setAnimationEnabled(initiallyAnimated);
-      // Run the animation.  The popup is already visible, so we can skip the
+      // Run the animation. The popup is already visible, so we can skip the
       // call to setState.
       if (initiallyAnimated) {
         impl.setClip(getElement(), "rect(0px, 0px, 0px, 0px)");
@@ -433,6 +439,10 @@
       return;
     }
     showing = false;
+    if (nativePreviewHandlerRegistration != null) {
+      nativePreviewHandlerRegistration.removeHandler();
+      nativePreviewHandlerRegistration = null;
+    }
 
     // Hide the popup
     resizeAnimation.setState(false);
@@ -463,74 +473,22 @@
     return modal;
   }
 
-  @SuppressWarnings("deprecation")
+  /**
+   * Returns <code>true</code> if the popup should preview all native events,
+   * even if the event has already been consumed by another popup.
+   * 
+   * @return true if previewAllNativeEvents is enabled, false if disabled
+   */
+  public boolean isPreviewingAllNativeEvents() {
+    return previewAllNativeEvents;
+  }
+
+  /**
+   * @deprecated use {@link #onPreviewNativeEvent(NativePreviewEvent)} instead
+   */
+  @Deprecated
   public boolean onEventPreview(Event event) {
-    Element target = DOM.eventGetTarget(event);
-
-    boolean eventTargetsPopup = (target != null)
-        && DOM.isOrHasChild(getElement(), target);
-
-    int type = DOM.eventGetType(event);
-    switch (type) {
-      case Event.ONKEYDOWN: {
-        boolean allow = onKeyDownPreview((char) DOM.eventGetKeyCode(event),
-            KeyboardListenerCollection.getKeyboardModifiers(event));
-        return allow && (eventTargetsPopup || !modal);
-      }
-      case Event.ONKEYUP: {
-        boolean allow = onKeyUpPreview((char) DOM.eventGetKeyCode(event),
-            KeyboardListenerCollection.getKeyboardModifiers(event));
-        return allow && (eventTargetsPopup || !modal);
-      }
-      case Event.ONKEYPRESS: {
-        boolean allow = onKeyPressPreview((char) DOM.eventGetKeyCode(event),
-            KeyboardListenerCollection.getKeyboardModifiers(event));
-        return allow && (eventTargetsPopup || !modal);
-      }
-
-      case Event.ONMOUSEDOWN:
-        // Don't eat events if event capture is enabled, as this can interfere
-        // with dialog dragging, for example.
-        if (DOM.getCaptureElement() != null) {
-          return true;
-        }
-
-        if (!eventTargetsPopup && shouldAutoHide(event)) {
-          hide(true);
-          return true;
-        }
-        break;
-      case Event.ONMOUSEUP:
-      case Event.ONMOUSEMOVE:
-      case Event.ONCLICK:
-      case Event.ONDBLCLICK: {
-        // Don't eat events if event capture is enabled, as this can interfere
-        // with dialog dragging, for example.
-        if (DOM.getCaptureElement() != null) {
-          return true;
-        }
-
-        // If it's an outside click and auto-hide is enabled:
-        // hide the popup and _don't_ eat the event. ONMOUSEDOWN is used to
-        // prevent problems with showing a popup in response to a mousedown.
-        if (!eventTargetsPopup && shouldAutoHide(event)
-            && (type == Event.ONMOUSEDOWN)) {
-          hide(true);
-          return true;
-        }
-
-        break;
-      }
-
-      case Event.ONFOCUS: {
-        if (modal && !eventTargetsPopup && (target != null)) {
-          blur(target);
-          return false;
-        }
-      }
-    }
-
-    return !modal || eventTargetsPopup;
+    return true;
   }
 
   /**
@@ -541,7 +499,9 @@
    * @param modifiers keyboard modifiers, as specified in
    *          {@link com.google.gwt.event.dom.client.KeyCodes}.
    * @return <code>false</code> to suppress the event
+   * @deprecated use {@link #onPreviewNativeEvent(NativePreviewEvent)} instead
    */
+  @Deprecated
   public boolean onKeyDownPreview(char key, int modifiers) {
     return true;
   }
@@ -554,7 +514,9 @@
    * @param modifiers keyboard modifiers, as specified in
    *          {@link com.google.gwt.event.dom.client.KeyCodes}.
    * @return <code>false</code> to suppress the event
+   * @deprecated use {@link #onPreviewNativeEvent(NativePreviewEvent)} instead
    */
+  @Deprecated
   public boolean onKeyPressPreview(char key, int modifiers) {
     return true;
   }
@@ -567,7 +529,9 @@
    * @param modifiers keyboard modifiers, as specified in
    *          {@link com.google.gwt.event.dom.client.KeyCodes}.
    * @return <code>false</code> to suppress the event
+   * @deprecated use {@link #onPreviewNativeEvent(NativePreviewEvent)} instead
    */
+  @Deprecated
   public boolean onKeyUpPreview(char key, int modifiers) {
     return true;
   }
@@ -592,8 +556,9 @@
   }
 
   /**
-   * If the auto hide partner is non null, its mouse events will 
-   * not hide a panel set to autohide.
+   * If the auto hide partner is non null, its mouse events will not hide a
+   * panel set to autohide.
+   * 
    * @param element new auto hide partner
    */
   public void setAutoHidePartner(Element element) {
@@ -633,7 +598,7 @@
   public void setModal(boolean modal) {
     this.modal = modal;
   }
-  
+
   /**
    * Sets the popup's position relative to the browser's client area. The
    * popup's position may be set before calling {@link #show()}.
@@ -655,8 +620,8 @@
     // called before show() is called (so a popup can be positioned without it
     // 'jumping' on the screen).
     Element elem = getElement();
-    DOM.setStyleAttribute(elem, "left", left + "px");
-    DOM.setStyleAttribute(elem, "top", top + "px");
+    elem.getStyle().setPropertyPx("left", left);
+    elem.getStyle().setPropertyPx("top", top);
   }
 
   /**
@@ -676,13 +641,31 @@
     setVisible(true);
   }
 
+  /**
+   * <p>
+   * When enabled, the popup will preview all native events, even if another
+   * popup was opened after this one.
+   * </p>
+   * <p>
+   * If autoHide is enabled, enabling this feature will cause the popup to
+   * autoHide even if another non-modal popup was shown after it. If this
+   * feature is disabled, the popup will only autoHide if it was the last popup
+   * opened.
+   * </p>
+   * 
+   * @param previewAllNativeEvents true to enable, false to disable
+   */
+  public void setPreviewingAllNativeEvents(boolean previewAllNativeEvents) {
+    this.previewAllNativeEvents = previewAllNativeEvents;
+  }
+
   @Override
   public void setTitle(String title) {
     Element containerElement = getContainerElement();
     if (title == null || title.length() == 0) {
-      DOM.removeElementAttribute(containerElement, "title");
+      containerElement.removeAttribute("title");
     } else {
-      DOM.setElementAttribute(containerElement, "title", title);
+      containerElement.setAttribute("title", title);
     }
   }
 
@@ -744,7 +727,11 @@
       return;
     }
     showing = true;
-    DOM.addEventPreview(this);
+    nativePreviewHandlerRegistration = Event.addNativePreviewHandler(new NativePreviewHandler() {
+      public void onPreviewNativeEvent(NativePreviewEvent event) {
+        previewNativeEvent(event);
+      }
+    });
     resizeAnimation.setState(true);
   }
 
@@ -768,19 +755,24 @@
   }
 
   @Override
-  protected Element getContainerElement() {
-    return impl.getContainerElement(DOM.getFirstChild(super.getContainerElement()));
+  protected com.google.gwt.user.client.Element getContainerElement() {
+    return impl.getContainerElement(getPopupImplElement());
+  }
+
+  @Override
+  protected com.google.gwt.user.client.Element getStyleElement() {
+    return impl.getStyleElement(getPopupImplElement());
   }
 
   /**
-   * This method is called when a widget is detached from the browser's
-   * document. To receive notification before the PopupPanel is removed from the
-   * document, override the {@link Widget#onUnload()} method instead.
+   * @see NativePreviewHandler#onPreviewNativeEvent(NativePreviewEvent)
    */
-  @Override
-  protected void onDetach() {
-    DOM.removeEventPreview(this);
-    super.onDetach();
+  @SuppressWarnings("deprecation")
+  protected void onPreviewNativeEvent(NativePreviewEvent event) {
+    // Cancel the event based on the deprecated onEventPreview() method
+    if (!event.isCanceled() && !onEventPreview(event.getNativeEvent())) {
+      event.cancel();
+    }
   }
 
   /**
@@ -841,9 +833,37 @@
     }
   }-*/;
 
-  private boolean eventInPartner(Event event) {
+  /**
+   * Does the event target the partner element?
+   * 
+   * @param event the native event
+   * @return true if the event targets the partner
+   */
+  private boolean eventTargetsPartner(Event event) {
     return autoHidePartner != null
-      && autoHidePartner.isOrHasChild(event.getTarget());
+        && autoHidePartner.isOrHasChild(event.getTarget());
+  }
+
+  /**
+   * Does the event target this popup?
+   * 
+   * @param event the native event
+   * @return true if the event targets the popup
+   */
+  private boolean eventTargetsPopup(Event event) {
+    return getElement().isOrHasChild(event.getTarget());
+  }
+
+  /**
+   * Get the element that {@link PopupImpl} uses.  PopupImpl creates an element
+   * that goes inside of the outer element, so all methods in PopupImpl are
+   * relative to the first child of the outer element, not the outer element
+   * itself.
+   * 
+   * @return the Element that {@link PopupImpl} creates and expects
+   */
+  private com.google.gwt.user.client.Element getPopupImplElement() {
+    return DOM.getFirstChild(super.getContainerElement());
   }
 
   /**
@@ -974,10 +994,103 @@
     }
     setPopupPosition(left, top);
   }
-  
-  private boolean shouldAutoHide(Event event) {
-    boolean shouldAutoHide = autoHide && !eventInPartner(event);
-    return shouldAutoHide;
-  }
 
+  /**
+   * Preview the {@link NativePreviewEvent}.
+   * 
+   * @param event the {@link NativePreviewEvent}
+   */
+  private void previewNativeEvent(NativePreviewEvent event) {
+    // If the event has been canceled or consumed, ignore it
+    if (event.isCanceled() || (!previewAllNativeEvents && event.isConsumed())) {
+      // We need to ensure that we cancel the event even if its been consumed so
+      // that popups lower on the stack do not auto hide
+      if (modal) {
+        event.cancel();
+      }
+      return;
+    }
+
+    // Fire the event hook and return if the event is canceled
+    onPreviewNativeEvent(event);
+    if (event.isCanceled()) {
+      return;
+    }
+
+    // If the event targets the popup or the partner, consume it
+    Event nativeEvent = event.getNativeEvent();
+    boolean eventTargetsPopupOrPartner = eventTargetsPopup(nativeEvent)
+        || eventTargetsPartner(nativeEvent);
+    if (eventTargetsPopupOrPartner) {
+      event.consume();
+    }
+
+    // Cancel the event if it doesn't target the modal popup. Note that the
+    // event can be both canceled and consumed.
+    if (modal) {
+      event.cancel();
+    }
+
+    // Switch on the event type
+    int type = nativeEvent.getTypeInt();
+    switch (type) {
+      case Event.ONKEYDOWN: {
+        if (!onKeyDownPreview((char) nativeEvent.getKeyCode(),
+            KeyboardListenerCollection.getKeyboardModifiers(nativeEvent))) {
+          event.cancel();
+        }
+        return;
+      }
+      case Event.ONKEYUP: {
+        if (!onKeyUpPreview((char) nativeEvent.getKeyCode(),
+            KeyboardListenerCollection.getKeyboardModifiers(nativeEvent))) {
+          event.cancel();
+        }
+        return;
+      }
+      case Event.ONKEYPRESS: {
+        if (!onKeyPressPreview((char) nativeEvent.getKeyCode(),
+            KeyboardListenerCollection.getKeyboardModifiers(nativeEvent))) {
+          event.cancel();
+        }
+        return;
+      }
+
+      case Event.ONMOUSEDOWN:
+        // Don't eat events if event capture is enabled, as this can
+        // interfere with dialog dragging, for example.
+        if (DOM.getCaptureElement() != null) {
+          event.consume();
+          return;
+        }
+
+        if (!eventTargetsPopupOrPartner && autoHide) {
+          hide(true);
+          return;
+        }
+        break;
+      case Event.ONMOUSEUP:
+      case Event.ONMOUSEMOVE:
+      case Event.ONCLICK:
+      case Event.ONDBLCLICK: {
+        // Don't eat events if event capture is enabled, as this can
+        // interfere with dialog dragging, for example.
+        if (DOM.getCaptureElement() != null) {
+          event.consume();
+          return;
+        }
+        break;
+      }
+
+      case Event.ONFOCUS: {
+        Element target = nativeEvent.getTarget();
+        if (modal && !eventTargetsPopupOrPartner && (target != null)) {
+          blur(target);
+          event.cancel();
+          return;
+        }
+        break;
+      }
+    }
+  }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/ScrollListener.java b/user/src/com/google/gwt/user/client/ui/ScrollListener.java
index d7e6130..6b50121 100644
--- a/user/src/com/google/gwt/user/client/ui/ScrollListener.java
+++ b/user/src/com/google/gwt/user/client/ui/ScrollListener.java
@@ -19,6 +19,9 @@
 
 /**
  * Event listener interface for scroll events.
+ * 
+ * @deprecated use {@link com.google.gwt.event.dom.client.ScrollHandler}
+ *             instead
  */
 @Deprecated
 public interface ScrollListener extends EventListener {
diff --git a/user/src/com/google/gwt/user/client/ui/ScrollListenerCollection.java b/user/src/com/google/gwt/user/client/ui/ScrollListenerCollection.java
index 5576063..15a0b03 100644
--- a/user/src/com/google/gwt/user/client/ui/ScrollListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/ScrollListenerCollection.java
@@ -21,6 +21,9 @@
  * A helper class for implementers of the SourcesScrollEvents interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.ScrollListener}.
+ * 
+ * @deprecated use <code>addDomHandler(myHandler, ScrollEvent.getType())</code>
+ *             to manage handlers within your widget instead
  */
 @Deprecated
 public class ScrollListenerCollection extends ArrayList<ScrollListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/SourcesChangeEvents.java b/user/src/com/google/gwt/user/client/ui/SourcesChangeEvents.java
index 27f6c16..268f3ad 100644
--- a/user/src/com/google/gwt/user/client/ui/SourcesChangeEvents.java
+++ b/user/src/com/google/gwt/user/client/ui/SourcesChangeEvents.java
@@ -19,7 +19,7 @@
  * A widget that implements this interface sources the events defined by the
  * {@link com.google.gwt.user.client.ui.ChangeListener} interface.
  * 
- * @deprecated Use {@link com.google.gwt.event.dom.client.HasChangeHandlers}
+ * @deprecated use {@link com.google.gwt.event.dom.client.HasChangeHandlers}
  *             instead
  */
 @Deprecated
diff --git a/user/src/com/google/gwt/user/client/ui/SourcesMouseEvents.java b/user/src/com/google/gwt/user/client/ui/SourcesMouseEvents.java
index ce3c60a..96a6cad 100644
--- a/user/src/com/google/gwt/user/client/ui/SourcesMouseEvents.java
+++ b/user/src/com/google/gwt/user/client/ui/SourcesMouseEvents.java
@@ -19,7 +19,7 @@
  * A widget that implements this interface sources the events defined by the
  * {@link com.google.gwt.user.client.ui.MouseListener} interface.
  * 
- * @deprecated use {@link com.google.gwt.event.dom.client.HasAllMouseHandlerss}
+ * @deprecated use {@link com.google.gwt.event.dom.client.HasAllMouseHandlers}
  *             instead
  */
 @Deprecated
diff --git a/user/src/com/google/gwt/user/client/ui/SourcesMouseWheelEvents.java b/user/src/com/google/gwt/user/client/ui/SourcesMouseWheelEvents.java
index c003da6..f342544 100644
--- a/user/src/com/google/gwt/user/client/ui/SourcesMouseWheelEvents.java
+++ b/user/src/com/google/gwt/user/client/ui/SourcesMouseWheelEvents.java
@@ -19,9 +19,10 @@
  * A widget that implements this interface sources the events defined by the
  * {@link com.google.gwt.user.client.ui.MouseWheelListener} interface.
  * 
- * @deprecated use {@link com.google.gwt.event.dom.client.HasMouseDownHandlers}
+ * @deprecated use {@link com.google.gwt.event.dom.client.HasMouseWheelHandlers}
  *             instead
  */
+@Deprecated
 public interface SourcesMouseWheelEvents {
 
   /**
diff --git a/user/src/com/google/gwt/user/client/ui/SourcesTreeEvents.java b/user/src/com/google/gwt/user/client/ui/SourcesTreeEvents.java
index 4f7e8fe..e47c443 100644
--- a/user/src/com/google/gwt/user/client/ui/SourcesTreeEvents.java
+++ b/user/src/com/google/gwt/user/client/ui/SourcesTreeEvents.java
@@ -22,7 +22,7 @@
  * @deprecated use
  *             {@link com.google.gwt.event.logical.shared.HasBeforeSelectionHandlers}
  *             , {@link com.google.gwt.event.logical.shared.HasOpenHandlers},
- *             {@link com.google.gwt.event.logical.shared.HasClickHandlers}
+ *             {@link com.google.gwt.event.dom.client.HasClickHandlers}
  *             instead
  */
 @Deprecated
diff --git a/user/src/com/google/gwt/user/client/ui/SplitPanel.java b/user/src/com/google/gwt/user/client/ui/SplitPanel.java
index ff58976..aaf5692 100644
--- a/user/src/com/google/gwt/user/client/ui/SplitPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/SplitPanel.java
@@ -316,6 +316,7 @@
         break;
       }
     }
+    super.onBrowserEvent(event);
   }
 
   @Override
diff --git a/user/src/com/google/gwt/user/client/ui/StackPanel.java b/user/src/com/google/gwt/user/client/ui/StackPanel.java
index ae17c23..8432a01 100644
--- a/user/src/com/google/gwt/user/client/ui/StackPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/StackPanel.java
@@ -171,6 +171,7 @@
         showStack(index);
       }
     }
+    super.onBrowserEvent(event);
   }
 
   @Override
diff --git a/user/src/com/google/gwt/user/client/ui/SuggestBox.java b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
index 8fd59b2..eacf785 100644
--- a/user/src/com/google/gwt/user/client/ui/SuggestBox.java
+++ b/user/src/com/google/gwt/user/client/ui/SuggestBox.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -240,6 +240,7 @@
       super(true, false, "suggestPopup");
       setWidget(suggestionMenu);
       setStyleName(STYLENAME_DEFAULT);
+      setPreviewingAllNativeEvents(true);
     }
 
     /**
@@ -475,6 +476,7 @@
    * 
    * @deprecated use addSelectionHandler instead.
    */
+  @Deprecated
   public void addEventHandler(final SuggestionHandler handler) {
     ListenerWrapper.Suggestion.add(this, handler);
   }
diff --git a/user/src/com/google/gwt/user/client/ui/TabListenerCollection.java b/user/src/com/google/gwt/user/client/ui/TabListenerCollection.java
index 2cf6fce..4693454 100644
--- a/user/src/com/google/gwt/user/client/ui/TabListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/TabListenerCollection.java
@@ -22,6 +22,9 @@
  * {@link com.google.gwt.user.client.ui.SourcesTabEvents} interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.TabListener}.
+ * 
+ * @deprecated {@link TabPanel} and {@link TabBar} should now completely manage
+ *             their own handlers
  */
 @Deprecated
 public class TabListenerCollection extends ArrayList<TabListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/TableListenerCollection.java b/user/src/com/google/gwt/user/client/ui/TableListenerCollection.java
index 638f7d2..d013eed 100644
--- a/user/src/com/google/gwt/user/client/ui/TableListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/TableListenerCollection.java
@@ -22,6 +22,10 @@
  * {@link com.google.gwt.user.client.ui.SourcesTableEvents} interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.TableListener}.
+ * 
+ * @deprecated use
+ *             {@link HTMLTable#getCellForEvent(com.google.gwt.event.dom.client.ClickEvent)}
+ *             or similar code
  */
 @Deprecated
 public class TableListenerCollection extends ArrayList<TableListener> {
diff --git a/user/src/com/google/gwt/user/client/ui/TreeListenerCollection.java b/user/src/com/google/gwt/user/client/ui/TreeListenerCollection.java
index 92a2320..92bd35d 100644
--- a/user/src/com/google/gwt/user/client/ui/TreeListenerCollection.java
+++ b/user/src/com/google/gwt/user/client/ui/TreeListenerCollection.java
@@ -21,6 +21,8 @@
  * A helper class for implementers of the SourcesClickEvents interface. This
  * subclass of {@link ArrayList} assumes that all objects added to it will be of
  * type {@link com.google.gwt.user.client.ui.ClickListener}.
+ * 
+ * @deprecated {@link Tree} should now completely manage its own handlers
  */
 @Deprecated
 public class TreeListenerCollection extends ArrayList<TreeListener> {
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 7d0725e..7f23170 100644
--- a/user/src/com/google/gwt/user/client/ui/Widget.java
+++ b/user/src/com/google/gwt/user/client/ui/Widget.java
@@ -183,19 +183,23 @@
   }
 
   /**
-   * If a widget implements HasWidgets, it must override this method and call
-   * {@link #onAttach()} for each of its child widgets.
+   * If a widget contains one or more child widgets that are not in the logical
+   * widget hierarchy (the child is physically connected only on the DOM level),
+   * it must override this method and call {@link #onAttach()} for each of its
+   * child widgets.
    * 
-   * @see Panel#onAttach()
+   * @see #onAttach()
    */
   protected void doAttachChildren() {
   }
 
   /**
-   * If a widget implements HasWidgets, it must override this method and call
-   * onDetach() for each of its child widgets.
+   * If a widget contains one or more child widgets that are not in the logical
+   * widget hierarchy (the child is physically connected only on the DOM level),
+   * it must override this method and call {@link #onDetach()} for each of its
+   * child widgets.
    * 
-   * @see Panel#onDetach()
+   * @see #onDetach()
    */
   protected void doDetachChildren() {
   }
diff --git a/user/src/com/google/gwt/user/client/ui/impl/PopupImpl.java b/user/src/com/google/gwt/user/client/ui/impl/PopupImpl.java
index 9af98c1..d8897cc 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/PopupImpl.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/PopupImpl.java
@@ -31,6 +31,10 @@
     return popup;
   }
 
+  public Element getStyleElement(Element popup) {
+    return DOM.getParent(popup);
+  }
+
   public void onHide(Element popup) {
   }
 
diff --git a/user/src/com/google/gwt/user/client/ui/impl/PopupImplMozilla.java b/user/src/com/google/gwt/user/client/ui/impl/PopupImplMozilla.java
index a11fe48..eaa6c94 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/PopupImplMozilla.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/PopupImplMozilla.java
@@ -99,6 +99,11 @@
   }
 
   @Override
+  public Element getStyleElement(Element outerElem) {
+    return isMac ? outerElem : super.getStyleElement(outerElem);
+  }
+
+  @Override
   public void setClip(Element popup, String rect) {
     super.setClip(popup, rect);
     DOM.setStyleAttribute(popup, "display", "none");
diff --git a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css
index f9ed0a6..f71a4a9 100644
--- a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css
+++ b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome.css
@@ -1073,7 +1073,7 @@
 }
 
 .gwt-Tree .gwt-TreeItem {
-  padding: 1px;
+  padding: 1px 0px;
   margin: 0px;
   white-space: nowrap;
   cursor: hand;
diff --git a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css
index 693c41f..6d8a276 100644
--- a/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css
+++ b/user/src/com/google/gwt/user/theme/chrome/public/gwt/chrome/chrome_rtl.css
@@ -1073,7 +1073,7 @@
 }
 
 .gwt-Tree .gwt-TreeItem {
-  padding: 1px;
+  padding: 1px 0px;
   margin: 0px;
   white-space: nowrap;
   cursor: hand;
diff --git a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
index 1e341c2..6b274f3 100644
--- a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
+++ b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
@@ -977,7 +977,7 @@
 }
 
 .gwt-Tree .gwt-TreeItem {
-  padding: 1px;
+  padding: 1px 0px;
   margin: 0px;
   white-space: nowrap;
   cursor: hand;
diff --git a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
index f73cbff..4c7e922 100644
--- a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
+++ b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
@@ -977,7 +977,7 @@
 }
 
 .gwt-Tree .gwt-TreeItem {
-  padding: 1px;
+  padding: 1px 0px;
   margin: 0px;
   white-space: nowrap;
   cursor: hand;
diff --git a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css
index 7b4b8ae..2b0341d 100644
--- a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css
+++ b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard.css
@@ -1072,7 +1072,7 @@
 }
 
 .gwt-Tree .gwt-TreeItem {
-  padding: 1px;
+  padding: 1px 0px;
   margin: 0px;
   white-space: nowrap;
   cursor: hand;
diff --git a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css
index e3e65af..22db0da 100644
--- a/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css
+++ b/user/src/com/google/gwt/user/theme/standard/public/gwt/standard/standard_rtl.css
@@ -1072,7 +1072,7 @@
 }
 
 .gwt-Tree .gwt-TreeItem {
-  padding: 1px;
+  padding: 1px 0px;
   margin: 0px;
   white-space: nowrap;
   cursor: hand;
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index 864e0d6..515955b 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -19,6 +19,7 @@
 import com.google.gwt.user.client.AsyncProxyTest;
 import com.google.gwt.user.client.CommandExecutorTest;
 import com.google.gwt.user.client.CookieTest;
+import com.google.gwt.user.client.EventTest;
 import com.google.gwt.user.client.WindowTest;
 import com.google.gwt.user.client.ui.AbsolutePanelTest;
 import com.google.gwt.user.client.ui.AnchorTest;
@@ -114,6 +115,7 @@
     suite.addTestSuite(DockPanelTest.class);
     suite.addTestSuite(DOMTest.class);
     suite.addTestSuite(ElementWrappingTest.class);
+    suite.addTestSuite(EventTest.class);
     suite.addTestSuite(FastStringMapTest.class);
     suite.addTestSuite(FlexTableTest.class);
     suite.addTestSuite(FlowPanelTest.class);
diff --git a/user/test/com/google/gwt/user/client/EventTest.java b/user/test/com/google/gwt/user/client/EventTest.java
new file mode 100644
index 0000000..a894e85
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/EventTest.java
@@ -0,0 +1,410 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.user.client;
+
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.Event.NativePreviewHandler;
+
+/**
+ * Test Case for {@link Event}.
+ */
+public class EventTest extends GWTTestCase {
+  /**
+   * An EventPreview used for testing.
+   */
+  @SuppressWarnings("deprecation")
+  private static class TestEventPreview implements EventPreview {
+    private boolean doCancel;
+    private boolean isFired = false;
+
+    /**
+     * Construct a new {@link TestEventPreview}.
+     * 
+     * @param doCancel if true, cancel the event
+     */
+    public TestEventPreview(boolean doCancel) {
+      this.doCancel = doCancel;
+    }
+
+    @Deprecated
+    public boolean onEventPreview(Event event) {
+      assertFalse(isFired);
+      isFired = true;
+      return !doCancel;
+    }
+
+    public void assertIsFired(boolean expected) {
+      assertEquals(expected, isFired);
+    }
+  }
+
+  /**
+   * A NativePreviewHandler used for testing.
+   */
+  private static class TestNativePreviewHandler implements NativePreviewHandler {
+    private boolean doCancel;
+    private boolean doPreventCancel;
+    private boolean isFired = false;
+
+    /**
+     * Construct a new {@link TestNativePreviewHandler}.
+     * 
+     * @param doCancel if true, cancel the event
+     * @param doPreventCancel if true, prevent the event from being canceled
+     */
+    public TestNativePreviewHandler(boolean doCancel, boolean doPreventCancel) {
+      this.doCancel = doCancel;
+      this.doPreventCancel = doPreventCancel;
+    }
+
+    public void onPreviewNativeEvent(NativePreviewEvent event) {
+      assertFalse(isFired);
+      isFired = true;
+      if (doCancel) {
+        event.cancel();
+      }
+      if (doPreventCancel) {
+        event.consume();
+      }
+    }
+
+    public void assertIsFired(boolean expected) {
+      assertEquals(expected, isFired);
+    }
+  }
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+
+  /**
+   * Test that {@link Event#fireNativePreviewEvent(Event)} returns the correct
+   * value if the native event is canceled.
+   */
+  public void testFireNativePreviewEventCancel() {
+    TestNativePreviewHandler handler0 = new TestNativePreviewHandler(true,
+        false);
+    TestNativePreviewHandler handler1 = new TestNativePreviewHandler(true,
+        false);
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+    assertFalse(Event.fireNativePreviewEvent(null));
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(true);
+    reg0.removeHandler();
+    reg1.removeHandler();
+  }
+
+  /**
+   * Test that {@link Event#fireNativePreviewEvent(Event)} returns the correct
+   * value if the native event is prevented from being canceled, even if another
+   * handler cancels the event.
+   */
+  public void testFireNativePreviewEventPreventCancel() {
+    TestNativePreviewHandler handler0 = new TestNativePreviewHandler(false,
+        true);
+    TestNativePreviewHandler handler1 = new TestNativePreviewHandler(true,
+        false);
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+    assertTrue(Event.fireNativePreviewEvent(null));
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(true);
+    reg0.removeHandler();
+    reg1.removeHandler();
+  }
+
+  /**
+   * Test that {@link Event#fireNativePreviewEvent(Event)} fires handlers in
+   * reverse order. Also verify that the legacy EventPreview fires last.
+   */
+  @SuppressWarnings("deprecation")
+  public void testFireNativePreviewEventReverseOrder() {
+    final TestEventPreview preview = new TestEventPreview(false);
+    final TestNativePreviewHandler handler0 = new TestNativePreviewHandler(
+        false, false) {
+      @Override
+      public void onPreviewNativeEvent(NativePreviewEvent event) {
+        super.onPreviewNativeEvent(event);
+        preview.assertIsFired(false);
+      }
+    };
+    final TestNativePreviewHandler handler1 = new TestNativePreviewHandler(
+        false, false) {
+      @Override
+      public void onPreviewNativeEvent(NativePreviewEvent event) {
+        super.onPreviewNativeEvent(event);
+        handler0.assertIsFired(false);
+        preview.assertIsFired(false);
+      }
+    };
+    final TestNativePreviewHandler handler2 = new TestNativePreviewHandler(
+        false, false) {
+      @Override
+      public void onPreviewNativeEvent(NativePreviewEvent event) {
+        super.onPreviewNativeEvent(event);
+        handler0.assertIsFired(false);
+        handler1.assertIsFired(false);
+        preview.assertIsFired(false);
+      }
+    };
+    final TestNativePreviewHandler handler3 = new TestNativePreviewHandler(
+        false, false) {
+      @Override
+      public void onPreviewNativeEvent(NativePreviewEvent event) {
+        super.onPreviewNativeEvent(event);
+        handler0.assertIsFired(false);
+        handler1.assertIsFired(false);
+        handler2.assertIsFired(false);
+        preview.assertIsFired(false);
+      }
+    };
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+    HandlerRegistration reg2 = Event.addNativePreviewHandler(handler2);
+    HandlerRegistration reg3 = Event.addNativePreviewHandler(handler3);
+    DOM.addEventPreview(preview);
+    assertTrue(DOM.previewEvent(null));
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(true);
+    handler2.assertIsFired(true);
+    handler3.assertIsFired(true);
+    preview.assertIsFired(true);
+    reg0.removeHandler();
+    reg1.removeHandler();
+    reg2.removeHandler();
+    reg3.removeHandler();
+    DOM.removeEventPreview(preview);
+  }
+
+  /**
+   * Test removal of a {@link NativePreviewHandler} works.
+   */
+  public void testFireNativePreviewEventRemoval() {
+    TestNativePreviewHandler handler0 = new TestNativePreviewHandler(false,
+        false);
+    TestNativePreviewHandler handler1 = new TestNativePreviewHandler(false,
+        false);
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+    reg1.removeHandler();
+    assertTrue(Event.fireNativePreviewEvent(null));
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(false);
+    reg0.removeHandler();
+  }
+
+  /**
+   * Test that {@link Event#fireNativePreviewEvent(Event)} returns the correct
+   * value if the native event is not canceled.
+   */
+  public void testFireNativePreviewEventWithoutCancel() {
+    TestNativePreviewHandler handler0 = new TestNativePreviewHandler(false,
+        false);
+    TestNativePreviewHandler handler1 = new TestNativePreviewHandler(false,
+        false);
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+    assertTrue(Event.fireNativePreviewEvent(null));
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(true);
+    reg0.removeHandler();
+    reg1.removeHandler();
+  }
+
+  /**
+   * Test that {@link Event#fireNativePreviewEvent(Event)} returns the correct
+   * value if no handlers are present.
+   */
+  public void testFireNativePreviewEventWithoutHandlers() {
+    assertTrue(Event.fireNativePreviewEvent(null));
+  }
+
+  /**
+   * Test that legacy EventPreview and NativePreviewHandlers can both cancel the
+   * event.
+   */
+  @Deprecated
+  public void testLegacyEventPreviewCancelByBoth() {
+    // Add handlers
+    TestNativePreviewHandler handler0 = new TestNativePreviewHandler(false,
+        false);
+    TestNativePreviewHandler handler1 = new TestNativePreviewHandler(true,
+        false);
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+
+    // Add legacy EventPreview
+    TestEventPreview preview = new TestEventPreview(true);
+    DOM.addEventPreview(preview);
+
+    // Fire the event
+    assertFalse(DOM.previewEvent(null));
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(true);
+    preview.assertIsFired(true);
+    reg0.removeHandler();
+    reg1.removeHandler();
+    DOM.removeEventPreview(preview);
+  }
+
+  /**
+   * Test that legacy EventPreview can cancel the event.
+   */
+  @Deprecated
+  public void testLegacyEventPreviewCancelByEventPreview() {
+    // Add handlers
+    TestNativePreviewHandler handler0 = new TestNativePreviewHandler(false,
+        false);
+    TestNativePreviewHandler handler1 = new TestNativePreviewHandler(false,
+        false);
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+
+    // Add legacy EventPreview
+    TestEventPreview preview = new TestEventPreview(true);
+    DOM.addEventPreview(preview);
+
+    // Fire the event
+    assertFalse(DOM.previewEvent(null));
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(true);
+    preview.assertIsFired(true);
+    reg0.removeHandler();
+    reg1.removeHandler();
+    DOM.removeEventPreview(preview);
+  }
+
+  /**
+   * Test that legacy EventPreview still fires after the NativeHandler cancels
+   * the event.
+   */
+  @Deprecated
+  public void testLegacyEventPreviewCancelByHandler() {
+    // Add handlers
+    TestNativePreviewHandler handler0 = new TestNativePreviewHandler(false,
+        false);
+    TestNativePreviewHandler handler1 = new TestNativePreviewHandler(true,
+        false);
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+
+    // Add legacy EventPreview
+    TestEventPreview preview = new TestEventPreview(false);
+    DOM.addEventPreview(preview);
+
+    // Fire the event
+    assertFalse(DOM.previewEvent(null));
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(true);
+    preview.assertIsFired(true);
+    reg0.removeHandler();
+    reg1.removeHandler();
+    DOM.removeEventPreview(preview);
+  }
+
+  /**
+   * Test that legacy EventPreview still fires after the NativeHandlers without
+   * canceling the event.
+   */
+  @Deprecated
+  public void testLegacyEventPreviewWithoutCancel() {
+    // Add handlers
+    TestNativePreviewHandler handler0 = new TestNativePreviewHandler(false,
+        false);
+    TestNativePreviewHandler handler1 = new TestNativePreviewHandler(false,
+        false);
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+
+    // Add legacy EventPreview
+    TestEventPreview preview = new TestEventPreview(false);
+    DOM.addEventPreview(preview);
+
+    // Fire the event
+    assertTrue(DOM.previewEvent(null));
+    handler0.assertIsFired(true);
+    handler1.assertIsFired(true);
+    preview.assertIsFired(true);
+    reg0.removeHandler();
+    reg1.removeHandler();
+    DOM.removeEventPreview(preview);
+  }
+
+  /**
+   * Test the accessors in {@link NativePreviewEvent}.
+   */
+  public void testNativePreviewEventAccessors() {
+    // cancelNativeEvent
+    {
+      NativePreviewEvent event = new NativePreviewEvent();
+      assertFalse(event.isCanceled());
+      event.cancel();
+      assertTrue(event.isCanceled());
+    }
+
+    // preventCancelNativeEvent
+    {
+      NativePreviewEvent event = new NativePreviewEvent();
+      assertFalse(event.isConsumed());
+      event.consume();
+      assertTrue(event.isConsumed());
+    }
+
+    // revive
+    {
+      NativePreviewEvent event = new NativePreviewEvent();
+      event.cancel();
+      event.consume();
+      assertTrue(event.isCanceled());
+      assertTrue(event.isConsumed());
+      event.revive();
+      assertFalse(event.isCanceled());
+      assertFalse(event.isConsumed());
+    }
+  }
+
+  /**
+   * Test that the singleton instance of {@link NativePreviewEvent} is revived
+   * correctly.
+   */
+  public void testReviveNativePreviewEvent() {
+    // Fire the event and cancel it
+    TestNativePreviewHandler handler0 = new TestNativePreviewHandler(true, true);
+    HandlerRegistration reg0 = Event.addNativePreviewHandler(handler0);
+    Event.fireNativePreviewEvent(null);
+    handler0.assertIsFired(true);
+    reg0.removeHandler();
+
+    // Fire the event again, but don't cancel it
+    TestNativePreviewHandler handler1 = new TestNativePreviewHandler(false,
+        false) {
+      @Override
+      public void onPreviewNativeEvent(NativePreviewEvent event) {
+        assertFalse(event.isCanceled());
+        assertFalse(event.isConsumed());
+        super.onPreviewNativeEvent(event);
+      }
+    };
+    HandlerRegistration reg1 = Event.addNativePreviewHandler(handler1);
+    assertTrue(Event.fireNativePreviewEvent(null));
+    handler1.assertIsFired(true);
+    reg1.removeHandler();
+  }
+}
diff --git a/user/test/com/google/gwt/user/client/ui/PopupTest.java b/user/test/com/google/gwt/user/client/ui/PopupTest.java
index f42b84c..8aa91e3 100644
--- a/user/test/com/google/gwt/user/client/ui/PopupTest.java
+++ b/user/test/com/google/gwt/user/client/ui/PopupTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008 Google Inc.
+ * 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
@@ -74,6 +74,12 @@
     assertTrue(popup.isAutoHideEnabled());
     popup.setAutoHideEnabled(false);
     assertFalse(popup.isAutoHideEnabled());
+
+    // PreviewAllNativeEvents enabled
+    popup.setPreviewingAllNativeEvents(true);
+    assertTrue(popup.isPreviewingAllNativeEvents());
+    popup.setPreviewingAllNativeEvents(false);
+    assertFalse(popup.isPreviewingAllNativeEvents());
   }
 
   /**