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