summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/com')
-rw-r--r--src/com/vaadin/event/ClientEventList.java82
-rw-r--r--src/com/vaadin/event/ComponentEventListener.java8
-rw-r--r--src/com/vaadin/event/FieldEvents.java92
-rw-r--r--src/com/vaadin/event/MouseEvents.java82
-rwxr-xr-xsrc/com/vaadin/terminal/gwt/client/ApplicationConnection.java27
-rw-r--r--src/com/vaadin/terminal/gwt/client/ComponentDetail.java34
-rw-r--r--src/com/vaadin/terminal/gwt/client/ComponentEventHandler.java114
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java10
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java31
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java57
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VPanel.java12
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTextField.java2
-rw-r--r--src/com/vaadin/tools/ReflectTools.java29
-rw-r--r--src/com/vaadin/ui/AbstractComponent.java231
-rw-r--r--src/com/vaadin/ui/AbstractOrderedLayout.java67
-rw-r--r--src/com/vaadin/ui/Component.java9
-rw-r--r--src/com/vaadin/ui/Embedded.java18
-rw-r--r--src/com/vaadin/ui/GridLayout.java34
-rw-r--r--src/com/vaadin/ui/Panel.java21
-rw-r--r--src/com/vaadin/ui/TextField.java33
20 files changed, 945 insertions, 48 deletions
diff --git a/src/com/vaadin/event/ClientEventList.java b/src/com/vaadin/event/ClientEventList.java
new file mode 100644
index 0000000000..633026ca8b
--- /dev/null
+++ b/src/com/vaadin/event/ClientEventList.java
@@ -0,0 +1,82 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.event;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ * this class is used to store the registered events so a list of the required
+ * client event identifiers (that the client-side should listen for and send to
+ * the server-side) can be sent to the client-side via a variable.
+ *
+ * @author davengo GmbH (Germany/Berlin, www.davengo.com)
+ *
+ */
+public class ClientEventList {
+
+ /**
+ * the list containing the registered client events (as strings for
+ * client-side transfer)
+ */
+ private Map<String, Integer> clientEvents = null;
+
+ /**
+ * initializes the list if necessary
+ */
+ private void checkList() {
+ if (clientEvents == null) {
+ clientEvents = new HashMap<String, Integer>();
+ }
+ }
+
+ /**
+ * listens for the event <br>
+ * <br>
+ * increments the internal counter for the event by one
+ *
+ * @param eventIdentifier
+ * the identifier of the event to listen for
+ */
+ public void listenEvent(String eventIdentifier) {
+ checkList();
+ if (!clientEvents.keySet().contains(eventIdentifier))
+ clientEvents.put(eventIdentifier, 1);
+ else
+ clientEvents.put(eventIdentifier,
+ clientEvents.get(eventIdentifier) + 1);
+ }
+
+ /**
+ * unlistens for an event <br>
+ * <br>
+ * decrements the internal counter by one, if 0 is reached the event is
+ * removed from the event-list
+ *
+ * @param eventIdentifier
+ * the identifier of the event to stop listening for
+ */
+ public void unlistenEvent(String eventIdentifier) {
+ checkList();
+ if (clientEvents.keySet().contains(eventIdentifier)) {
+ clientEvents.put(eventIdentifier,
+ clientEvents.get(eventIdentifier) - 1);
+ if (clientEvents.get(eventIdentifier) <= 0)
+ clientEvents.remove(eventIdentifier);
+ }
+ }
+
+ /**
+ * @return a string array containing all registered events
+ */
+ public String[] getEvents() {
+ if (clientEvents == null) {
+ return new String[] {};
+ }
+ return clientEvents.keySet().toArray(new String[] {});
+ }
+
+}
diff --git a/src/com/vaadin/event/ComponentEventListener.java b/src/com/vaadin/event/ComponentEventListener.java
new file mode 100644
index 0000000000..723fc090c0
--- /dev/null
+++ b/src/com/vaadin/event/ComponentEventListener.java
@@ -0,0 +1,8 @@
+package com.vaadin.event;
+
+import java.io.Serializable;
+import java.util.EventListener;
+
+public interface ComponentEventListener extends EventListener, Serializable {
+
+} \ No newline at end of file
diff --git a/src/com/vaadin/event/FieldEvents.java b/src/com/vaadin/event/FieldEvents.java
new file mode 100644
index 0000000000..ab81ac85c0
--- /dev/null
+++ b/src/com/vaadin/event/FieldEvents.java
@@ -0,0 +1,92 @@
+package com.vaadin.event;
+
+import java.lang.reflect.Method;
+
+import com.vaadin.tools.ReflectTools;
+import com.vaadin.ui.Component;
+
+public interface FieldEvents {
+
+ /*
+ * component focus event and listener
+ */
+
+ public class FocusEvent extends Component.Event {
+
+ private static final long serialVersionUID = -7644184999481404162L;
+
+ public FocusEvent(Component source) {
+ super(source);
+ }
+ }
+
+ public interface FocusListener extends ComponentEventListener {
+
+ public static final Method focusMethod = ReflectTools.findMethod(
+ FocusListener.class, "focus", FocusEvent.class);
+
+ /**
+ * Component has been focused
+ *
+ * @param event
+ * Component focus event.
+ */
+ public void focus(FocusEvent event);
+ }
+
+ /*
+ * component blur event and listener
+ */
+
+ public class BlurEvent extends Component.Event {
+
+ private static final long serialVersionUID = -7644184999481404162L;
+
+ public BlurEvent(Component source) {
+ super(source);
+ }
+ }
+
+ public interface BlurListener extends ComponentEventListener {
+
+ public static final Method blurMethod = ReflectTools.findMethod(
+ BlurListener.class, "blur", BlurEvent.class);
+
+ /**
+ * Component has been blurred
+ *
+ * @param event
+ * Component blur event.
+ */
+ public void blur(BlurEvent event);
+ }
+
+ /*
+ * component value change event
+ */
+
+ public class ValueChangeEvent extends Component.Event {
+
+ private static final long serialVersionUID = -7644184999481404162L;
+
+ public ValueChangeEvent(Component source) {
+ super(source);
+ }
+ }
+
+ public interface ValueChangeListener extends ComponentEventListener {
+
+ public static final Method valueChangeMethod = ReflectTools.findMethod(
+ ValueChangeListener.class, "valueChange",
+ ValueChangeEvent.class);
+
+ /**
+ * Component value was changed
+ *
+ * @param event
+ * Component change event.
+ */
+ public void valueChange(ValueChangeEvent event);
+ }
+
+}
diff --git a/src/com/vaadin/event/MouseEvents.java b/src/com/vaadin/event/MouseEvents.java
new file mode 100644
index 0000000000..19fdff8cc4
--- /dev/null
+++ b/src/com/vaadin/event/MouseEvents.java
@@ -0,0 +1,82 @@
+package com.vaadin.event;
+
+import java.lang.reflect.Method;
+
+import com.vaadin.tools.ReflectTools;
+import com.vaadin.ui.Component;
+
+public interface MouseEvents {
+
+ /**
+ * defines the clicked mouse button for a ComponentClickEvents
+ */
+ public enum MouseButton {
+ LEFT, RIGHT, MIDDLE
+ }
+
+ public class ClickEvent extends Component.Event {
+
+ private MouseButton mouseButton;
+
+ private static final long serialVersionUID = -7644184999481404162L;
+
+ public ClickEvent(Component source, String mouseButton) {
+ super(source);
+ if (mouseButton.equals("left")) {
+ this.mouseButton = MouseButton.LEFT;
+ } else if (mouseButton.equals("right")) {
+ this.mouseButton = MouseButton.RIGHT;
+ } else {
+ this.mouseButton = MouseButton.MIDDLE;
+ }
+ }
+
+ public MouseButton getMouseButton() {
+ return mouseButton;
+ }
+
+ }
+
+ public interface ClickListener extends ComponentEventListener {
+
+ public static final Method clickMethod = ReflectTools.findMethod(
+ ClickListener.class, "click", ClickEvent.class);
+
+ /**
+ * Component has been clicked
+ *
+ * @param event
+ * Component click event.
+ */
+ public void click(ClickEvent event);
+ }
+
+ /*
+ * component double click event
+ */
+
+ public class DoubleClickEvent extends Component.Event {
+
+ private static final long serialVersionUID = -7644184999481404162L;
+
+ public DoubleClickEvent(Component source) {
+ super(source);
+ }
+ }
+
+ public interface DoubleClickListener extends ComponentEventListener {
+
+ public static final Method doubleClickMethod = ReflectTools.findMethod(
+ DoubleClickListener.class, "doubleClick",
+ DoubleClickEvent.class);
+
+ /**
+ * Component value was changed
+ *
+ * @param event
+ * Component change event.
+ */
+ public void doubleClick(DoubleClickEvent event);
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index 4adfc86342..362e3eb8b1 100755
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -845,11 +845,11 @@ public class ApplicationConnection {
}
}-*/;
- public void registerPaintable(String id, Paintable paintable) {
- ComponentDetail componentDetail = new ComponentDetail();
- componentDetail.setComponent(paintable);
- idToPaintableDetail.put(id, componentDetail);
- setPid(((Widget) paintable).getElement(), id);
+ public void registerPaintable(String pid, Paintable paintable) {
+ ComponentDetail componentDetail = new ComponentDetail(this, pid,
+ paintable);
+ idToPaintableDetail.put(pid, componentDetail);
+ setPid(((Widget) paintable).getElement(), pid);
}
private native void setPid(Element el, String pid)
@@ -1113,6 +1113,10 @@ public class ApplicationConnection {
return true;
}
+ // register the listened events by the server-side to the event-handler
+ // of the component
+ componentDetail.getEventHandler().registerEventsFromUIDL(uidl);
+
// Visibility
boolean visible = !uidl.getBooleanAttribute("invisible");
boolean wasVisible = component.isVisible();
@@ -1780,4 +1784,17 @@ public class ApplicationConnection {
return configuration;
}
+ /**
+ * returns the event handler for the given paintable
+ *
+ * @param paintable
+ * @return
+ */
+ public ComponentEventHandler getEventHandler(Paintable paintable) {
+ ComponentDetail componentDetail = idToPaintableDetail
+ .get(getPid(paintable));
+
+ return componentDetail.getEventHandler();
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ComponentDetail.java b/src/com/vaadin/terminal/gwt/client/ComponentDetail.java
index 8e61ec7429..8f39733ef1 100644
--- a/src/com/vaadin/terminal/gwt/client/ComponentDetail.java
+++ b/src/com/vaadin/terminal/gwt/client/ComponentDetail.java
@@ -6,9 +6,21 @@ import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
import com.vaadin.terminal.gwt.client.RenderInformation.Size;
class ComponentDetail {
- private String pid;
+
+ private ComponentEventHandler eventHandler;
private Paintable component;
private TooltipInfo tooltipInfo = new TooltipInfo();
+ private String pid;
+
+ public ComponentDetail(ApplicationConnection client, String pid,
+ Paintable component) {
+ this.component = component;
+ this.pid = pid;
+
+ // create the event handler for this component
+ this.eventHandler = new ComponentEventHandler(this, client);
+
+ }
/**
* Returns a TooltipInfo assosiated with Component. If element is given,
@@ -49,14 +61,6 @@ class ComponentDetail {
}
/**
- * @param pid
- * the pid to set
- */
- void setPid(String pid) {
- this.pid = pid;
- }
-
- /**
* @return the component
*/
Paintable getComponent() {
@@ -64,14 +68,6 @@ class ComponentDetail {
}
/**
- * @param component
- * the component to set
- */
- void setComponent(Paintable component) {
- this.component = component;
- }
-
- /**
* @return the relativeSize
*/
FloatSize getRelativeSize() {
@@ -112,4 +108,8 @@ class ComponentDetail {
}
}
+ public ComponentEventHandler getEventHandler() {
+ return eventHandler;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ComponentEventHandler.java b/src/com/vaadin/terminal/gwt/client/ComponentEventHandler.java
new file mode 100644
index 0000000000..f309f79979
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ComponentEventHandler.java
@@ -0,0 +1,114 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * class for event handlers used by ComponentEventHandler
+ *
+ * @author davengo GmbH (Germany/Berlin, www.davengo.com)
+ *
+ */
+public class ComponentEventHandler {
+
+ public static final String HANDLER_LISTEN_ATTRIBUTE = "listenEvents";
+ public static final String HANDLER_TRIGGER_VARIABLE = "fireEvent";
+
+ private List<String> eventRegistrations;
+ private ComponentDetail detail;
+ private ApplicationConnection client;
+
+ public ComponentEventHandler(ComponentDetail detail,
+ ApplicationConnection client) {
+ this.detail = detail;
+ this.client = client;
+ this.eventRegistrations = null;
+ }
+
+ /**
+ * Fires a event which is transmitted to the server and passed on the the
+ * components handleEvent method provided listeners have been registered on
+ * the server side.
+ *
+ * @param eventIdentifier
+ * the unique identifier for the event
+ * @param parameters
+ * the parameters for the event (can be null)
+ */
+ public void fireEvent(String eventIdentifier, String... parameters) {
+ fireEvent(eventIdentifier, false, parameters);
+ }
+
+ /**
+ * Fires a component event which is transmitted to the server and passed on
+ * the the components handleEvent method. The event is sent to the server
+ * even though there are no explicit listeners registered on the server
+ * side.
+ *
+ * @param eventIdentifier
+ * the unique identifier for the event
+ * @param parameters
+ * the parameters for the event (can be null)
+ */
+ public void fireComponentEvent(String eventIdentifier, String... parameters) {
+ fireEvent(eventIdentifier, true, parameters);
+ }
+
+ private void fireEvent(String eventIdentifier, boolean forceTransmission,
+ String... parameters) {
+
+ String[] event;
+
+ // filter events which are not listened on the server-side right here
+ boolean transmit = forceTransmission
+ || ((!(eventRegistrations == null)) && eventRegistrations
+ .contains(eventIdentifier));
+
+ if (transmit) {
+ if (parameters != null) {
+ event = new String[parameters.length + 1];
+ event[0] = eventIdentifier;
+ for (int i = 0; i < parameters.length; i++) {
+ event[i + 1] = parameters[i];
+ }
+ } else {
+ event = new String[] { eventIdentifier };
+ }
+
+ // transmit the event to the server-side
+ client.updateVariable(detail.getPid(), HANDLER_TRIGGER_VARIABLE,
+ event, true);
+ }
+ }
+
+ void registerEventsFromUIDL(UIDL componentUIDL) {
+
+ // read out the request event handlers
+ if (componentUIDL.hasAttribute(HANDLER_LISTEN_ATTRIBUTE)) {
+ String[] requestedEvents = componentUIDL
+ .getStringArrayAttribute(HANDLER_LISTEN_ATTRIBUTE);
+
+ // create the eventRegistrations list if necessary
+ if ((requestedEvents.length > 0) && (eventRegistrations == null)) {
+ eventRegistrations = new ArrayList<String>();
+ }
+
+ // parse the requested event handlers
+ for (String reqEvent : requestedEvents) {
+
+ if (!eventRegistrations.contains(reqEvent)) {
+ eventRegistrations.add(reqEvent);
+ }
+
+ }
+
+ }
+
+ }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java b/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
index c05f1c06d3..159ecafa53 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
@@ -11,6 +11,8 @@ import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.dom.client.ObjectElement;
import com.google.gwt.dom.client.Style;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -22,7 +24,7 @@ import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.VTooltip;
-public class VEmbedded extends HTML implements Paintable {
+public class VEmbedded extends HTML implements Paintable, ClickHandler {
private static String CLASSNAME = "v-embedded";
private String height;
@@ -33,6 +35,7 @@ public class VEmbedded extends HTML implements Paintable {
public VEmbedded() {
setStyleName(CLASSNAME);
+ addClickHandler(this);
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
@@ -236,4 +239,9 @@ public class VEmbedded extends HTML implements Paintable {
client.handleTooltipEvent(event, this);
}
+
+ public void onClick(ClickEvent event) {
+ client.getEventHandler(this).fireEvent("click", "left");
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
index e2f217267a..366476bef0 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
@@ -14,6 +14,9 @@ import java.util.Set;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.SimplePanel;
@@ -28,7 +31,8 @@ import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;
import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
-public class VGridLayout extends SimplePanel implements Paintable, Container {
+public class VGridLayout extends SimplePanel implements Paintable, Container,
+ ClickHandler {
public static final String CLASSNAME = "v-gridlayout";
@@ -71,6 +75,8 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
getElement().appendChild(margin);
setStyleName(CLASSNAME);
setWidget(canvas);
+
+ addDomHandler(this, ClickEvent.getType());
}
@Override
@@ -1021,4 +1027,27 @@ public class VGridLayout extends SimplePanel implements Paintable, Container {
}
return cell;
}
+
+ public void onClick(ClickEvent event) {
+ String col = null;
+ String row = null;
+
+ Element clickTarget = (Element) event.getNativeEvent().getEventTarget()
+ .cast();
+ Element rootElement = getElement();
+ while (clickTarget != null && clickTarget != rootElement) {
+ Paintable paintable = client.getPaintable(clickTarget);
+ if (paintable != null) {
+ Cell cell = paintableToCell.get(paintable);
+ row = String.valueOf(cell.row);
+ col = String.valueOf(cell.col);
+ break;
+ }
+ clickTarget = DOM.getParent(clickTarget);
+ }
+
+ client.getEventHandler(this).fireEvent("click", "left", row, col);
+
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java
index 282136383d..10d7fe4d02 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java
@@ -5,6 +5,12 @@ import java.util.Iterator;
import java.util.Set;
import com.google.gwt.core.client.JsArrayString;
+import com.google.gwt.dom.client.Node;
+import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.DOM;
+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.BrowserInfo;
@@ -18,7 +24,7 @@ import com.vaadin.terminal.gwt.client.RenderInformation.Size;
import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;
import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
-public class VOrderedLayout extends CellBasedLayout {
+public class VOrderedLayout extends CellBasedLayout implements ClickHandler {
public static final String CLASSNAME = "v-orderedlayout";
@@ -49,6 +55,7 @@ public class VOrderedLayout extends CellBasedLayout {
public VOrderedLayout() {
this(CLASSNAME, ORIENTATION_VERTICAL);
allowOrientationUpdate = true;
+ addDomHandler(this, ClickEvent.getType());
}
protected VOrderedLayout(String className, int orientation) {
@@ -61,6 +68,7 @@ public class VOrderedLayout extends CellBasedLayout {
STYLENAME_MARGIN_BOTTOM = className + "-margin-bottom";
STYLENAME_MARGIN_LEFT = className + "-margin-left";
+ addDomHandler(this, ClickEvent.getType());
}
@Override
@@ -915,4 +923,51 @@ public class VOrderedLayout extends CellBasedLayout {
}
}
+ public void onClick(ClickEvent event) {
+ Integer childComponentId = getChildComponentId((Element) event
+ .getNativeEvent().getEventTarget().cast());
+ String childComponentString = childComponentId.toString();
+ client.getEventHandler(this).fireEvent("click", "left",
+ childComponentString);
+
+ }
+
+ /**
+ * Returns the index of the child component which contains "element".
+ *
+ * @param element
+ * @return
+ */
+ private int getChildComponentId(Element element) {
+ Element rootElement = getElement();
+ Element parent = DOM.getParent(element);
+ if (parent == null) {
+ return -1;
+ }
+ Element grandParent = DOM.getParent(parent);
+ if (grandParent == null) {
+ return -1;
+ }
+
+ while (grandParent != null && parent != rootElement) {
+ if (grandParent == rootElement) {
+ NodeList<Node> nodes = parent.getChildNodes();
+ int size = nodes.getLength();
+ for (int index = 0; index < size; index++) {
+ if (nodes.getItem(index) == element) {
+ return index;
+ }
+ }
+
+ // This should not happen
+ return -1;
+ }
+
+ element = parent;
+ parent = grandParent;
+ grandParent = DOM.getParent(grandParent);
+ }
+ return -1;
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
index ec4acf2e4d..608a7fd9ab 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
@@ -8,6 +8,8 @@ import java.util.Set;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -22,7 +24,7 @@ import com.vaadin.terminal.gwt.client.RenderSpace;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
-public class VPanel extends SimplePanel implements Container {
+public class VPanel extends SimplePanel implements Container, ClickHandler {
public static final String CLASSNAME = "v-panel";
@@ -91,6 +93,9 @@ public class VPanel extends SimplePanel implements Container {
DOM.sinkEvents(contentNode, Event.ONSCROLL);
contentNode.getStyle().setProperty("position", "relative");
getElement().getStyle().setProperty("overflow", "hidden");
+
+ addDomHandler(this, ClickEvent.getType());
+
}
@Override
@@ -334,6 +339,8 @@ public class VPanel extends SimplePanel implements Container {
@Override
public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+
final Element target = DOM.eventGetTarget(event);
final int type = DOM.eventGetType(event);
if (type == Event.ONKEYDOWN && shortcutHandler != null) {
@@ -516,4 +523,7 @@ public class VPanel extends SimplePanel implements Container {
detectContainerBorders();
}
+ public void onClick(ClickEvent event) {
+ client.getEventHandler(this).fireEvent("click", "left");
+ }
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
index 845a50e793..860891f99f 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
@@ -195,6 +195,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
}
}
focusedTextField = this;
+ client.getEventHandler(this).fireEvent("focus", (String[]) null);
}
public void onBlur(BlurEvent event) {
@@ -207,6 +208,7 @@ public class VTextField extends TextBoxBase implements Paintable, Field,
addStyleDependentName(CLASSNAME_PROMPT);
}
onChange(null);
+ client.getEventHandler(this).fireEvent("blur", (String[]) null);
}
private void setPrompting(boolean prompting) {
diff --git a/src/com/vaadin/tools/ReflectTools.java b/src/com/vaadin/tools/ReflectTools.java
new file mode 100644
index 0000000000..d74efba105
--- /dev/null
+++ b/src/com/vaadin/tools/ReflectTools.java
@@ -0,0 +1,29 @@
+package com.vaadin.tools;
+
+import java.lang.reflect.Method;
+
+public class ReflectTools {
+ /**
+ * Locates the method in the given class. Returns null if the method is not
+ * found. This method never throws exceptions. Errors in locating methods
+ * are considered serious problems and are output to standard error.
+ *
+ * @param cls
+ * Class that contains the method
+ * @param methodName
+ * The name of the method
+ * @param parameterTypes
+ * The parameter types for the method.
+ * @return A method reference or null if the method was not found
+ */
+ public static Method findMethod(Class<?> cls, String methodName,
+ Class<?>... parameterTypes) {
+ try {
+ return cls.getDeclaredMethod(methodName, parameterTypes);
+ } catch (Exception e) {
+ // Print the stack trace as
+ e.printStackTrace(System.err);
+ }
+ return null;
+ }
+}
diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java
index 2e6a0d6e19..c624cf3224 100644
--- a/src/com/vaadin/ui/AbstractComponent.java
+++ b/src/com/vaadin/ui/AbstractComponent.java
@@ -16,6 +16,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.vaadin.Application;
+import com.vaadin.event.ClientEventList;
import com.vaadin.event.EventRouter;
import com.vaadin.event.MethodEventSource;
import com.vaadin.terminal.ErrorMessage;
@@ -23,7 +24,9 @@ import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.Terminal;
+import com.vaadin.terminal.gwt.client.ComponentEventHandler;
import com.vaadin.terminal.gwt.server.ComponentSizeValidator;
+import com.vaadin.tools.ReflectTools;
/**
* An abstract class that defines default implementation for the
@@ -93,6 +96,12 @@ public abstract class AbstractComponent implements Component, MethodEventSource
private EventRouter eventRouter = null;
/**
+ * The ClientEventList used for collecting client events which should be
+ * transmitted from the client to the server
+ */
+ private ClientEventList clientEvents = null;
+
+ /**
* The internal error message of the component.
*/
private ErrorMessage componentError = null;
@@ -679,6 +688,22 @@ public abstract class AbstractComponent implements Component, MethodEventSource
target.addAttribute("description", getDescription());
}
+ // davengo GmbH: add client event variables
+ String[] trigger = new String[] {};
+ String[] events = new String[] {};
+ if (clientEvents != null) {
+ events = clientEvents.getEvents();
+ }
+ if (events.length != 0) {
+ target.addVariable(this,
+ ComponentEventHandler.HANDLER_TRIGGER_VARIABLE,
+ trigger);
+ target.addAttribute(
+ ComponentEventHandler.HANDLER_LISTEN_ATTRIBUTE,
+ events);
+ }
+ // end of event variables
+
paintContent(target);
final ErrorMessage error = getErrorMessage();
@@ -813,6 +838,62 @@ public abstract class AbstractComponent implements Component, MethodEventSource
}
}
+ /**
+ * this method is executed when a event arrives from the event-api.<br>
+ * this should be overridden by components which intend to use the event-api
+ * mechanism for registering Events.
+ *
+ * @param eventIdentifier
+ * @param parameters
+ */
+ protected void handleEvent(String eventIdentifier, String[] parameters) {
+ // implemented by subclasses
+ }
+
+ /**
+ * listens to the specified event type.<br>
+ * on changes of the registered event by the client-side component, the
+ * method handleEvent(String event, String[] parameters) will be invoked (as
+ * long as either a listener is registered at the component for the given
+ * event type or the forceTransmission flag has been set by the client-side
+ * component). <br>
+ * <br>
+ * <b>for every listener attached to this component this method has to be
+ * called once. the client-event list holds a counter on how-many listeners
+ * are listening for an event.</b><br>
+ * <br>
+ * this method should be executed by components which intend to use the
+ * event-api mechanism for listening on events.
+ *
+ * @param eventIdentifier
+ */
+ private void listenEvent(String eventIdentifier) {
+ if (clientEvents == null) {
+ clientEvents = new ClientEventList();
+ }
+ clientEvents.listenEvent(eventIdentifier);
+ requestRepaint();
+ }
+
+ /**
+ * stops listening to the specified event type. <br>
+ * <br>
+ * <b>for every listener detached from this component this method has to be
+ * called once. the client-event list holds a counter on how-many listeners
+ * are listening for an event.</b><br>
+ * <br>
+ * this method should be executed by components which intend to use the
+ * event-api mechanism for listening on events.
+ *
+ * @param eventIdentifier
+ */
+ private void unlistenEvent(String eventIdentifier) {
+ if (clientEvents != null) {
+ clientEvents.unlistenEvent(eventIdentifier);
+ requestRepaint();
+ }
+ }
+
/* Component variable changes */
/*
@@ -821,22 +902,138 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* interface.
*/
public void changeVariables(Object source, Map variables) {
+
+ // handle events when triggered
+ if (variables
+ .containsKey(ComponentEventHandler.HANDLER_TRIGGER_VARIABLE)) {
+ String[] firedEvent = (String[]) variables
+ .get(ComponentEventHandler.HANDLER_TRIGGER_VARIABLE);
+
+ // detect vaadin events
+ String[] params = new String[firedEvent.length - 1];
+
+ for (int i = 0; i < params.length; i++) {
+ params[i] = firedEvent[i + 1];
+ }
+
+ String event = firedEvent[0];
+
+ handleEvent(event, params);
+
+ }
+
}
/* General event framework */
- private static final Method COMPONENT_EVENT_METHOD;
-
- static {
- try {
- COMPONENT_EVENT_METHOD = Component.Listener.class
- .getDeclaredMethod("componentEvent",
- new Class[] { Component.Event.class });
- } catch (final java.lang.NoSuchMethodException e) {
- // This should never happen
- throw new java.lang.RuntimeException(
- "Internal error finding methods in AbstractComponent");
+ private static final Method COMPONENT_EVENT_METHOD = ReflectTools
+ .findMethod(Component.Listener.class, "componentEvent",
+ Component.Event.class);
+
+ /**
+ * <p>
+ * Registers a new listener with the specified activation method to listen
+ * events generated by this component. If the activation method does not
+ * have any arguments the event object will not be passed to it when it's
+ * called.
+ * </p>
+ *
+ * <p>
+ * This method additionally informs the event-api to route events with the
+ * given eventIdentifier to the components handleEvent function call.
+ * </p>
+ *
+ * <p>
+ * For more information on the inheritable event mechanism see the
+ * {@link com.vaadin.event com.vaadin.event package documentation}.
+ * </p>
+ *
+ * @param eventIdentifier
+ * the identifier of the event to listen for
+ * @param eventType
+ * the type of the listened event. Events of this type or its
+ * subclasses activate the listener.
+ * @param object
+ * the object instance who owns the activation method.
+ * @param method
+ * the activation method.
+ */
+ protected void addEventListener(String eventIdentifier, Class<?> eventType,
+ Object object, Method method) {
+ if (eventRouter == null) {
+ eventRouter = new EventRouter();
}
+ eventRouter.addListener(eventType, object, method);
+ listenEvent(eventIdentifier);
+ }
+
+ /**
+ * Removes all registered listeners matching the given parameters. Since
+ * this method receives the event type and the listener object as
+ * parameters, it will unregister all <code>object</code>'s methods that are
+ * registered to listen to events of type <code>eventType</code> generated
+ * by this component.
+ *
+ * <p>
+ * This method additionally informs the event-api to stop routing events
+ * with the given eventIdentifier to the components handleEvent function
+ * call.
+ * </p>
+ *
+ * <p>
+ * For more information on the inheritable event mechanism see the
+ * {@link com.vaadin.event com.vaadin.event package documentation}.
+ * </p>
+ *
+ * @param eventIdentifier
+ * the identifier of the event to stop listening for
+ * @param eventType
+ * the exact event type the <code>object</code> listens to.
+ * @param target
+ * the target object that has registered to listen to events of
+ * type <code>eventType</code> with one or more methods.
+ */
+ protected void removeEventListener(String eventIdentifier,
+ Class<?> eventType, Object target) {
+ if (eventRouter != null) {
+ eventRouter.removeListener(eventType, target);
+ }
+ unlistenEvent(eventIdentifier);
+ }
+
+ /**
+ * Removes one registered listener method. The given method owned by the
+ * given object will no longer be called when the specified events are
+ * generated by this component.
+ *
+ * <p>
+ * This method additionally informs the event-api to stop routing events
+ * with the given eventIdentifier to the components handleEvent function
+ * call.
+ * </p>
+ *
+ * <p>
+ * For more information on the inheritable event mechanism see the
+ * {@link com.vaadin.event com.vaadin.event package documentation}.
+ * </p>
+ *
+ * @param eventIdentifier
+ * the identifier of the event to stop listening for
+ * @param eventType
+ * the exact event type the <code>object</code> listens to.
+ * @param target
+ * target object that has registered to listen to events of type
+ * <code>eventType</code> with one or more methods.
+ * @param method
+ * the method owned by <code>target</code> that's registered to
+ * listen to events of type <code>eventType</code>.
+ */
+ protected void removeEventListener(String eventIdentifier, Class eventType,
+ Object target, Method method) {
+ if (eventRouter != null) {
+ eventRouter.removeListener(eventType, target, method);
+ }
+ unlistenEvent(eventIdentifier);
}
/**
@@ -1012,12 +1209,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* implemented interface.
*/
public void addListener(Component.Listener listener) {
- if (eventRouter == null) {
- eventRouter = new EventRouter();
- }
-
- eventRouter.addListener(Component.Event.class, listener,
- COMPONENT_EVENT_METHOD);
+ addListener(Component.Event.class, listener, COMPONENT_EVENT_METHOD);
}
/*
@@ -1026,10 +1218,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
* interface.
*/
public void removeListener(Component.Listener listener) {
- if (eventRouter != null) {
- eventRouter.removeListener(Component.Event.class, listener,
- COMPONENT_EVENT_METHOD);
- }
+ removeListener(Component.Event.class, listener, COMPONENT_EVENT_METHOD);
}
/**
diff --git a/src/com/vaadin/ui/AbstractOrderedLayout.java b/src/com/vaadin/ui/AbstractOrderedLayout.java
index b43d155714..ed2f70d4f0 100644
--- a/src/com/vaadin/ui/AbstractOrderedLayout.java
+++ b/src/com/vaadin/ui/AbstractOrderedLayout.java
@@ -4,14 +4,18 @@
package com.vaadin.ui;
+import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
+import com.vaadin.event.ComponentEventListener;
+import com.vaadin.event.MouseEvents.ClickEvent;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Sizeable;
+import com.vaadin.tools.ReflectTools;
@SuppressWarnings("serial")
public abstract class AbstractOrderedLayout extends AbstractLayout implements
@@ -307,4 +311,67 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements
AlignmentUtils.setComponentAlignment(this, component, alignment);
}
+ public interface LayoutClickListener extends ComponentEventListener {
+
+ public static final Method clickMethod = ReflectTools.findMethod(
+ LayoutClickListener.class, "layoutClick",
+ LayoutClickEvent.class);
+
+ /**
+ * Layout has been clicked
+ *
+ * @param event
+ * Component click event.
+ */
+ public void layoutClick(LayoutClickEvent event);
+ }
+
+ /**
+ * An event fired when the layout has been clicked. The event contains
+ * information about the target layout (component) and the child component
+ * that was clicked. If no child component was found it is set to null.
+ *
+ */
+ public static class LayoutClickEvent extends ClickEvent {
+
+ private Component childComponent;
+
+ public LayoutClickEvent(Component source, String mouseButton,
+ Component childComponent) {
+ super(source, mouseButton);
+ this.childComponent = childComponent;
+ }
+
+ public Component getChildComponent() {
+ return childComponent;
+ }
+
+ }
+
+ public void addListener(LayoutClickListener listener) {
+ addEventListener("click", LayoutClickEvent.class, listener,
+ LayoutClickListener.clickMethod);
+ }
+
+ public void removeListener(LayoutClickListener listener) {
+ removeEventListener("click", LayoutClickEvent.class, listener,
+ LayoutClickListener.clickMethod);
+ }
+
+ @Override
+ protected void handleEvent(String event, String[] parameters) {
+ if (event.equals("click")) {
+ String button = parameters[0];
+ String childComponentId = parameters[1];
+ Component childComponent = null;
+ try {
+ int id = Integer.parseInt(childComponentId);
+ childComponent = components.get(id);
+ } catch (Exception e) {
+ // TODO: handle exception
+ }
+
+ fireEvent(new LayoutClickEvent(this, button, childComponent));
+ }
+ }
}
diff --git a/src/com/vaadin/ui/Component.java b/src/com/vaadin/ui/Component.java
index ab7b7bb2ca..75d819f4b3 100644
--- a/src/com/vaadin/ui/Component.java
+++ b/src/com/vaadin/ui/Component.java
@@ -326,6 +326,15 @@ public interface Component extends Paintable, VariableOwner, Sizeable,
public Event(Component source) {
super(source);
}
+
+ /**
+ * Gets the Component where the event occurred.
+ *
+ * @return the Source of the event.
+ */
+ public Component getComponent() {
+ return (Component) getSource();
+ }
}
/**
diff --git a/src/com/vaadin/ui/Embedded.java b/src/com/vaadin/ui/Embedded.java
index 3b20641c5f..be60b744aa 100644
--- a/src/com/vaadin/ui/Embedded.java
+++ b/src/com/vaadin/ui/Embedded.java
@@ -7,6 +7,8 @@ package com.vaadin.ui;
import java.util.Hashtable;
import java.util.Iterator;
+import com.vaadin.event.MouseEvents.ClickEvent;
+import com.vaadin.event.MouseEvents.ClickListener;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
@@ -414,4 +416,20 @@ public class Embedded extends AbstractComponent {
}
}
+ public void addListener(ClickListener listener) {
+ addEventListener("click", ClickEvent.class, listener,
+ ClickListener.clickMethod);
+ }
+
+ public void removeListener(ClickListener listener) {
+ removeEventListener("click", ClickEvent.class, listener,
+ ClickListener.clickMethod);
+ }
+
+ @Override
+ protected void handleEvent(String event, String[] parameters) {
+ if (event.equals("click")) {
+ fireEvent(new ClickEvent(this, parameters[0]));
+ }
+ }
}
diff --git a/src/com/vaadin/ui/GridLayout.java b/src/com/vaadin/ui/GridLayout.java
index d07e232b1a..510a8051d7 100644
--- a/src/com/vaadin/ui/GridLayout.java
+++ b/src/com/vaadin/ui/GridLayout.java
@@ -15,6 +15,8 @@ import java.util.Map.Entry;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VGridLayout;
+import com.vaadin.ui.AbstractOrderedLayout.LayoutClickEvent;
+import com.vaadin.ui.AbstractOrderedLayout.LayoutClickListener;
/**
* <p>
@@ -72,7 +74,7 @@ public class GridLayout extends AbstractLayout implements
/**
* Mapping from components to their respective areas.
*/
- private final LinkedList components = new LinkedList();
+ private final LinkedList<Component> components = new LinkedList<Component>();
/**
* Mapping from components to alignments (horizontal + vertical).
@@ -1299,4 +1301,34 @@ public class GridLayout extends AbstractLayout implements
AlignmentUtils.setComponentAlignment(this, component, alignment);
}
+ public void addListener(LayoutClickListener listener) {
+ addEventListener("click", LayoutClickEvent.class, listener,
+ LayoutClickListener.clickMethod);
+ }
+
+ public void removeListener(LayoutClickListener listener) {
+ removeEventListener("click", LayoutClickEvent.class, listener,
+ LayoutClickListener.clickMethod);
+ }
+
+ @Override
+ protected void handleEvent(String event, String[] parameters) {
+ if (event.equals("click")) {
+ String button = parameters[0];
+ String childComponentRow = parameters[1];
+ String childComponentCol = parameters[2];
+
+ Component childComponent = null;
+ try {
+ childComponent = getComponent(Integer
+ .parseInt(childComponentCol), Integer
+ .parseInt(childComponentRow));
+ } catch (Exception e) {
+ // TODO: handle exception
+ }
+
+ fireEvent(new LayoutClickEvent(this, button, childComponent));
+ }
+ }
+
}
diff --git a/src/com/vaadin/ui/Panel.java b/src/com/vaadin/ui/Panel.java
index 03f1857386..2aaf697e85 100644
--- a/src/com/vaadin/ui/Panel.java
+++ b/src/com/vaadin/ui/Panel.java
@@ -11,6 +11,8 @@ import java.util.Map;
import com.vaadin.event.Action;
import com.vaadin.event.ShortcutAction;
import com.vaadin.event.Action.Handler;
+import com.vaadin.event.MouseEvents.ClickEvent;
+import com.vaadin.event.MouseEvents.ClickListener;
import com.vaadin.terminal.KeyMapper;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
@@ -543,4 +545,23 @@ public class Panel extends AbstractComponentContainer implements Scrollable,
requestRepaint();
}
}
+
+ @Override
+ protected void handleEvent(String eventIdentifier, String[] parameters) {
+ if (eventIdentifier.equals("click")) {
+ fireEvent(new ClickEvent(this, parameters[0]));
+ }
+ }
+
+ public void addListener(ClickListener listener) {
+ addEventListener("click", ClickEvent.class, listener,
+ ClickListener.clickMethod);
+ }
+
+ public void removeListener(ClickListener listener) {
+ removeEventListener("click", ClickEvent.class, listener,
+ ClickListener.clickMethod);
+
+ }
+
}
diff --git a/src/com/vaadin/ui/TextField.java b/src/com/vaadin/ui/TextField.java
index a773617265..94c97849c2 100644
--- a/src/com/vaadin/ui/TextField.java
+++ b/src/com/vaadin/ui/TextField.java
@@ -8,6 +8,10 @@ import java.text.Format;
import java.util.Map;
import com.vaadin.data.Property;
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VTextField;
@@ -547,4 +551,33 @@ public class TextField extends AbstractField {
requestRepaint();
}
+ @Override
+ protected void handleEvent(String eventIdentifier, String[] parameters) {
+ if (eventIdentifier.equals("focus")) {
+ fireEvent(new FocusEvent(this));
+ } else if (eventIdentifier.equals("blur")) {
+ fireEvent(new BlurEvent(this));
+ }
+ }
+
+ public void addListener(FocusListener listener) {
+ addEventListener("focus", FocusEvent.class, listener,
+ FocusListener.focusMethod);
+ }
+
+ public void removeListener(FocusListener listener) {
+ removeEventListener("focus", FocusEvent.class, listener,
+ FocusListener.focusMethod);
+ }
+
+ public void addListener(BlurListener listener) {
+ addEventListener("blur", BlurEvent.class, listener,
+ BlurListener.blurMethod);
+ }
+
+ public void removeListener(BlurListener listener) {
+ removeEventListener("blur", BlurEvent.class, listener,
+ BlurListener.blurMethod);
+ }
+
}