Browse Source

Merged and slightly modified fix for #4652 - MouseEventDetails and ClickEvent should provide coordinates relative to component

svn changeset:13800/svn branch:6.4
tags/6.7.0.beta1
Artur Signell 14 years ago
parent
commit
e9b730ddc0

+ 22
- 0
src/com/vaadin/event/MouseEvents.java View File

@@ -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.
*

+ 34
- 1
src/com/vaadin/terminal/gwt/client/MouseEventDetails.java View File

@@ -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();
}

}

+ 123
- 104
src/com/vaadin/terminal/gwt/client/ui/ClickEventHandler.java View File

@@ -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;
}

}

+ 2
- 1
src/com/vaadin/terminal/gwt/client/ui/LayoutClickEventHandler.java View File

@@ -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());


+ 6
- 0
src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java View File

@@ -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;

+ 5
- 32
src/com/vaadin/ui/Table.java View File

@@ -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;
}
}

/**

+ 47
- 0
tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.html View File

@@ -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>

+ 37
- 0
tests/src/com/vaadin/tests/components/embedded/EmbeddedClickListenerRelativeCoordinates.java View File

@@ -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;
}

}

+ 47
- 0
tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.html View File

@@ -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>

+ 36
- 0
tests/src/com/vaadin/tests/components/panel/PanelClickListenerRelativeCoordinates.java View File

@@ -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;
}

}

+ 3
- 1
tests/src/com/vaadin/tests/layouts/TestLayoutClickListeners.java View File

@@ -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() + ")");

}


Loading…
Cancel
Save