diff options
author | Artur Signell <artur.signell@itmill.com> | 2009-11-20 12:33:35 +0000 |
---|---|---|
committer | Artur Signell <artur.signell@itmill.com> | 2009-11-20 12:33:35 +0000 |
commit | ab4e63b78dd81ccc99d81d3fc4cb9f9455d5fce6 (patch) | |
tree | b3c94666ed2ba1896a04e3eca1a3c71d256fb611 /src | |
parent | f8ca6621b3fba6e01aaa3088a391f1a2b624b5b9 (diff) | |
download | vaadin-framework-ab4e63b78dd81ccc99d81d3fc4cb9f9455d5fce6.tar.gz vaadin-framework-ab4e63b78dd81ccc99d81d3fc4cb9f9455d5fce6.zip |
Initial commit for framework enhancement for #3234
svn changeset:9947/svn branch:event-framework-3234
Diffstat (limited to 'src')
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); + } + } |