svn changeset:13800/svn branch:6.4tags/6.7.0.beta1
@@ -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. | |||
* |
@@ -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(); | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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()); | |||
@@ -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; |
@@ -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; | |||
} | |||
} | |||
/** |
@@ -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> |
@@ -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; | |||
} | |||
} |
@@ -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> |
@@ -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; | |||
} | |||
} |
@@ -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() + ")"); | |||
} | |||