Fixing issue 3186 by modifying ListenerWrapper to provide correct values for x and y and adding a visual test case for this problem.
Review by:jlabanca

git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4299 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/ui/ListenerWrapper.java b/user/src/com/google/gwt/user/client/ui/ListenerWrapper.java
index 1ea7741..ad0dbb7 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