Added a default implementation of handleAction() which reflects over the

methods of the controller looking for a handle<foo> method where <foo> 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
This commit is contained in:
mdb
2002-03-21 00:53:38 +00:00
parent 2e173531a7
commit 744019ccb0
@@ -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}.
*
* <p> 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:
*
* <pre>
* public void handleCancelClicked (Object source);
* public void handleTextEntered (Object source, String text);
* </pre>
*
* 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:
*
* <pre>
* public void handleCancelClicked (JButton source);
* </pre>
*
* One would have to ensure that the only action events generated with
* the action command string "Cancel" were generated by
* <code>JButton</code> 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