diff options
11 files changed, 362 insertions, 139 deletions
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 @@ -80,6 +80,28 @@ public interface MouseEvents { } /** + * 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. * * @return true if the event is a double click event, false otherwise 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 <H extends EventHandler> HandlerRegistration registerHandler(
- final H handler, DomEvent.Type<H> 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<String, Object> parameters = new HashMap<String, Object>();
- 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 <H extends EventHandler> HandlerRegistration registerHandler( + final H handler, DomEvent.Type<H> 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<String, Object> parameters = new HashMap<String, Object>(); + 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="" /> +<title>EmbeddedClickListenerRelativeCoordinates</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">EmbeddedClickListenerRelativeCoordinates</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/EmbeddedClickListenerRelativeCoordinates</td> + <td></td> +</tr> +<tr> + <td>waitForVaadin</td> + <td></td> + <td></td> +</tr> +<tr> + <td>waitForVaadin</td> + <td></td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=vaadinrunEmbeddedClickListenerRelativeCoordinates::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VEmbedded[0]/domChild[0]</td> + <td>41,22</td> +</tr> +<tr> + <td>waitForVaadin</td> + <td></td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td></td> +</tr> + +</tbody></table> +</body> +</html> 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 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="http://192.168.2.60:8080/" /> +<title>PanelClickListenerRelativeCoordinates</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">PanelClickListenerRelativeCoordinates</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/vaadin/run/PanelClickListenerRelativeCoordinates</td> + <td></td> +</tr> +<tr> + <td>waitForVaadin</td> + <td></td> + <td></td> +</tr> +<tr> + <td>waitForVaadin</td> + <td></td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=vaadinrunPanelClickListenerRelativeCoordinates::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VPanel[0]/VVerticalLayout[0]</td> + <td>287,25</td> +</tr> +<tr> + <td>waitForVaadin</td> + <td></td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td></td> +</tr> + +</tbody></table> +</body> +</html> 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() + ")"); } |