Added a NativePreviewEvent to replce the current EventPreview system. Now, multiple widgets can preview the same event, instead of just the one at the top of the stack. This fixes a couple of subtle bugs and adds some use cases, such as listening for user timeout.
Patch by: jlabanca
Review by: ecc
Issue: 1275
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4385 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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/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><option></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/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/MenuBar.java b/user/src/com/google/gwt/user/client/ui/MenuBar.java
index 2cc23cf..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;
@@ -958,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/PopupPanel.java b/user/src/com/google/gwt/user/client/ui/PopupPanel.java
index 6064c12..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,24 +755,24 @@
}
@Override
- protected Element getContainerElement() {
+ protected com.google.gwt.user.client.Element getContainerElement() {
return impl.getContainerElement(getPopupImplElement());
}
@Override
- protected Element getStyleElement() {
+ 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();
+ }
}
/**
@@ -846,9 +833,25 @@
}
}-*/;
- 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());
}
/**
@@ -859,7 +862,7 @@
*
* @return the Element that {@link PopupImpl} creates and expects
*/
- private Element getPopupImplElement() {
+ private com.google.gwt.user.client.Element getPopupImplElement() {
return DOM.getFirstChild(super.getContainerElement());
}
@@ -991,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/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/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index 56d1d5b..b9c3d79 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
@@ -18,6 +18,7 @@
import com.google.gwt.junit.tools.GWTTestSuite;
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;
@@ -112,6 +113,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());
}
/**