]> source.dussan.org Git - vaadin-framework.git/commitdiff
Initial commit for framework enhancement for #3234
authorArtur Signell <artur.signell@itmill.com>
Fri, 20 Nov 2009 12:33:35 +0000 (12:33 +0000)
committerArtur Signell <artur.signell@itmill.com>
Fri, 20 Nov 2009 12:33:35 +0000 (12:33 +0000)
svn changeset:9947/svn branch:event-framework-3234

20 files changed:
src/com/vaadin/event/ClientEventList.java [new file with mode: 0644]
src/com/vaadin/event/ComponentEventListener.java [new file with mode: 0644]
src/com/vaadin/event/FieldEvents.java [new file with mode: 0644]
src/com/vaadin/event/MouseEvents.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/ComponentDetail.java
src/com/vaadin/terminal/gwt/client/ComponentEventHandler.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java
src/com/vaadin/terminal/gwt/client/ui/VPanel.java
src/com/vaadin/terminal/gwt/client/ui/VTextField.java
src/com/vaadin/tools/ReflectTools.java [new file with mode: 0644]
src/com/vaadin/ui/AbstractComponent.java
src/com/vaadin/ui/AbstractOrderedLayout.java
src/com/vaadin/ui/Component.java
src/com/vaadin/ui/Embedded.java
src/com/vaadin/ui/GridLayout.java
src/com/vaadin/ui/Panel.java
src/com/vaadin/ui/TextField.java

diff --git a/src/com/vaadin/event/ClientEventList.java b/src/com/vaadin/event/ClientEventList.java
new file mode 100644 (file)
index 0000000..633026c
--- /dev/null
@@ -0,0 +1,82 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.event;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+/**\r
+ * \r
+ * this class is used to store the registered events so a list of the required\r
+ * client event identifiers (that the client-side should listen for and send to\r
+ * the server-side) can be sent to the client-side via a variable.\r
+ * \r
+ * @author davengo GmbH (Germany/Berlin, www.davengo.com)\r
+ * \r
+ */\r
+public class ClientEventList {\r
+\r
+    /**\r
+     * the list containing the registered client events (as strings for\r
+     * client-side transfer)\r
+     */\r
+    private Map<String, Integer> clientEvents = null;\r
+\r
+    /**\r
+     * initializes the list if necessary\r
+     */\r
+    private void checkList() {\r
+        if (clientEvents == null) {\r
+            clientEvents = new HashMap<String, Integer>();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * listens for the event <br>\r
+     * <br>\r
+     * increments the internal counter for the event by one\r
+     * \r
+     * @param eventIdentifier\r
+     *            the identifier of the event to listen for\r
+     */\r
+    public void listenEvent(String eventIdentifier) {\r
+        checkList();\r
+        if (!clientEvents.keySet().contains(eventIdentifier))\r
+            clientEvents.put(eventIdentifier, 1);\r
+        else\r
+            clientEvents.put(eventIdentifier,\r
+                    clientEvents.get(eventIdentifier) + 1);\r
+    }\r
+\r
+    /**\r
+     * unlistens for an event <br>\r
+     * <br>\r
+     * decrements the internal counter by one, if 0 is reached the event is\r
+     * removed from the event-list\r
+     * \r
+     * @param eventIdentifier\r
+     *            the identifier of the event to stop listening for\r
+     */\r
+    public void unlistenEvent(String eventIdentifier) {\r
+        checkList();\r
+        if (clientEvents.keySet().contains(eventIdentifier)) {\r
+            clientEvents.put(eventIdentifier,\r
+                    clientEvents.get(eventIdentifier) - 1);\r
+            if (clientEvents.get(eventIdentifier) <= 0)\r
+                clientEvents.remove(eventIdentifier);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * @return a string array containing all registered events\r
+     */\r
+    public String[] getEvents() {\r
+        if (clientEvents == null) {\r
+            return new String[] {};\r
+        }\r
+        return clientEvents.keySet().toArray(new String[] {});\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/event/ComponentEventListener.java b/src/com/vaadin/event/ComponentEventListener.java
new file mode 100644 (file)
index 0000000..723fc09
--- /dev/null
@@ -0,0 +1,8 @@
+package com.vaadin.event;\r
+\r
+import java.io.Serializable;\r
+import java.util.EventListener;\r
+\r
+public interface ComponentEventListener extends EventListener, Serializable {\r
+\r
+}
\ 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 (file)
index 0000000..ab81ac8
--- /dev/null
@@ -0,0 +1,92 @@
+package com.vaadin.event;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+import com.vaadin.tools.ReflectTools;\r
+import com.vaadin.ui.Component;\r
+\r
+public interface FieldEvents {\r
+\r
+    /*\r
+     * component focus event and listener\r
+     */\r
+\r
+    public class FocusEvent extends Component.Event {\r
+\r
+        private static final long serialVersionUID = -7644184999481404162L;\r
+\r
+        public FocusEvent(Component source) {\r
+            super(source);\r
+        }\r
+    }\r
+\r
+    public interface FocusListener extends ComponentEventListener {\r
+\r
+        public static final Method focusMethod = ReflectTools.findMethod(\r
+                FocusListener.class, "focus", FocusEvent.class);\r
+\r
+        /**\r
+         * Component has been focused\r
+         * \r
+         * @param event\r
+         *            Component focus event.\r
+         */\r
+        public void focus(FocusEvent event);\r
+    }\r
+\r
+    /*\r
+     * component blur event and listener\r
+     */\r
+\r
+    public class BlurEvent extends Component.Event {\r
+\r
+        private static final long serialVersionUID = -7644184999481404162L;\r
+\r
+        public BlurEvent(Component source) {\r
+            super(source);\r
+        }\r
+    }\r
+\r
+    public interface BlurListener extends ComponentEventListener {\r
+\r
+        public static final Method blurMethod = ReflectTools.findMethod(\r
+                BlurListener.class, "blur", BlurEvent.class);\r
+\r
+        /**\r
+         * Component has been blurred\r
+         * \r
+         * @param event\r
+         *            Component blur event.\r
+         */\r
+        public void blur(BlurEvent event);\r
+    }\r
+\r
+    /*\r
+     * component value change event\r
+     */\r
+\r
+    public class ValueChangeEvent extends Component.Event {\r
+\r
+        private static final long serialVersionUID = -7644184999481404162L;\r
+\r
+        public ValueChangeEvent(Component source) {\r
+            super(source);\r
+        }\r
+    }\r
+\r
+    public interface ValueChangeListener extends ComponentEventListener {\r
+\r
+        public static final Method valueChangeMethod = ReflectTools.findMethod(\r
+                ValueChangeListener.class, "valueChange",\r
+                ValueChangeEvent.class);\r
+\r
+        /**\r
+         * Component value was changed\r
+         * \r
+         * @param event\r
+         *            Component change event.\r
+         */\r
+        public void valueChange(ValueChangeEvent event);\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/event/MouseEvents.java b/src/com/vaadin/event/MouseEvents.java
new file mode 100644 (file)
index 0000000..19fdff8
--- /dev/null
@@ -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);
+    }
+
+}
index 4adfc86342e26051e29647a15d57c0be49fec100..362e3eb8b1edbf45a6e207cde0bba678c6f3833a 100755 (executable)
@@ -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();
+    }
+
 }
index 8e61ec74292ba20c10f69a17ed1fdc53ae6a9a1a..8f39733ef1d4221311b99ab94607963aadc2e7f3 100644 (file)
@@ -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,
@@ -48,14 +60,6 @@ class ComponentDetail {
         return pid;
     }
 
-    /**
-     * @param pid
-     *            the pid to set
-     */
-    void setPid(String pid) {
-        this.pid = pid;
-    }
-
     /**
      * @return the component
      */
@@ -63,14 +67,6 @@ class ComponentDetail {
         return component;
     }
 
-    /**
-     * @param component
-     *            the component to set
-     */
-    void setComponent(Paintable component) {
-        this.component = component;
-    }
-
     /**
      * @return the relativeSize
      */
@@ -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 (file)
index 0000000..f309f79
--- /dev/null
@@ -0,0 +1,114 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * \r
+ * class for event handlers used by ComponentEventHandler\r
+ * \r
+ * @author davengo GmbH (Germany/Berlin, www.davengo.com)\r
+ * \r
+ */\r
+public class ComponentEventHandler {\r
+\r
+    public static final String HANDLER_LISTEN_ATTRIBUTE = "listenEvents";\r
+    public static final String HANDLER_TRIGGER_VARIABLE = "fireEvent";\r
+\r
+    private List<String> eventRegistrations;\r
+    private ComponentDetail detail;\r
+    private ApplicationConnection client;\r
+\r
+    public ComponentEventHandler(ComponentDetail detail,\r
+            ApplicationConnection client) {\r
+        this.detail = detail;\r
+        this.client = client;\r
+        this.eventRegistrations = null;\r
+    }\r
+\r
+    /**\r
+     * Fires a event which is transmitted to the server and passed on the the\r
+     * components handleEvent method provided listeners have been registered on\r
+     * the server side.\r
+     * \r
+     * @param eventIdentifier\r
+     *            the unique identifier for the event\r
+     * @param parameters\r
+     *            the parameters for the event (can be null)\r
+     */\r
+    public void fireEvent(String eventIdentifier, String... parameters) {\r
+        fireEvent(eventIdentifier, false, parameters);\r
+    }\r
+\r
+    /**\r
+     * Fires a component event which is transmitted to the server and passed on\r
+     * the the components handleEvent method. The event is sent to the server\r
+     * even though there are no explicit listeners registered on the server\r
+     * side.\r
+     * \r
+     * @param eventIdentifier\r
+     *            the unique identifier for the event\r
+     * @param parameters\r
+     *            the parameters for the event (can be null)\r
+     */\r
+    public void fireComponentEvent(String eventIdentifier, String... parameters) {\r
+        fireEvent(eventIdentifier, true, parameters);\r
+    }\r
+\r
+    private void fireEvent(String eventIdentifier, boolean forceTransmission,\r
+            String... parameters) {\r
+\r
+        String[] event;\r
+\r
+        // filter events which are not listened on the server-side right here\r
+        boolean transmit = forceTransmission\r
+                || ((!(eventRegistrations == null)) && eventRegistrations\r
+                        .contains(eventIdentifier));\r
+\r
+        if (transmit) {\r
+            if (parameters != null) {\r
+                event = new String[parameters.length + 1];\r
+                event[0] = eventIdentifier;\r
+                for (int i = 0; i < parameters.length; i++) {\r
+                    event[i + 1] = parameters[i];\r
+                }\r
+            } else {\r
+                event = new String[] { eventIdentifier };\r
+            }\r
+\r
+            // transmit the event to the server-side\r
+            client.updateVariable(detail.getPid(), HANDLER_TRIGGER_VARIABLE,\r
+                    event, true);\r
+        }\r
+    }\r
+\r
+    void registerEventsFromUIDL(UIDL componentUIDL) {\r
+\r
+        // read out the request event handlers\r
+        if (componentUIDL.hasAttribute(HANDLER_LISTEN_ATTRIBUTE)) {\r
+            String[] requestedEvents = componentUIDL\r
+                    .getStringArrayAttribute(HANDLER_LISTEN_ATTRIBUTE);\r
+\r
+            // create the eventRegistrations list if necessary\r
+            if ((requestedEvents.length > 0) && (eventRegistrations == null)) {\r
+                eventRegistrations = new ArrayList<String>();\r
+            }\r
+\r
+            // parse the requested event handlers\r
+            for (String reqEvent : requestedEvents) {\r
+\r
+                if (!eventRegistrations.contains(reqEvent)) {\r
+                    eventRegistrations.add(reqEvent);\r
+                }\r
+\r
+            }\r
+\r
+        }\r
+\r
+    }\r
+\r
+}\r
index c05f1c06d32c099a0b7287a48fe9b9ca885aa557..159ecafa531b0008fc98d8202f0cc45f6ff9c50d 100644 (file)
@@ -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");
+    }
+
 }
index e2f217267a50877350306075f4700b96b8784e91..366476bef0e059a18e93187b1430178aa8fd00b7 100644 (file)
@@ -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);
+
+    }
+
 }
index 282136383d6bbeaabb85839e021391b57fbb26de..10d7fe4d02844b48e5501d920a6dda96421fca2a 100644 (file)
@@ -5,6 +5,12 @@ import java.util.Iterator;
 import java.util.Set;\r
 \r
 import com.google.gwt.core.client.JsArrayString;\r
+import com.google.gwt.dom.client.Node;\r
+import com.google.gwt.dom.client.NodeList;\r
+import com.google.gwt.event.dom.client.ClickEvent;\r
+import com.google.gwt.event.dom.client.ClickHandler;\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.Element;\r
 import com.google.gwt.user.client.ui.Widget;\r
 import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
 import com.vaadin.terminal.gwt.client.BrowserInfo;\r
@@ -18,7 +24,7 @@ import com.vaadin.terminal.gwt.client.RenderInformation.Size;
 import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;\r
 import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;\r
 \r
-public class VOrderedLayout extends CellBasedLayout {\r
+public class VOrderedLayout extends CellBasedLayout implements ClickHandler {\r
 \r
     public static final String CLASSNAME = "v-orderedlayout";\r
 \r
@@ -49,6 +55,7 @@ public class VOrderedLayout extends CellBasedLayout {
     public VOrderedLayout() {\r
         this(CLASSNAME, ORIENTATION_VERTICAL);\r
         allowOrientationUpdate = true;\r
+        addDomHandler(this, ClickEvent.getType());\r
     }\r
 \r
     protected VOrderedLayout(String className, int orientation) {\r
@@ -61,6 +68,7 @@ public class VOrderedLayout extends CellBasedLayout {
         STYLENAME_MARGIN_BOTTOM = className + "-margin-bottom";\r
         STYLENAME_MARGIN_LEFT = className + "-margin-left";\r
 \r
+        addDomHandler(this, ClickEvent.getType());\r
     }\r
 \r
     @Override\r
@@ -915,4 +923,51 @@ public class VOrderedLayout extends CellBasedLayout {
         }\r
     }\r
 \r
+    public void onClick(ClickEvent event) {\r
+        Integer childComponentId = getChildComponentId((Element) event\r
+                .getNativeEvent().getEventTarget().cast());\r
+        String childComponentString = childComponentId.toString();\r
+        client.getEventHandler(this).fireEvent("click", "left",\r
+                childComponentString);\r
+\r
+    }\r
+\r
+    /**\r
+     * Returns the index of the child component which contains "element".\r
+     * \r
+     * @param element\r
+     * @return\r
+     */\r
+    private int getChildComponentId(Element element) {\r
+        Element rootElement = getElement();\r
+        Element parent = DOM.getParent(element);\r
+        if (parent == null) {\r
+            return -1;\r
+        }\r
+        Element grandParent = DOM.getParent(parent);\r
+        if (grandParent == null) {\r
+            return -1;\r
+        }\r
+\r
+        while (grandParent != null && parent != rootElement) {\r
+            if (grandParent == rootElement) {\r
+                NodeList<Node> nodes = parent.getChildNodes();\r
+                int size = nodes.getLength();\r
+                for (int index = 0; index < size; index++) {\r
+                    if (nodes.getItem(index) == element) {\r
+                        return index;\r
+                    }\r
+                }\r
+\r
+                // This should not happen\r
+                return -1;\r
+            }\r
+\r
+            element = parent;\r
+            parent = grandParent;\r
+            grandParent = DOM.getParent(grandParent);\r
+        }\r
+        return -1;\r
+    }\r
+\r
 }\r
index ec4acf2e4da1baccd275e3892adc04ed64ad440e..608a7fd9ab7b23ecc4636a363b4ac19db3944957 100644 (file)
@@ -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");
+    }
 }
index 845a50e79389d78f1d1230ba871a21ac0e65e9df..860891f99fcabbef447757e386ef0fc7ddfd3003 100644 (file)
@@ -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 (file)
index 0000000..d74efba
--- /dev/null
@@ -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;
+    }
+}
index 2e6a0d6e19c47cc576891bd19ae89a6f38397a08..c624cf322440adfb6690a946b4ef9d918d93b120 100644 (file)
@@ -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
@@ -92,6 +95,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.
      */
@@ -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);
     }
 
     /**
index b43d155714aece255312ddae3d620d00df5c54a5..ed2f70d4f050e81f887de040333e03d9c6f2aa8d 100644 (file)
@@ -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));
+        }
+    }
 }
index ab7b7bb2ca7faaf91d293bf7a9398589a1c1da28..75d819f4b3b767873cb3b6b588eac3e37a1028ab 100644 (file)
@@ -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();
+        }
     }
 
     /**
index 3b20641c5fc79907fd62224b19b843e16bcede99..be60b744aa6bba0854ab49a68682009be9e07bd0 100644 (file)
@@ -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]));
+        }
+    }
 }
index d07e232b1aa14c648ccfcfb2ba5d54bc41cf6f7d..510a8051d735571064b3dec922ffff05e5e5a323 100644 (file)
@@ -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));
+        }
+    }
+
 }
index 03f1857386345f48ff5c3d993f24010c2e9aa4c6..2aaf697e85be10ccf0a54f0e20c385df36610c44 100644 (file)
@@ -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);
+
+    }
+
 }
index a7736172657e3cfa875ce58c74d816d00c4533b8..94c97849c2eb9dd559dc5330e829d32383acea48 100644 (file)
@@ -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);
+    }
+
 }