/* GenericEventListener.java Purpose: Description: History: Nov 21, 2007 6:10:38 PM , Created by robbiecheng Copyright (C) 2007 Potix Corporation. All Rights Reserved. {{IS_RIGHT This program is distributed under LGPL Version 2.1 in the hope that it will be useful, but WITHOUT ANY WARRANTY. }}IS_RIGHT */ package org.zkoss.zk.ui.event; import java.lang.reflect.Method; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.sys.ComponentsCtrl; /** * <p>An abstract event listener that you can extend and write intuitive onXxx event * handler methods; this class dispatch event to the implemented onXxx event handler methods * automatically. It also provides a convenient method {@link #bindComponent} that you * can bind a target event component to this event listener easily.</p> * <p>Following is an example. Whenever onOK or onCancel is posted (or sent) to this event * listener, it dispatch the control to the corresponding defined onOK() and onCancel() methods * respectively. Note how the bindComponent() method bind this event listener to the main * window.</p> *<pre><code> * <window id="main"> * ... * </window> * * <zscript><!-- both OK in zscript or a compiled Java class --> * public class MyEventListener extends GenericEventListener { * public void onOK(Event evt) { * //doOK! * //... * } * public void onCancel() { * //doCancel * //... * } * } * * new MyEventListener().bindComponent(main); * </zscript> * </code></pre> * @author robbiecheng * @since 3.0.1 * */ public abstract class GenericEventListener<T extends Event> implements SerializableEventListener<T> { /* Process the event by forwarding the invocation to * the corresponding method called onXxx. * * <p>You rarely need to override this method. * Rather, provide corresponding onXxx method to handle the event. * * <p>Since 3.0.8, this method treats ForwardEvent specially. If the * event argument passed into this listener is a ForwardEvent and the * defined onXxx method specifies a specific event class * as its parameter rather than generic Event or ForwardEvent class, then this * method will unwrap the ForwardEvent automatically * (see {@link org.zkoss.zk.ui.event.ForwardEvent#getOrigin()}) * and pass the original forwarded event to the onXxx method.</p> * * @see org.zkoss.zk.ui.event.EventListener#onEvent(org.zkoss.zk.ui.event.Event) */ public void onEvent(Event evt) throws Exception { final Object controller = getController(); final Method mtd = ComponentsCtrl.getEventMethod(controller.getClass(), evt.getName()); if (mtd != null) { if (mtd.getParameterTypes().length == 0) mtd.invoke(controller); else if (evt instanceof ForwardEvent) { //ForwardEvent final Class paramcls = mtd.getParameterTypes()[0]; //paramcls is ForwardEvent || Event if (ForwardEvent.class.isAssignableFrom(paramcls) || Event.class.equals(paramcls)) { mtd.invoke(controller, evt); } else { do { evt = ((ForwardEvent) evt).getOrigin(); } while (evt instanceof ForwardEvent); mtd.invoke(controller, evt); } } else mtd.invoke(controller, evt); } } /** * A convenient method that help you register this event listener * to the specified target component. * * <p>All public methods whose names start with "on" are considered * as event handlers and the corresponding event is listened. * For example, if the derived class has a method named onOK, * then the onOK event is listened and the onOK method is called * when the event is received. * * @param comp the target component to register this event listener. */ public void bindComponent(Component comp) { final Method[] metds = getController().getClass().getMethods(); for (int i = 0; i < metds.length; i++) { final String evtnm = metds[i].getName(); if (Events.isValid(evtnm)) comp.addEventListener(evtnm, this); } } /** * A convenient method that help you remove this event listener from the * specified target component. This is a counter method of the {@link #bindComponent(Component)} * method. * * @param comp the target component to remove this event listener. * @since 3.6.3 */ public void unbindComponent(Component comp) { final Method[] metds = getController().getClass().getMethods(); for (int i = 0; i < metds.length; i++) { final String evtnm = metds[i].getName(); if (Events.isValid(evtnm)) comp.removeEventListener(evtnm, this); } } /** * Returns the controller that really implement the * onXxx methods (default to this). It is intended to be overrode; * you shall not have to call this method directly. * @since 3.0.8 */ protected Object getController() { return this; } }