From e9b730ddc0a44529a26520b8e0206ca2586a24d4 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 21 Jun 2010 08:23:39 +0000 Subject: [PATCH] Merged and slightly modified fix for #4652 - MouseEventDetails and ClickEvent should provide coordinates relative to component svn changeset:13800/svn branch:6.4 --- src/com/vaadin/event/MouseEvents.java | 22 ++ .../gwt/client/MouseEventDetails.java | 35 ++- .../gwt/client/ui/ClickEventHandler.java | 227 ++++++++++-------- .../client/ui/LayoutClickEventHandler.java | 3 +- .../terminal/gwt/client/ui/VSplitPanel.java | 6 + src/com/vaadin/ui/Table.java | 37 +-- ...eddedClickListenerRelativeCoordinates.html | 47 ++++ ...eddedClickListenerRelativeCoordinates.java | 37 +++ ...PanelClickListenerRelativeCoordinates.html | 47 ++++ ...PanelClickListenerRelativeCoordinates.java | 36 +++ .../layouts/TestLayoutClickListeners.java | 4 +- 11 files changed, 362 insertions(+), 139 deletions(-) create mode 100644 tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html create mode 100644 tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java create mode 100644 tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.html create mode 100644 tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.java diff --git a/src/com/vaadin/event/MouseEvents.java b/src/com/vaadin/event/MouseEvents.java index a7daf70714..547a56a9ea 100644 --- a/src/com/vaadin/event/MouseEvents.java +++ b/src/com/vaadin/event/MouseEvents.java @@ -79,6 +79,28 @@ public interface MouseEvents { return details.getClientY(); } + /** + * Returns the relative mouse position (x coordinate) when the click + * took place. The position is relative to the clicked component. + * + * @return The mouse cursor x position relative to the clicked layout + * component or -1 if no x coordinate available + */ + public int getRelativeX() { + return details.getRelativeX(); + } + + /** + * Returns the relative mouse position (y coordinate) when the click + * took place. The position is relative to the clicked component. + * + * @return The mouse cursor y position relative to the clicked layout + * component or -1 if no y coordinate available + */ + public int getRelativeY() { + return details.getRelativeY(); + } + /** * Checks if the event is a double click event. * diff --git a/src/com/vaadin/terminal/gwt/client/MouseEventDetails.java b/src/com/vaadin/terminal/gwt/client/MouseEventDetails.java index 9905d9ff1d..85a6270f71 100644 --- a/src/com/vaadin/terminal/gwt/client/MouseEventDetails.java +++ b/src/com/vaadin/terminal/gwt/client/MouseEventDetails.java @@ -3,6 +3,7 @@ */ package com.vaadin.terminal.gwt.client; +import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.user.client.Event; @@ -24,6 +25,8 @@ public class MouseEventDetails { private boolean metaKey; private boolean shiftKey; private int type; + private int relativeX = -1; + private int relativeY = -1; public int getButton() { return button; @@ -53,7 +56,19 @@ public class MouseEventDetails { return shiftKey; } + public int getRelativeX() { + return relativeX; + } + + public int getRelativeY() { + return relativeY; + } + public MouseEventDetails(NativeEvent evt) { + this(evt, null); + } + + public MouseEventDetails(NativeEvent evt, Element relativeToElement) { button = evt.getButton(); clientX = evt.getClientX(); clientY = evt.getClientY(); @@ -62,6 +77,10 @@ public class MouseEventDetails { metaKey = evt.getMetaKey(); shiftKey = evt.getShiftKey(); type = Event.getTypeInt(evt.getType()); + if (relativeToElement != null) { + relativeX = getRelativeX(evt, relativeToElement); + relativeY = getRelativeY(evt, relativeToElement); + } } private MouseEventDetails() { @@ -75,7 +94,7 @@ public class MouseEventDetails { public String serialize() { return "" + button + DELIM + clientX + DELIM + clientY + DELIM + altKey + DELIM + ctrlKey + DELIM + metaKey + DELIM + shiftKey + DELIM - + type; + + type + DELIM + relativeX + DELIM + relativeY; } public static MouseEventDetails deSerialize(String serializedString) { @@ -90,6 +109,8 @@ public class MouseEventDetails { instance.metaKey = Boolean.valueOf(fields[5]).booleanValue(); instance.shiftKey = Boolean.valueOf(fields[6]).booleanValue(); instance.type = Integer.parseInt(fields[7]); + instance.relativeX = Integer.parseInt(fields[8]); + instance.relativeY = Integer.parseInt(fields[9]); return instance; } @@ -113,4 +134,16 @@ public class MouseEventDetails { return type == Event.ONDBLCLICK; } + private static int getRelativeX(NativeEvent evt, Element target) { + return evt.getClientX() - target.getAbsoluteLeft() + + target.getScrollLeft() + + target.getOwnerDocument().getScrollLeft(); + } + + private static int getRelativeY(NativeEvent evt, Element target) { + return evt.getClientY() - target.getAbsoluteTop() + + target.getScrollTop() + + target.getOwnerDocument().getScrollTop(); + } + } diff --git a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java index a80cbb431b..1c6c11ec95 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java +++ b/src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java @@ -1,117 +1,136 @@ /* @ITMillApache2LicenseForJavaFiles@ */ -package com.vaadin.terminal.gwt.client.ui; - -import java.util.HashMap; -import java.util.Map; - -import com.google.gwt.dom.client.NativeEvent; -import com.google.gwt.event.dom.client.ContextMenuEvent; -import com.google.gwt.event.dom.client.ContextMenuHandler; -import com.google.gwt.event.dom.client.DomEvent; -import com.google.gwt.event.dom.client.DoubleClickEvent; -import com.google.gwt.event.dom.client.DoubleClickHandler; -import com.google.gwt.event.dom.client.MouseUpEvent; -import com.google.gwt.event.dom.client.MouseUpHandler; -import com.google.gwt.event.shared.EventHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.MouseEventDetails; -import com.vaadin.terminal.gwt.client.Paintable; - -public abstract class ClickEventHandler implements DoubleClickHandler, - ContextMenuHandler, MouseUpHandler { - - private HandlerRegistration doubleClickHandlerRegistration; - private HandlerRegistration mouseUpHandlerRegistration; - private HandlerRegistration contextMenuHandlerRegistration; - - protected String clickEventIdentifier; - protected Paintable paintable; - private ApplicationConnection client; - - public ClickEventHandler(Paintable paintable, String clickEventIdentifier) { - this.paintable = paintable; - this.clickEventIdentifier = clickEventIdentifier; - } - - public void handleEventHandlerRegistration(ApplicationConnection client) { - this.client = client; +package com.vaadin.terminal.gwt.client.ui; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.event.dom.client.ContextMenuEvent; +import com.google.gwt.event.dom.client.ContextMenuHandler; +import com.google.gwt.event.dom.client.DomEvent; +import com.google.gwt.event.dom.client.DoubleClickEvent; +import com.google.gwt.event.dom.client.DoubleClickHandler; +import com.google.gwt.event.dom.client.MouseUpEvent; +import com.google.gwt.event.dom.client.MouseUpHandler; +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.MouseEventDetails; +import com.vaadin.terminal.gwt.client.Paintable; + +public abstract class ClickEventHandler implements DoubleClickHandler, + ContextMenuHandler, MouseUpHandler { + + private HandlerRegistration doubleClickHandlerRegistration; + private HandlerRegistration mouseUpHandlerRegistration; + private HandlerRegistration contextMenuHandlerRegistration; + + protected String clickEventIdentifier; + protected Paintable paintable; + private ApplicationConnection client; + + public ClickEventHandler(Paintable paintable, String clickEventIdentifier) { + this.paintable = paintable; + this.clickEventIdentifier = clickEventIdentifier; + } + + public void handleEventHandlerRegistration(ApplicationConnection client) { + this.client = client; // Handle registering/unregistering of click handler depending on if // server side listeners have been added or removed. - if (hasEventListener()) { - if (mouseUpHandlerRegistration == null) { - mouseUpHandlerRegistration = registerHandler(this, MouseUpEvent - .getType()); - contextMenuHandlerRegistration = registerHandler(this, - ContextMenuEvent.getType()); - doubleClickHandlerRegistration = registerHandler(this, - DoubleClickEvent.getType()); - } - } else { - if (mouseUpHandlerRegistration != null) { + if (hasEventListener()) { + if (mouseUpHandlerRegistration == null) { + mouseUpHandlerRegistration = registerHandler(this, MouseUpEvent + .getType()); + contextMenuHandlerRegistration = registerHandler(this, + ContextMenuEvent.getType()); + doubleClickHandlerRegistration = registerHandler(this, + DoubleClickEvent.getType()); + } + } else { + if (mouseUpHandlerRegistration != null) { // Remove existing handlers - doubleClickHandlerRegistration.removeHandler(); - mouseUpHandlerRegistration.removeHandler(); - contextMenuHandlerRegistration.removeHandler(); - - contextMenuHandlerRegistration = null; - mouseUpHandlerRegistration = null; - doubleClickHandlerRegistration = null; - - } - } - - } - - protected abstract HandlerRegistration registerHandler( - final H handler, DomEvent.Type type); - - protected ApplicationConnection getApplicationConnection() { - return client; - } - - public boolean hasEventListener() { - return getApplicationConnection().hasEventListeners(paintable, - clickEventIdentifier); - } - - protected void fireClick(NativeEvent event) { - ApplicationConnection client = getApplicationConnection(); - String pid = getApplicationConnection().getPid(paintable); - - MouseEventDetails mouseDetails = new MouseEventDetails(event); - - Map parameters = new HashMap(); - parameters.put("mouseDetails", mouseDetails.serialize()); - client.updateVariable(pid, clickEventIdentifier, parameters, true); - - } - - public void onContextMenu(ContextMenuEvent event) { - if (hasEventListener()) { + doubleClickHandlerRegistration.removeHandler(); + mouseUpHandlerRegistration.removeHandler(); + contextMenuHandlerRegistration.removeHandler(); + + contextMenuHandlerRegistration = null; + mouseUpHandlerRegistration = null; + doubleClickHandlerRegistration = null; + + } + } + + } + + protected abstract HandlerRegistration registerHandler( + final H handler, DomEvent.Type type); + + protected ApplicationConnection getApplicationConnection() { + return client; + } + + public boolean hasEventListener() { + return getApplicationConnection().hasEventListeners(paintable, + clickEventIdentifier); + } + + protected void fireClick(NativeEvent event) { + ApplicationConnection client = getApplicationConnection(); + String pid = getApplicationConnection().getPid(paintable); + + MouseEventDetails mouseDetails = new MouseEventDetails(event, + getRelativeToElement()); + + Map parameters = new HashMap(); + parameters.put("mouseDetails", mouseDetails.serialize()); + client.updateVariable(pid, clickEventIdentifier, parameters, true); + + } + + public void onContextMenu(ContextMenuEvent event) { + if (hasEventListener()) { // Prevent showing the browser's context menu when there is a right // click listener. - event.preventDefault(); - } - - } - - public void onMouseUp(MouseUpEvent event) { + event.preventDefault(); + } + + } + + public void onMouseUp(MouseUpEvent event) { // TODO For perfect accuracy we should check that a mousedown has // occured on this element before this mouseup and that no mouseup // has occured anywhere after that. - if (hasEventListener()) { + if (hasEventListener()) { // "Click" with left, right or middle button - fireClick(event.getNativeEvent()); - } - } - - public void onDoubleClick(DoubleClickEvent event) { - if (hasEventListener()) { - fireClick(event.getNativeEvent()); - } - } - + fireClick(event.getNativeEvent()); + } + } + + public void onDoubleClick(DoubleClickEvent event) { + if (hasEventListener()) { + fireClick(event.getNativeEvent()); + } + } + + /** + * Click event calculates and returns coordinates relative to the element + * returned by this method. Default implementation uses the root element of + * the widget. Override to provide a different relative element. + * + * @return The Element used for calculating relative coordinates for a click + * or null if no relative coordinates can be calculated. + */ + protected Element getRelativeToElement() { + if (paintable instanceof Widget) { + return ((Widget) paintable).getElement(); + } + + return null; + } + } \ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java index 423b301013..ca6938f8c6 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java +++ b/src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java @@ -26,7 +26,8 @@ public abstract class LayoutClickEventHandler extends ClickEventHandler { ApplicationConnection client = getApplicationConnection(); String pid = getApplicationConnection().getPid(paintable); - MouseEventDetails mouseDetails = new MouseEventDetails(event); + MouseEventDetails mouseDetails = new MouseEventDetails(event, + getRelativeToElement()); Paintable childComponent = getChildComponent((Element) event .getEventTarget().cast()); diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java index 6dc8c65509..977f3855ca 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java @@ -65,6 +65,12 @@ public class VSplitPanel extends ComplexPanel implements Container, super.fireClick(event); } } + + @Override + protected Element getRelativeToElement() { + return null; + } + }; public static final int ORIENTATION_HORIZONTAL = 0; diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java index c164673f48..9cd81ec6b2 100644 --- a/src/com/vaadin/ui/Table.java +++ b/src/com/vaadin/ui/Table.java @@ -29,6 +29,7 @@ import com.vaadin.event.ItemClickEvent; import com.vaadin.event.Action.Handler; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.event.ItemClickEvent.ItemClickSource; +import com.vaadin.event.MouseEvents.ClickEvent; import com.vaadin.event.dd.DragAndDropEvent; import com.vaadin.event.dd.DragSource; import com.vaadin.event.dd.DropHandler; @@ -3759,7 +3760,7 @@ public class Table extends AbstractSelect implements Action.Container, * the column which header was pressed and details about the mouse event * itself. */ - public static class HeaderClickEvent extends Component.Event { + public static class HeaderClickEvent extends ClickEvent { public static final Method HEADER_CLICK_METHOD; static { @@ -3777,13 +3778,9 @@ public class Table extends AbstractSelect implements Action.Container, // The property id of the column which header was pressed private Object columnPropertyId; - // The mouse details - private MouseEventDetails details; - public HeaderClickEvent(Component source, Object propertyId, MouseEventDetails details) { - super(source); - this.details = details; + super(source, details); columnPropertyId = propertyId; } @@ -3795,16 +3792,6 @@ public class Table extends AbstractSelect implements Action.Container, public Object getPropertyId() { return columnPropertyId; } - - /** - * Returns the details of the mouse event like the mouse coordinates, - * button pressed etc. - * - * @return The mouse details - */ - public MouseEventDetails getEventDetails() { - return details; - } } /** @@ -3813,7 +3800,7 @@ public class Table extends AbstractSelect implements Action.Container, * the column which header was pressed and details about the mouse event * itself. */ - public static class FooterClickEvent extends Component.Event { + public static class FooterClickEvent extends ClickEvent { public static final Method FOOTER_CLICK_METHOD; static { @@ -3831,9 +3818,6 @@ public class Table extends AbstractSelect implements Action.Container, // The property id of the column which header was pressed private Object columnPropertyId; - // The mouse details - private MouseEventDetails details; - /** * Constructor * @@ -3846,9 +3830,8 @@ public class Table extends AbstractSelect implements Action.Container, */ public FooterClickEvent(Component source, Object propertyId, MouseEventDetails details) { - super(source); + super(source, details); columnPropertyId = propertyId; - this.details = details; } /** @@ -3859,16 +3842,6 @@ public class Table extends AbstractSelect implements Action.Container, public Object getPropertyId() { return columnPropertyId; } - - /** - * Returns the details of the mouse event like the mouse coordinates, - * button pressed etc. - * - * @return The mouse details - */ - public MouseEventDetails getEventDetails() { - return details; - } } /** diff --git a/tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html b/tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html new file mode 100644 index 0000000000..4def1f5d14 --- /dev/null +++ b/tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html @@ -0,0 +1,47 @@ + + + + + + +EmbeddedClickListenerRelativeCoordinates + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
EmbeddedClickListenerRelativeCoordinates
open/run/EmbeddedClickListenerRelativeCoordinates
waitForVaadin
waitForVaadin
mouseClickvaadin=vaadinrunEmbeddedClickListenerRelativeCoordinates::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VEmbedded[0]/domChild[0]41,22
waitForVaadin
screenCapture
+ + diff --git a/tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java b/tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java new file mode 100644 index 0000000000..96b1d36901 --- /dev/null +++ b/tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java @@ -0,0 +1,37 @@ +package com.vaadin.tests.components.embedded; + +import com.vaadin.event.MouseEvents.ClickEvent; +import com.vaadin.event.MouseEvents.ClickListener; +import com.vaadin.terminal.ThemeResource; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Embedded; + +public class EmbeddedClickListenerRelativeCoordinates extends TestBase { + + @Override + protected void setup() { + Embedded e = new Embedded("Embedded caption", new ThemeResource( + "../runo/icons/64/ok.png")); + e.addListener(new ClickListener() { + + public void click(ClickEvent event) { + getMainWindow() + .showNotification( + "" + event.getRelativeX() + ", " + + event.getRelativeY()); + } + }); + addComponent(e); + } + + @Override + protected String getDescription() { + return "Click the image to get coordinates relative to the top-left corder of the embedded image."; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.html b/tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.html new file mode 100644 index 0000000000..1088c4eeb9 --- /dev/null +++ b/tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.html @@ -0,0 +1,47 @@ + + + + + + +PanelClickListenerRelativeCoordinates + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PanelClickListenerRelativeCoordinates
open/vaadin/run/PanelClickListenerRelativeCoordinates
waitForVaadin
waitForVaadin
mouseClickvaadin=vaadinrunPanelClickListenerRelativeCoordinates::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VPanel[0]/VVerticalLayout[0]287,25
waitForVaadin
screenCapture
+ + diff --git a/tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.java b/tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.java new file mode 100644 index 0000000000..65a185b160 --- /dev/null +++ b/tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.java @@ -0,0 +1,36 @@ +package com.vaadin.tests.components.panel; + +import com.vaadin.event.MouseEvents.ClickEvent; +import com.vaadin.event.MouseEvents.ClickListener; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Panel; + +public class PanelClickListenerRelativeCoordinates extends TestBase { + + @Override + protected void setup() { + Panel panel = new Panel("Panel's caption"); + panel.addListener(new ClickListener() { + + public void click(ClickEvent event) { + getMainWindow() + .showNotification( + "" + event.getRelativeX() + ", " + + event.getRelativeY()); + } + }); + addComponent(panel); + + } + + @Override + protected String getDescription() { + return "Click the panel to get coordinates relative to the top-left corder of the panel."; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.java b/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.java index 386608f01f..68f001baea 100644 --- a/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.java +++ b/tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.java @@ -150,7 +150,9 @@ public class TestLayoutClickListeners extends AbstractTestCase { if (event.isDoubleClick()) { type = "double-click"; } - log.log(layout + ": " + button + " " + type + " on " + target); + log.log(layout + ": " + button + " " + type + " on " + target + + ", coordinates relative to the layout (" + + event.getRelativeX() + ", " + event.getRelativeY() + ")"); } -- 2.39.5