summaryrefslogtreecommitdiffstats
path: root/src/com/itmill/toolkit/event
diff options
context:
space:
mode:
authorJoonas Lehtinen <joonas.lehtinen@itmill.com>2006-11-01 09:11:32 +0000
committerJoonas Lehtinen <joonas.lehtinen@itmill.com>2006-11-01 09:11:32 +0000
commit13af8cba414fbb6f02ef458a86c5afcad70c5275 (patch)
tree959ccae1696d9c208124ec3982f166bca6c28f0a /src/com/itmill/toolkit/event
parentde5565e87dc08be0a577c663bb2e009d0838c872 (diff)
downloadvaadin-framework-13af8cba414fbb6f02ef458a86c5afcad70c5275.tar.gz
vaadin-framework-13af8cba414fbb6f02ef458a86c5afcad70c5275.zip
Refactoring: Enably -> IT Mill Toolkit
svn changeset:92/svn branch:toolkit
Diffstat (limited to 'src/com/itmill/toolkit/event')
-rw-r--r--src/com/itmill/toolkit/event/Action.java150
-rw-r--r--src/com/itmill/toolkit/event/EventRouter.java167
-rw-r--r--src/com/itmill/toolkit/event/ListenerMethod.java466
-rw-r--r--src/com/itmill/toolkit/event/MethodEventSource.java139
-rw-r--r--src/com/itmill/toolkit/event/package.html58
5 files changed, 980 insertions, 0 deletions
diff --git a/src/com/itmill/toolkit/event/Action.java b/src/com/itmill/toolkit/event/Action.java
new file mode 100644
index 0000000000..ce61c97022
--- /dev/null
+++ b/src/com/itmill/toolkit/event/Action.java
@@ -0,0 +1,150 @@
+/* *************************************************************************
+
+ IT Mill Toolkit
+
+ Development of Browser User Intarfaces Made Easy
+
+ Copyright (C) 2000-2006 IT Mill Ltd
+
+ *************************************************************************
+
+ This product is distributed under commercial license that can be found
+ from the product package on license/license.txt. Use of this product might
+ require purchasing a commercial license from IT Mill Ltd. For guidelines
+ on usage, see license/licensing-guidelines.html
+
+ *************************************************************************
+
+ For more information, contact:
+
+ IT Mill Ltd phone: +358 2 4802 7180
+ Ruukinkatu 2-4 fax: +358 2 4802 7181
+ 20540, Turku email: info@itmill.com
+ Finland company www: www.itmill.com
+
+ Primary source for information and releases: www.itmill.com
+
+ ********************************************************************** */
+
+package com.itmill.toolkit.event;
+
+import com.itmill.toolkit.terminal.*;
+
+/** Implements the MillStone action framework. This class contains
+ * subinterfaces for action handling and listing, and for action handler
+ * registrations and unregistration.
+ *
+ * @author IT Mill Ltd.
+ * @version @VERSION@
+ * @since 3.0
+ */
+public class Action {
+
+ /** Action title */
+ private String caption;
+
+ /** Action icon */
+ private Resource icon = null;
+
+ /** Constructs a new action with the given caption.
+ *
+ * @param caption caption for the new action.
+ */
+ public Action(String caption) {
+ this.caption = caption;
+ }
+
+ /** Constructs a new action with the given caption string and icon.
+ *
+ * @param caption caption for the new action.
+ * @param icon icon for the new action
+ */
+ public Action(String caption, Resource icon) {
+ this.caption = caption;
+ this.icon = icon;
+ }
+
+ /** Returns the action's caption.
+ *
+ * @return the action's caption as a <code>String</code>
+ */
+ public String getCaption() {
+ return caption;
+ }
+
+ /** Returns the action's icon.
+ *
+ * @return Icon
+ */
+ public Resource getIcon() {
+ return icon;
+ }
+
+ /** Interface implemented by classes who wish to handle actions.
+ * @author IT Mill Ltd.
+ * @version @VERSION@
+ * @since 3.0
+ */
+ public interface Handler {
+
+ /** Returns the list of actions applicable to this handler.
+ *
+ * @param target The target handler to list actions for. For item
+ * containers this is the item id.
+ * @param sender The party that would be sending the actions.
+ * Most of this is the action container.
+ */
+ public Action[] getActions(Object target, Object sender);
+
+ /** Handles an action for the given target. The handler method
+ * may just discard the action if it's not suitable.
+ *
+ * @param action The action to be handled
+ * @param sender The sender of the action. This is most often the
+ * action container.
+ * @param target The target of the <code>action</code>. For item
+ * containers this is the item id.
+ */
+ public void handleAction(Action action, Object sender, Object target);
+ }
+
+ /** Interface implemented by all components where actions can be
+ * registered. This means that the components lets others to register
+ * as action handlers to it. When the component receives an action
+ * targeting its contents it should loop all action handlers registered
+ * to it and let them hanle the action.
+ * @author IT Mill Ltd.
+ * @version @VERSION@
+ * @since 3.0
+ */
+ public interface Container {
+
+ /** Registers a new action handler for this container
+ *
+ * @param actionHandler the new handler to be added.
+ */
+ public void addActionHandler(Action.Handler actionHandler);
+
+ /** Remove a previously registered action handler for the contents
+ * of this container.
+ *
+ * @param actionHandler the handler to be removed
+ */
+ public void removeActionHandler(Action.Handler actionHandler);
+ }
+
+ /** Sets the caption.
+ * @param caption The caption to set
+ */
+ public void setCaption(String caption) {
+ this.caption = caption;
+ }
+
+ /** Sets the icon.
+ * @param icon The icon to set
+ */
+ public void setIcon(Resource icon) {
+ this.icon = icon;
+ }
+
+}
diff --git a/src/com/itmill/toolkit/event/EventRouter.java b/src/com/itmill/toolkit/event/EventRouter.java
new file mode 100644
index 0000000000..db83085300
--- /dev/null
+++ b/src/com/itmill/toolkit/event/EventRouter.java
@@ -0,0 +1,167 @@
+/* *************************************************************************
+
+ IT Mill Toolkit
+
+ Development of Browser User Intarfaces Made Easy
+
+ Copyright (C) 2000-2006 IT Mill Ltd
+
+ *************************************************************************
+
+ This product is distributed under commercial license that can be found
+ from the product package on license/license.txt. Use of this product might
+ require purchasing a commercial license from IT Mill Ltd. For guidelines
+ on usage, see license/licensing-guidelines.html
+
+ *************************************************************************
+
+ For more information, contact:
+
+ IT Mill Ltd phone: +358 2 4802 7180
+ Ruukinkatu 2-4 fax: +358 2 4802 7181
+ 20540, Turku email: info@itmill.com
+ Finland company www: www.itmill.com
+
+ Primary source for information and releases: www.itmill.com
+
+ ********************************************************************** */
+
+package com.itmill.toolkit.event;
+
+import java.util.EventObject;
+import java.util.LinkedList;
+import java.util.Iterator;
+import java.lang.reflect.Method;
+
+/** Event router class implementing the MillStone inheritable event
+ * listening model. For more information on the event model see the
+ * {@link com.itmill.toolkit.event package documentation}.
+ *
+ * @author IT Mill Ltd.
+ * @version @VERSION@
+ * @since 3.0
+ */
+public class EventRouter implements MethodEventSource {
+
+ /** List of registered listeners. */
+ private LinkedList listenerList = null;
+
+ /* Registers a new listener with the specified activation method to
+ * listen events generated by this component.
+ * Don't add a JavaDoc comment here, we use the default documentation
+ * from implemented interface.
+ */
+ public void addListener(Class eventType, Object object, Method method) {
+
+ if (listenerList == null)
+ listenerList = new LinkedList();
+
+ listenerList.add(new ListenerMethod(eventType, object, method));
+ }
+
+ /* Registers a new listener with the specified named activation method
+ * to listen events generated by this component.
+ * Don't add a JavaDoc comment here, we use the default documentation
+ * from implemented interface.
+ */
+ public void addListener(Class eventType, Object object, String methodName) {
+
+ if (listenerList == null)
+ listenerList = new LinkedList();
+
+ listenerList.add(new ListenerMethod(eventType, object, methodName));
+ }
+
+ /* Removes all registered listeners matching the given parameters.
+ * Don't add a JavaDoc comment here, we use the default documentation
+ * from implemented interface.
+ */
+ public void removeListener(Class eventType, Object target) {
+
+ if (listenerList != null) {
+ Iterator i = listenerList.iterator();
+ while (i.hasNext()) {
+ try {
+ ListenerMethod lm = (ListenerMethod) i.next();
+ if (lm.matches(eventType,target))
+ i.remove();
+ } catch (java.lang.ClassCastException e) {
+ // Class cast exceptions are ignored
+ }
+ }
+ }
+ }
+
+ /* Removes the event listener methods matching the given given
+ * paramaters.
+ * Don't add a JavaDoc comment here, we use the default documentation
+ * from implemented interface.
+ */
+ public void removeListener(Class eventType, Object target, Method method) {
+
+ if (listenerList != null) {
+ Iterator i = listenerList.iterator();
+ while (i.hasNext()) {
+ try {
+ ListenerMethod lm = (ListenerMethod) i.next();
+ if (lm.matches(eventType,target,method))
+ i.remove();
+ } catch (java.lang.ClassCastException e) {
+ // Class cast exceptions are ignored
+ }
+ }
+ }
+ }
+
+ /* Removes the event listener method matching the given given
+ * paramaters.
+ * Don't add a JavaDoc comment here, we use the default documentation
+ * from implemented interface.
+ */
+ public void removeListener(Class eventType, Object target, String methodName) {
+
+ // Find the correct method
+ Method[] methods = target.getClass().getMethods();
+ Method method = null;
+ for (int i=0; i<methods.length; i++)
+ if (methods[i].getName().equals(methodName))
+ method = methods[i];
+ if (method == null) throw new IllegalArgumentException();
+
+ // Remove the listeners
+ if (listenerList != null) {
+ Iterator i = listenerList.iterator();
+ while (i.hasNext()) {
+ try {
+ ListenerMethod lm = (ListenerMethod) i.next();
+ if (lm.matches(eventType,target,method))
+ i.remove();
+ } catch (java.lang.ClassCastException e) {
+ // Class cast exceptions are ignored
+ }
+ }
+ }
+ }
+
+ /** Remove all listeners from event router */
+ public void removeAllListeners() {
+ listenerList = null;
+ }
+
+ /** Send an event to all registered listeners. The listeners will decide
+ * if the activation method should be called or not.
+ *
+ * @param event Event to be sent to all listeners
+ */
+ public void fireEvent(EventObject event) {
+
+ // It is not necessary to send any events if there are no listeners
+ if (listenerList != null) {
+
+ // Send the event to all listeners. The listeners themselves
+ // will filter out unwanted events.
+ Iterator i = new LinkedList(listenerList).iterator();
+ while(i.hasNext()) ((ListenerMethod)i.next()).receiveEvent(event);
+ }
+ }
+}
diff --git a/src/com/itmill/toolkit/event/ListenerMethod.java b/src/com/itmill/toolkit/event/ListenerMethod.java
new file mode 100644
index 0000000000..0d899e420c
--- /dev/null
+++ b/src/com/itmill/toolkit/event/ListenerMethod.java
@@ -0,0 +1,466 @@
+/* *************************************************************************
+
+ IT Mill Toolkit
+
+ Development of Browser User Intarfaces Made Easy
+
+ Copyright (C) 2000-2006 IT Mill Ltd
+
+ *************************************************************************
+
+ This product is distributed under commercial license that can be found
+ from the product package on license/license.txt. Use of this product might
+ require purchasing a commercial license from IT Mill Ltd. For guidelines
+ on usage, see license/licensing-guidelines.html
+
+ *************************************************************************
+
+ For more information, contact:
+
+ IT Mill Ltd phone: +358 2 4802 7180
+ Ruukinkatu 2-4 fax: +358 2 4802 7181
+ 20540, Turku email: info@itmill.com
+ Finland company www: www.itmill.com
+
+ Primary source for information and releases: www.itmill.com
+
+ ********************************************************************** */
+
+package com.itmill.toolkit.event;
+
+import java.util.EventListener;
+import java.util.EventObject;
+import java.lang.reflect.Method;
+
+/** <p>One registered event listener. This class contains the listener
+ * object reference, listened event type, the trigger method to call when
+ * the event fires, and the optional argument list to pass to the method and
+ * the index of the argument to replace with the event object. It provides
+ * several constructors that allow omission of the optional arguments, and
+ * giving the listener method directly, or having the constructor to reflect
+ * it using merely the name of the method.</p>
+ *
+ * <p>It should be pointed out that the method
+ * {@link #receiveEvent(EventObject event)} is the one that filters out the
+ * events that do not match with the given event type and thus do not result
+ * in calling of the trigger method.</p>
+ *
+ * @author IT Mill Ltd.
+ * @version @VERSION@
+ * @since 3.0
+ */
+public class ListenerMethod implements EventListener {
+
+ /** Type of the event that should trigger this listener. Also the
+ * subclasses of this class are accepted to trigger the listener.
+ */
+ private Class eventType;
+
+ /** The object containing the trigger method, */
+ private Object object;
+
+ /** The trigger method to call when an event passing the given criteria
+ * fires.
+ */
+ private Method method;
+
+ /** Optional argument set to pass to the trigger method. */
+ private Object[] arguments;
+
+ /** Optional index to <code>arguments</code> that point out which one
+ * should be replaced with the triggering event object and thus be
+ * passed to the trigger method.
+ */
+ private int eventArgumentIndex;
+
+ /** <p>Constructs a new event listener from a trigger method, it's
+ * arguments and the argument index specifying which one is replaced
+ * with the event object when the trigger method is called.</p>
+ *
+ * <p>This constructor gets the trigger method as a parameter so it
+ * does not need to reflect to find it out.</p>
+ *
+ * @param eventType The event type that is listener listens to. All
+ * events of this kind (or its subclasses) result in calling the trigger
+ * method.
+ * @param object The object instance that contains the trigger method
+ * @param method the trigger method
+ * @param arguments arguments to be passed to the trigger method
+ * @param eventArgumentIndex An index to the argument list. This index
+ * points out the argument that is replaced with the event object before
+ * the argument set is passed to the trigger method. If
+ * <code>eventArgumentIndex</code> is negative, the triggering event
+ * object will not be passed to the trigger method, though it is still
+ * called.
+ * @throws java.lang.IllegalArgumentException if <code>method</code>
+ * is not a member of <code>object</code>.
+ */
+ public ListenerMethod(
+ Class eventType,
+ Object object,
+ Method method,
+ Object[] arguments,
+ int eventArgumentIndex)
+ throws java.lang.IllegalArgumentException {
+
+ // Check that the object is of correct type
+ if (!method.getDeclaringClass().isAssignableFrom(object.getClass()))
+ throw new java.lang.IllegalArgumentException();
+
+ // Check that the event argument is null
+ if (eventArgumentIndex >= 0 && arguments[eventArgumentIndex] != null)
+ throw new java.lang.IllegalArgumentException();
+
+ // Check the event type is supported by the method
+ if (eventArgumentIndex >= 0
+ && !method.getParameterTypes()[eventArgumentIndex].isAssignableFrom(
+ eventType))
+ throw new java.lang.IllegalArgumentException();
+
+ this.eventType = eventType;
+ this.object = object;
+ this.method = method;
+ this.arguments = arguments;
+ this.eventArgumentIndex = eventArgumentIndex;
+ }
+
+ /** <p>Constructs a new event listener from a trigger method name, it's
+ * arguments and the argument index specifying which one is replaced
+ * with the event object. The actual trigger method is reflected from
+ * <code>object</code>, and
+ * <code>java.lang.IllegalArgumentException</code> is thrown unless
+ * exactly one match is found.
+ *
+ * @param eventType The event type that is listener listens to. All
+ * events of this kind (or its subclasses) result in calling the trigger
+ * method.
+ * @param object The object instance that contains the trigger method
+ * @param methodName The name of the trigger method. If
+ * <code>object</code> does not contain the method or it contains more
+ * than one matching methods
+ * <code>java.lang.IllegalArgumentException</code> is thrown.
+ * @param arguments arguments to be passed to the trigger method
+ * @param eventArgumentIndex An index to the argument list. This index
+ * points out the argument that is replaced with the event object before
+ * the argument set is passed to the trigger method. If
+ * <code>eventArgumentIndex</code> is negative, the triggering event
+ * object will not be passed to the trigger method, though it is still
+ * called.
+ * @throws java.lang.IllegalArgumentException unless exactly one match
+ * <code>methodName</code> is found in <code>object</code>.
+ */
+ public ListenerMethod(
+ Class eventType,
+ Object object,
+ String methodName,
+ Object[] arguments,
+ int eventArgumentIndex)
+ throws java.lang.IllegalArgumentException {
+
+ // Find the correct method
+ Method[] methods = object.getClass().getMethods();
+ Method method = null;
+ for (int i = 0; i < methods.length; i++)
+ if (methods[i].getName().equals(methodName))
+ method = methods[i];
+ if (method == null)
+ throw new IllegalArgumentException();
+
+ // Check that the event argument is null
+ if (eventArgumentIndex >= 0 && arguments[eventArgumentIndex] != null)
+ throw new java.lang.IllegalArgumentException();
+
+ // Check the event type is supported by the method
+ if (eventArgumentIndex >= 0
+ && !method.getParameterTypes()[eventArgumentIndex].isAssignableFrom(
+ eventType))
+ throw new java.lang.IllegalArgumentException();
+
+ this.eventType = eventType;
+ this.object = object;
+ this.method = method;
+ this.arguments = arguments;
+ this.eventArgumentIndex = eventArgumentIndex;
+ }
+
+ /** <p>Constructs a new event listener from the trigger method and it's
+ * arguments. Since the the index to the replaced parameter is not
+ * specified the event triggering this listener will not be passed to
+ * the trigger method.</p>
+ *
+ * <p>This constructor gets the trigger method as a parameter so it
+ * does not need to reflect to find it out.</p>
+ *
+ * @param eventType The event type that is listener listens to. All
+ * events of this kind (or its subclasses) result in calling the trigger
+ * method.
+ * @param object The object instance that contains the trigger method
+ * @param method the trigger method
+ * @param arguments arguments to be passed to the trigger method
+ * @throws java.lang.IllegalArgumentException if <code>method</code>
+ * is not a member of <code>object</code>.
+ */
+ public ListenerMethod(
+ Class eventType,
+ Object object,
+ Method method,
+ Object[] arguments)
+ throws java.lang.IllegalArgumentException {
+
+ // Check that the object is of correct type
+ if (!method.getDeclaringClass().isAssignableFrom(object.getClass()))
+ throw new java.lang.IllegalArgumentException();
+
+ this.eventType = eventType;
+ this.object = object;
+ this.method = method;
+ this.arguments = arguments;
+ this.eventArgumentIndex = -1;
+ }
+
+ /** <p>Constructs a new event listener from a trigger method name and
+ * it's arguments. Since the the index to the replaced parameter is not
+ * specified the event triggering this listener will not be passed to
+ * the trigger method.</p>
+ *
+ * <p>The actual trigger method is reflected from <code>object</code>,
+ * and <code>java.lang.IllegalArgumentException</code> is thrown unless
+ * exactly one match is found.</p>
+ *
+ * @param eventType The event type that is listener listens to. All
+ * events of this kind (or its subclasses) result in calling the trigger
+ * method.
+ * @param object The object instance that contains the trigger method
+ * @param methodName The name of the trigger method. If
+ * <code>object</code> does not contain the method or it contains more
+ * than one matching methods
+ * <code>java.lang.IllegalArgumentException</code> is thrown.
+ * @param arguments arguments to be passed to the trigger method
+ * @throws java.lang.IllegalArgumentException unless exactly one match
+ * <code>methodName</code> is found in <code>object</code>.
+ */
+ public ListenerMethod(
+ Class eventType,
+ Object object,
+ String methodName,
+ Object[] arguments)
+ throws java.lang.IllegalArgumentException {
+
+ // Find the correct method
+ Method[] methods = object.getClass().getMethods();
+ Method method = null;
+ for (int i = 0; i < methods.length; i++)
+ if (methods[i].getName().equals(methodName))
+ method = methods[i];
+ if (method == null)
+ throw new IllegalArgumentException();
+
+ this.eventType = eventType;
+ this.object = object;
+ this.method = method;
+ this.arguments = arguments;
+ this.eventArgumentIndex = -1;
+ }
+
+ /** <p>Constructs a new event listener from a trigger method. Since the
+ * argument list is unspecified no parameters are passed to the trigger
+ * method when the listener is triggered.</p>
+ *
+ * <p>This constructor gets the trigger method as a parameter so it
+ * does not need to reflect to find it out.</p>
+ *
+ * @param eventType The event type that is listener listens to. All
+ * events of this kind (or its subclasses) result in calling the trigger
+ * method.
+ * @param object The object instance that contains the trigger method
+ * @param method the trigger method
+ * @throws java.lang.IllegalArgumentException if <code>method</code>
+ * is not a member of <code>object</code>.
+ */
+ public ListenerMethod(Class eventType, Object object, Method method)
+ throws java.lang.IllegalArgumentException {
+
+ // Check that the object is of correct type
+ if (!method.getDeclaringClass().isAssignableFrom(object.getClass()))
+ throw new java.lang.IllegalArgumentException();
+
+ this.eventType = eventType;
+ this.object = object;
+ this.method = method;
+ this.eventArgumentIndex = -1;
+
+ Class[] params = method.getParameterTypes();
+
+ if (params.length == 0)
+ this.arguments = new Object[0];
+ else if (params.length == 1 && params[0].isAssignableFrom(eventType)) {
+ this.arguments = new Object[] { null };
+ this.eventArgumentIndex = 0;
+ } else
+ throw new IllegalArgumentException();
+ }
+
+ /** <p>Constructs a new event listener from a trigger method name. Since
+ * the argument list is unspecified no parameters are passed to the
+ * trigger method when the listener is triggered.</p>
+ *
+ * <p>The actual trigger method is reflected from <code>object</code>,
+ * and <code>java.lang.IllegalArgumentException</code> is thrown unless
+ * exactly one match is found.</p>
+ *
+ * @param eventType The event type that is listener listens to. All
+ * events of this kind (or its subclasses) result in calling the trigger
+ * method.
+ * @param object The object instance that contains the trigger method
+ * @param methodName The name of the trigger method. If
+ * <code>object</code> does not contain the method or it contains more
+ * than one matching methods
+ * <code>java.lang.IllegalArgumentException</code> is thrown.
+ * @throws java.lang.IllegalArgumentException unless exactly one match
+ * <code>methodName</code> is found in <code>object</code>.
+ */
+ public ListenerMethod(Class eventType, Object object, String methodName)
+ throws java.lang.IllegalArgumentException {
+
+ // Find the correct method
+ Method[] methods = object.getClass().getMethods();
+ Method method = null;
+ for (int i = 0; i < methods.length; i++)
+ if (methods[i].getName().equals(methodName))
+ method = methods[i];
+ if (method == null)
+ throw new IllegalArgumentException();
+
+ this.eventType = eventType;
+ this.object = object;
+ this.method = method;
+ this.eventArgumentIndex = -1;
+
+ Class[] params = method.getParameterTypes();
+
+ if (params.length == 0)
+ this.arguments = new Object[0];
+ else if (params.length == 1 && params[0].isAssignableFrom(eventType)) {
+ this.arguments = new Object[] { null };
+ this.eventArgumentIndex = 0;
+ } else
+ throw new IllegalArgumentException();
+ }
+
+ /** Receives one event from the EventRouter and calls the trigger
+ * method if it matches with the criteria defined for the listener.
+ * Only the events of the same or subclass of the specified event
+ * class result in the trigger method to be called.
+ *
+ * @param event The fired event. Unless the trigger method's
+ * argument list and the index to the to be replaced argument is
+ * specified, this event will not be passed to the trigger method.
+ */
+ public void receiveEvent(EventObject event) {
+
+ // Only send events supported by the method
+ if (eventType.isAssignableFrom(event.getClass())) {
+ try {
+ if (eventArgumentIndex >= 0) {
+ if (eventArgumentIndex == 0 && arguments.length == 1)
+ method.invoke(object, new Object[] { event });
+ else {
+ Object[] arg = new Object[arguments.length];
+ for (int i = 0; i < arg.length; i++)
+ arg[i] = arguments[i];
+ arg[eventArgumentIndex] = event;
+ method.invoke(object, arg);
+ }
+ } else
+ method.invoke(object, arguments);
+
+ } catch (java.lang.IllegalAccessException e) {
+ // This should never happen
+ throw new java.lang.RuntimeException(
+ "Internal error - please report: " + e.toString());
+ } catch (java.lang.reflect.InvocationTargetException e) {
+ // This should never happen
+ throw new MethodException(
+ "Invocation if method " + method + " failed.",
+ e.getTargetException());
+ }
+ }
+ }
+
+ /** Checks if the given object and event match with the ones stored
+ * in this listener.
+ *
+ * @param target object to be matched against the object stored by this
+ * listener
+ * @param eventType type to be tested for equality against the type
+ * stored by this listener
+ * @return <code>true</code> if <code>target</code> is the same object
+ * as the one stored in this object and <code>eventType</code> equals
+ * the event type stored in this object.
+ */
+ public boolean matches(Class eventType, Object target) {
+ return (target == object) && (eventType.equals(this.eventType));
+ }
+
+ /** Checks if the given object, event and method match with the ones
+ * stored in this listener.
+ *
+ * @param target object to be matched against the object stored by this
+ * listener
+ * @param eventType type to be tested for equality against the type
+ * stored by this listener
+ * @param method method to be tested for equality against the method
+ * stored by this listener
+ * @return <code>true</code> if <code>target</code> is the same object
+ * as the one stored in this object, <code>eventType</code> equals
+ * with the event type stored in this object and <code>method</code>
+ * equals with the method stored in this object
+ */
+ public boolean matches(Class eventType, Object target, Method method) {
+ return (target == object)
+ && (eventType.equals(this.eventType) && method.equals(this.method));
+ }
+
+ /** Exception that wraps an exception thrown by an invoked method.
+ * When ListenerMethod invokes the target method, it may throw arbitrary
+ * exception. The original exception is wrapped into MethodException instance and
+ * rethrown by the ListenerMethod.
+ * @author IT Mill Ltd.
+ * @version @VERSION@
+ * @since 3.0
+ * */
+ public class MethodException extends RuntimeException {
+
+ /**
+ * Serial generated by eclipse.
+ */
+ private static final long serialVersionUID = 3257005445242894135L;
+
+ private Throwable cause;
+ private String message;
+
+ private MethodException(String message, Throwable cause) {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause() {
+ return this.cause;
+ }
+
+ /**
+ * @see java.lang.Throwable#getMessage()
+ */
+ public String getMessage() {
+ return message;
+ }
+
+ public String toString() {
+ String msg = super.toString();
+ if (cause != null)
+ msg += "\nCause: " + cause.toString();
+ return msg;
+ }
+
+ }
+}
diff --git a/src/com/itmill/toolkit/event/MethodEventSource.java b/src/com/itmill/toolkit/event/MethodEventSource.java
new file mode 100644
index 0000000000..fa994ee9b7
--- /dev/null
+++ b/src/com/itmill/toolkit/event/MethodEventSource.java
@@ -0,0 +1,139 @@
+/* *************************************************************************
+
+ IT Mill Toolkit
+
+ Development of Browser User Intarfaces Made Easy
+
+ Copyright (C) 2000-2006 IT Mill Ltd
+
+ *************************************************************************
+
+ This product is distributed under commercial license that can be found
+ from the product package on license/license.txt. Use of this product might
+ require purchasing a commercial license from IT Mill Ltd. For guidelines
+ on usage, see license/licensing-guidelines.html
+
+ *************************************************************************
+
+ For more information, contact:
+
+ IT Mill Ltd phone: +358 2 4802 7180
+ Ruukinkatu 2-4 fax: +358 2 4802 7181
+ 20540, Turku email: info@itmill.com
+ Finland company www: www.itmill.com
+
+ Primary source for information and releases: www.itmill.com
+
+ ********************************************************************** */
+
+package com.itmill.toolkit.event;
+
+import java.lang.reflect.Method;
+
+/** <p>Interface for classes supporting registeration of methods as event
+ * receivers.</p>
+ *
+ * <p>For more information on the MillStone inheritable event mechanism
+ * see the
+ * {@link com.itmill.toolkit.event com.itmill.toolkit.event package documentation}.</p>
+ *
+ * @author IT Mill Ltd.
+ * @version @VERSION@
+ * @since 3.0
+ */
+public interface MethodEventSource {
+
+ /** <p>Registers a new event 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>For more information on the MillStone inheritable event mechanism
+ * see the
+ * {@link com.itmill.toolkit.event com.itmill.toolkit.event package documentation}.</p>
+ *
+ * @param eventType 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
+ * @throws java.lang.IllegalArgumentException unless <code>method</code>
+ * has exactly one match in <code>object</code>
+ */
+ public void addListener(Class eventType, Object object, Method method);
+
+ /** <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 version of <code>addListener</code> gets the name of the
+ * activation method as a parameter. The actual method is reflected from
+ * <code>object</code>, and unless exactly one match is found,
+ * <code>java.lang.IllegalArgumentException</code> is thrown.</p>
+ *
+ * <p>For more information on the MillStone inheritable event mechanism
+ * see the
+ * {@link com.itmill.toolkit.event com.itmill.toolkit.event package documentation}.</p>
+ *
+ * @param eventType 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 methodName the name of the activation method
+ * @throws java.lang.IllegalArgumentException unless <code>method</code>
+ * has exactly one match in <code>object</code>
+ */
+ public void addListener(Class eventType, Object object, String methodName);
+
+ /** 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>For more information on the MillStone inheritable event mechanism
+ * see the
+ * {@link com.itmill.toolkit.event com.itmill.toolkit.event package documentation}.</p>
+ *
+ * @param eventType 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
+ */
+ public void removeListener(Class eventType, Object target);
+
+ /** 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>For more information on the MillStone inheritable event mechanism
+ * see the
+ * {@link com.itmill.toolkit.event com.itmill.toolkit.event package documentation}.</p>
+ *
+ * @param eventType 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>
+ */
+ public void removeListener(Class eventType, Object target, Method method);
+
+ /** <p>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>
+ *
+ * <p>This version of <code>removeListener</code> gets the name of the
+ * activation method as a parameter. The actual method is reflected from
+ * <code>target</code>, and unless exactly one match is found,
+ * <code>java.lang.IllegalArgumentException</code> is thrown.</p>
+ *
+ * <p>For more information on the MillStone inheritable event mechanism
+ * see the
+ * {@link com.itmill.toolkit.event com.itmill.toolkit.event package documentation}.</p>
+ *
+ * @param eventType 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 methodName name of the method owned by <code>target</code>
+ * that's registered to listen to events of type <code>eventType</code>
+ */
+ public void removeListener(Class eventType, Object target, String methodName);
+}
diff --git a/src/com/itmill/toolkit/event/package.html b/src/com/itmill/toolkit/event/package.html
new file mode 100644
index 0000000000..bd1faf7e89
--- /dev/null
+++ b/src/com/itmill/toolkit/event/package.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+</head>
+
+<body bgcolor="white">
+
+<!-- Package summary here -->
+
+<p>Provides classes and interfaces for the MillStone inheritable event
+model. The model supports inheritable events and a flexible way of
+registering and unregistering event listeners. It's a fundamental building
+block of the MillStone framework, and as it is included in
+{@link org.millstone.base.ui.AbstractComponent}, all UI components
+automatically support it.</p>
+
+<h2>Package Specification</h2>
+
+<p>The core of the MillStone event model is the inheritable event class
+hierarchy, and the {@link org.millstone.base.event.EventRouter EventRouter}
+which provide a simple, ubiquitous mechanism to transport events to all
+interested parties.</p>
+
+<p>The power of the event inheritance arises from the possibility of
+receiving not only the events of the registered type, <i>but also the
+ones which are inherited from it</i>. For example, let's assume that there
+are the events <code>GeneralEvent</code> and <code>SpecializedEvent</code>
+so that the latter inherits the former. Furthermore we have an object
+<code>A</code> which registers to receive <code>GeneralEvent</code> type
+events from the object <code>B</code>. <code>A</code> would of course
+receive all <code>GeneralEvent</code>s generated by <code>B</code>, but in
+addition to this, <code>A</code> would also receive all
+<code>SpecializedEvent</code>s generated by <code>B</code>. However, if
+<code>B</code> generates some other events that do not have
+<code>GeneralEvent</code> as an ancestor, <code>A</code> would not receive
+them unless it registers to listen for them, too.</p>
+
+<p>The interface to attaching and detaching listeners to and from an object
+works with methods. One specifies the event that should trigger the listener,
+the trigger method that should be called when a suitable event occurs and the
+object owning the method. From these a new listener is constructed and added
+to the event router of the specified component.</p>
+
+<p>The interface is defined in
+{@link org.millstone.base.event.MethodEventSource MethodEventSource}, and a
+straightforward implementation of it is defined in
+{@link org.millstone.base.event.EventRouter EventRouter} which also includes
+a method to actually fire the events.</p>
+
+<p>All fired events are passed to all registered listeners, which are of
+type {@link org.millstone.base.event.ListenerMethod ListenerMethod}. The
+listener then checks if the event type matches with the specified event
+type and calls the specified trigger method if it does.</p>
+
+<!-- Put @see and @since tags down here. -->
+
+</body>
+</html>