From 744019ccb09fac3580a4c55256eda2cbeb02f8f9 Mon Sep 17 00:00:00 2001 From: mdb Date: Thu, 21 Mar 2002 00:53:38 +0000 Subject: [PATCH] Added a default implementation of handleAction() which reflects over the methods of the controller looking for a handle method where is the action command. The arguments to the method are allowed to be either none, the source object that generated the action or the source object and the action argument (which requires that the action be a CommandEvent). git-svn-id: https://samskivert.googlecode.com/svn/trunk@680 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../java/com/samskivert/swing/Controller.java | 107 +++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) diff --git a/projects/samskivert/src/java/com/samskivert/swing/Controller.java b/projects/samskivert/src/java/com/samskivert/swing/Controller.java index 0a5a0588..c0cde96a 100644 --- a/projects/samskivert/src/java/com/samskivert/swing/Controller.java +++ b/projects/samskivert/src/java/com/samskivert/swing/Controller.java @@ -1,5 +1,5 @@ // -// $Id: Controller.java,v 1.10 2002/03/16 20:52:07 mdb Exp $ +// $Id: Controller.java,v 1.11 2002/03/21 00:53:38 mdb Exp $ // // samskivert library - useful routines for java programs // Copyright (C) 2001 Michael Bayne @@ -25,6 +25,8 @@ import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.lang.reflect.Method; + import javax.swing.JPanel; import javax.swing.event.AncestorEvent; @@ -144,12 +146,113 @@ public abstract class Controller * separate thread, for example via {@link * com.samskivert.swing.util.TaskMaster}. * + *

The default implementation of this method will reflect on the + * controller class, looking for a method that matches the name of the + * action event. A handler method must provide one of three + * signatures: one accepting no arguments, one including only a + * reference to the source object, or one including the source object + * and an extra argument (which can be used only if the action event + * is an instance of {@link CommandEvent}. For example: + * + *

+     * public void handleCancelClicked (Object source);
+     * public void handleTextEntered (Object source, String text);
+     * 
+ * + * The arguments to the method can be as specific or as generic as + * desired and reflection will perform the appropriate conversions at + * runtime. For example, a method could be declared like so: + * + *
+     * public void handleCancelClicked (JButton source);
+     * 
+ * + * One would have to ensure that the only action events generated with + * the action command string "Cancel" were generated by + * JButton instances if such a signature were used. + * * @param action The action to be processed. * * @return true if the action was processed, false if it should be * propagated up to the next controller in scope. */ - public abstract boolean handleAction (ActionEvent action); + public boolean handleAction (ActionEvent action) + { + Method method = null; + Object[] args = null; + + try { + // look for the appropriate method + String targetName = "handle" + action.getActionCommand(); + Method[] methods = getClass().getMethods(); + int mcount = methods.length; + + for (int i = 0; i < mcount; i++) { + if (methods[i].getName().equals(targetName)) { + // see if we can generate the appropriate arguments + args = generateArguments(methods[i], action); + // if we were able to, go ahead and use this method + if (args != null) { + method = methods[i]; + break; + } + } + } + + } catch (Exception e) { + Log.warning("Error searching for action handler method " + + "[controller=" + this + ", event=" + action + "]."); + return false; + } + + try { + if (method != null) { + method.invoke(this, args); + return true; + + } else { + return false; + } + + } catch (Exception e) { + Log.warning("Error invoking action handler [controller=" + this + + ", event=" + action + "]."); + // even though we choked, we still "handled" the action + return true; + } + } + + /** + * Used by {@link #handleAction} to generate arguments to the action + * handler method. + */ + protected Object[] generateArguments (Method method, ActionEvent action) + { + // figure out what sort of arguments are required by the method + Class[] atypes = method.getParameterTypes(); + + if (atypes == null || atypes.length == 0) { + return new Object[0]; + + } else if (atypes.length == 1) { + return new Object[] { action.getSource() }; + + } else if (atypes.length == 2) { + if (action instanceof CommandEvent) { + CommandEvent command = (CommandEvent)action; + return new Object[] { action.getSource(), + command.getArgument() }; + } + + Log.warning("Unable to map non-command event to " + + "handler method that requires extra " + + "argument [controller=" + this + + ", action=" + action + "]."); + } + + // we would have handled it, but we couldn't + return null; + } /** * Posts the specified action to the nearest controller in scope. The