Cherrypick merges of 1.6 c4298 and c4299.
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4314 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3186.java b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3186.java
new file mode 100644
index 0000000..a8360ca
--- /dev/null
+++ b/reference/code-museum/src/com/google/gwt/museum/client/defaultmuseum/Issue3186.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.gwt.museum.client.defaultmuseum;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.museum.client.common.AbstractIssue;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.AbsolutePanel;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.FocusPanel;
+import com.google.gwt.user.client.ui.MouseListener;
+import com.google.gwt.user.client.ui.MouseListenerCollection;
+import com.google.gwt.user.client.ui.Widget;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Ensure the ListenerWrapper for mouse still works like the old listeners did.
+ */
+@SuppressWarnings("deprecation")
+public class Issue3186 extends AbstractIssue {
+
+ enum VisibleEvents {
+ mouseDown, mouseEnter, mouseLeave, mouseMove, mouseUp
+ }
+
+ private final class TestWidget extends FocusPanel {
+ private class Control implements MouseListener {
+ int controlX;
+ int controlY;
+ int controlMouseEnter;
+ int controlMouseLeave;
+
+ public void onMouseDown(Widget sender, int x, int y) {
+ this.controlX = x;
+ this.controlY = y;
+ }
+
+ public void onMouseEnter(Widget sender) {
+ ++controlMouseEnter;
+ }
+
+ public void onMouseLeave(Widget sender) {
+ ++controlMouseLeave;
+ }
+
+ public void onMouseMove(Widget sender, int x, int y) {
+ this.controlX = x;
+ this.controlY = y;
+ }
+
+ public void onMouseUp(Widget sender, int x, int y) {
+ this.controlX = x;
+ this.controlY = y;
+ }
+ }
+
+ private class Current implements MouseListener {
+ private int mouseEnterCount;
+ private int mouseLeaveCount;
+
+ public void onMouseDown(Widget sender, int x, int y) {
+ check(x, y, VisibleEvents.mouseDown);
+ }
+
+ public void onMouseEnter(Widget sender) {
+ ++mouseEnterCount;
+ if (mouseEnterCount != control.controlMouseEnter) {
+ fail("recieved:" + mouseEnterCount + " events, expected:"
+ + control.controlMouseEnter, VisibleEvents.mouseEnter);
+ } else {
+ pass(VisibleEvents.mouseEnter);
+ }
+ sender.getElement().getStyle().setProperty("background", "yellow");
+ }
+
+ public void onMouseLeave(Widget sender) {
+ ++mouseLeaveCount;
+ if (mouseLeaveCount != control.controlMouseLeave) {
+ fail("recieved:" + mouseLeaveCount + " events, expected:"
+ + control.controlMouseLeave, VisibleEvents.mouseLeave);
+ } else {
+ pass(VisibleEvents.mouseLeave);
+ }
+
+ sender.getElement().getStyle().setProperty("background", "");
+ }
+
+ public void onMouseMove(Widget sender, int x, int y) {
+ check(x, y, VisibleEvents.mouseMove);
+ }
+
+ public void onMouseUp(Widget sender, int x, int y) {
+ check(x, y, VisibleEvents.mouseUp);
+ }
+
+ private void check(int x, int y, VisibleEvents event) {
+ String errorReport = getErrorReport(x, y);
+ if (errorReport == null) {
+ eventToElement.get(event).setInnerHTML(
+ "<span style='color:green'>pass</span>");
+ } else {
+ fail(errorReport, event);
+ }
+ }
+
+ private String getErrorReport(int x, int y) {
+ String errorReport = null;
+ if (x != control.controlX) {
+ errorReport = "wanted x: " + control.controlX + " actual x" + x;
+ } else if (y != control.controlY) {
+ errorReport += "wanted y: " + control.controlY + " actual y" + y;
+ }
+ return errorReport;
+ }
+ }
+
+ private FlexTable layout = null;
+ private MouseListenerCollection collection = new MouseListenerCollection();
+
+ private Control control = new Control();
+ private Current current = new Current();
+ private final Map<VisibleEvents, Element> eventToElement = new HashMap<VisibleEvents, Element>();
+
+ public TestWidget() {
+ layout = new FlexTable();
+ layout.setCellPadding(3);
+ layout.setBorderWidth(2);
+
+ layout.setHTML(0, 0, "<b>MouseEvents</b>");
+ layout.setHTML(0, 1, "<b>Status</b>");
+
+ for (VisibleEvents e : VisibleEvents.values()) {
+ eventToElement.put(e, addResultRow(e.name()));
+ }
+ add(layout);
+ this.addMouseListener(current);
+ collection.add(control);
+ }
+
+ public void fail(String errorReport, VisibleEvents event) {
+ eventToElement.get(event).setInnerHTML(
+ "<span style='color:red'>" + errorReport + "</span>");
+ }
+
+ @Override
+ public void onBrowserEvent(Event event) {
+ collection.fireMouseEvent(this, event);
+ super.onBrowserEvent(event);
+ }
+
+ public void pass(VisibleEvents event) {
+ eventToElement.get(event).setInnerHTML(
+ "<span style='color:green'>pass</span>");
+ }
+
+ private Element addResultRow(String eventName) {
+ int row = layout.getRowCount();
+ layout.setHTML(row, 0, eventName);
+ layout.setHTML(row, 1, "<span style='color:red'>?</span>");
+ Element cell = layout.getCellFormatter().getElement(row, 1);
+ return cell;
+ }
+ }
+
+ @Override
+ public Widget createIssue() {
+ AbsolutePanel p = new AbsolutePanel();
+ p.setHeight("500px");
+ p.setWidth("500px");
+ final TestWidget dialog = showTestWidget();
+ p.add(dialog, 100, 100);
+ return p;
+ }
+
+ @Override
+ public String getInstructions() {
+ return "move your mouse around ";
+ }
+
+ @Override
+ public String getSummary() {
+ return "mouse listeners work the same";
+ }
+
+ @Override
+ public boolean hasCSS() {
+ return false;
+ }
+
+ private TestWidget showTestWidget() {
+ final TestWidget dialog = new TestWidget();
+ return dialog;
+ }
+
+}
diff --git a/user/src/com/google/gwt/user/client/ListenerWrapper.java b/user/src/com/google/gwt/user/client/ListenerWrapper.java
index 45bf6ac..bcd0115 100644
--- a/user/src/com/google/gwt/user/client/ListenerWrapper.java
+++ b/user/src/com/google/gwt/user/client/ListenerWrapper.java
@@ -131,24 +131,29 @@
}
}
+
// This is an internal helper method with the current formulation, we have
// lost the info needed to make it safe by this point.
@SuppressWarnings("unchecked")
- protected static void baseRemove(HandlerManager manager,
+ // This is a direct copy of the baseRemove from
+ // com.google.gwt.user.client.ui.ListenerWrapper. Change in parallel.
+ static <H extends EventHandler> void baseRemove(HandlerManager manager,
EventListener listener, Type... keys) {
if (manager != null) {
- for (Type key : keys) {
+ for (Type<H> key : keys) {
int handlerCount = manager.getHandlerCount(key);
- for (int i = 0; i < handlerCount; i++) {
- EventHandler handler = manager.getHandler(key, i);
- if (handler instanceof ListenerWrapper && ((ListenerWrapper) handler).listener.equals(listener)) {
+ // We are removing things as we traverse, have to go backward
+ for (int i = handlerCount - 1; i >= 0; i--) {
+ H handler = manager.getHandler(key, i);
+ if (handler instanceof ListenerWrapper
+ && ((ListenerWrapper) handler).listener.equals(listener)) {
manager.removeHandler(key, handler);
}
}
}
}
}
-
+
/**
* Listener being wrapped.
*/
diff --git a/user/src/com/google/gwt/user/client/Window.java b/user/src/com/google/gwt/user/client/Window.java
index 50b2fc4..dae2416 100644
--- a/user/src/com/google/gwt/user/client/Window.java
+++ b/user/src/com/google/gwt/user/client/Window.java
@@ -392,12 +392,13 @@
}
}
+ // Package protected for testing.
+ static WindowHandlers handlers;
private static boolean closeHandlersInitialized;
private static boolean scrollHandlersInitialized;
private static boolean resizeHandlersInitialized;
private static final WindowImpl impl = GWT.create(WindowImpl.class);
- private static WindowHandlers handlers;
/**
* Adds a {@link CloseEvent} handler.
diff --git a/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java b/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
index b01d35f..bdf3024 100644
--- a/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
+++ b/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
@@ -271,25 +271,44 @@
}
public void onMouseDown(MouseDownEvent event) {
- listener.onMouseDown(source(event), event.getClientX(),
- event.getClientY());
+ Widget source = source(event);
+ Element elem = source.getElement();
+ listener.onMouseDown(source, event.getRelativeX(elem),
+ event.getRelativeY(elem));
}
public void onMouseMove(MouseMoveEvent event) {
- listener.onMouseMove(source(event), event.getClientX(),
- event.getClientY());
+ Widget source = source(event);
+ Element elem = source.getElement();
+ listener.onMouseMove(source, event.getRelativeX(elem),
+ event.getRelativeY(elem));
}
public void onMouseOut(MouseOutEvent event) {
- listener.onMouseLeave(source(event));
+ // Only fire the mouseLeave event if it's actually leaving this
+ // widget.
+ Element to = event.getToElement();
+ Widget source = source(event);
+ if (to == null || !source.getElement().isOrHasChild(to)) {
+ listener.onMouseLeave(source(event));
+ }
}
public void onMouseOver(MouseOverEvent event) {
- listener.onMouseEnter(source(event));
+ // Only fire the mouseEnter event if it's coming from outside this
+ // widget.
+ Element from = event.getFromElement();
+ Widget source = source(event);
+ if (from == null || !source.getElement().isOrHasChild(from)) {
+ listener.onMouseEnter(source(event));
+ }
}
public void onMouseUp(MouseUpEvent event) {
- listener.onMouseUp(source(event), event.getClientX(), event.getClientY());
+ Widget source = source(event);
+ Element elem = source.getElement();
+ listener.onMouseUp(source, event.getRelativeX(elem),
+ event.getRelativeY(elem));
}
}
public static class MouseWheel extends ListenerWrapper<MouseWheelListener> implements
@@ -510,6 +529,8 @@
EventListener listener, Type... keys) {
HandlerManager manager = eventSource.getHandlers();
if (manager != null) {
+ // This is a direct copy of the baseRemove from
+ // com.google.gwt.user.client.ListenerWrapper. Change in parallel.
for (Type<H> key : keys) {
int handlerCount = manager.getHandlerCount(key);
// We are removing things as we traverse, have to go backward
diff --git a/user/test/com/google/gwt/user/client/WindowTest.java b/user/test/com/google/gwt/user/client/WindowTest.java
index 04e2302..b0e0ea6 100644
--- a/user/test/com/google/gwt/user/client/WindowTest.java
+++ b/user/test/com/google/gwt/user/client/WindowTest.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.user.client;
+import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
@@ -176,4 +177,40 @@
// Cleanup the window
RootPanel.get().remove(largeDOM);
}
+
+ @SuppressWarnings("deprecation")
+ static class ListenerTester implements WindowResizeListener {
+ static int resize = 0;
+
+ public void onWindowResized(int width, int height) {
+ ++resize;
+ }
+
+ public static void fire() {
+ resize = 0;
+ ResizeEvent.fire(Window.handlers, 0, 0);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testListenerRemoval() {
+
+ WindowResizeListener r1 = new ListenerTester();
+ WindowResizeListener r2 = new ListenerTester();
+
+ Window.addWindowResizeListener(r1);
+ Window.addWindowResizeListener(r2);
+
+ ListenerTester.fire();
+ assertEquals(ListenerTester.resize, 2);
+
+ Window.removeWindowResizeListener(r1);
+ ListenerTester.fire();
+ assertEquals(ListenerTester.resize, 1);
+
+ Window.removeWindowResizeListener(r2);
+ ListenerTester.fire();
+ assertEquals(ListenerTester.resize, 0);
+ }
+
}
diff --git a/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java b/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
index 5bb0f60..c7ba8e2 100644
--- a/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
+++ b/user/test/com/google/gwt/user/client/ui/CheckBoxTest.java
@@ -15,8 +15,10 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
@@ -29,7 +31,7 @@
@Override
public String getModuleName() {
return "com.google.gwt.user.DebugTest";
- }
+ }
@Override
protected void gwtSetUp() throws Exception {
@@ -85,7 +87,7 @@
UIObjectTest.assertDebugId("myCheck-input", newInput);
UIObjectTest.assertDebugIdContents("myCheck-label", "myLabel");
}
-
+
public void testValueChangeEvent() {
CheckBox cb = new CheckBox();
Handler h = new Handler();
@@ -94,7 +96,7 @@
assertNull(h.received);
cb.setChecked(true);
assertNull(h.received);
-
+
cb.setValue(false);
assertNull(h.received);
cb.setValue(true);
@@ -102,17 +104,61 @@
cb.setValue(true, true);
assertNull(h.received);
-
+
cb.setValue(false, true);
assertFalse(h.received);
cb.setValue(true, true);
assertTrue(h.received);
+
+ try {
+ cb.setValue(null);
+ fail("Should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ /* pass */
+ }
}
-
+
+ static class ListenerTester implements ClickListener {
+ static int fired = 0;
+ static HandlerManager manager;
+
+ public static void fire() {
+ fired = 0;
+ manager.fireEvent(new ClickEvent() {
+ });
+ }
+
+ public void onClick(Widget sender) {
+ ++fired;
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void testListenerRemoval() {
+ CheckBox b = new CheckBox();
+
+ ClickListener r1 = new ListenerTester();
+ ClickListener r2 = new ListenerTester();
+ ListenerTester.manager = b.ensureHandlers();
+ b.addClickListener(r1);
+ b.addClickListener(r2);
+
+ ListenerTester.fire();
+ assertEquals(ListenerTester.fired, 2);
+
+ b.removeClickListener(r1);
+ ListenerTester.fire();
+ assertEquals(ListenerTester.fired, 1);
+
+ b.removeClickListener(r2);
+ ListenerTester.fire();
+ assertEquals(ListenerTester.fired, 0);
+ }
+
private static class Handler implements ValueChangeHandler<Boolean> {
Boolean received = null;
-
+
public void onValueChange(ValueChangeEvent<Boolean> event) {
received = event.getValue();
}