Favor dynamic controller method dispatch with an unadulterated method name. We

used to prepend "handle" to an action and then look up the method (which we
still support) but now we also check for a method just named directly after the
action.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@1890 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2006-08-24 18:20:27 +00:00
parent 6bb4640f0a
commit e00883856e
+62 -66
View File
@@ -37,35 +37,32 @@ import com.samskivert.Log;
import com.samskivert.swing.event.CommandEvent; import com.samskivert.swing.event.CommandEvent;
/** /**
* The controller class provides a basis for the separation of user * The controller class provides a basis for the separation of user interface
* interface code into display code and control code. The display code * code into display code and control code. The display code lives in a panel
* lives in a panel class (<code>javax.swing.JPanel</code> or something * class (<code>javax.swing.JPanel</code> or something conceptually similar)
* conceptually similar) and the control code lives in an associated * and the control code lives in an associated controller class.
* controller class.
* *
* <p> The controller philosophy is thus: The panel class (and its UI * <p> The controller philosophy is thus: The panel class (and its UI
* components) convert basic user interface actions into higher level * components) convert basic user interface actions into higher level actions
* actions that more cleanly encapsulate the action desired by the user * that more cleanly encapsulate the action desired by the user and they pass
* and they pass those actions on to their controller. The controller then * those actions on to their controller. The controller then performs abstract
* performs abstract processing based on the users desires and the * processing based on the users desires and the changing state of the
* changing state of the application and calls back to the panel to affect * application and calls back to the panel to affect changes to the display.
* changes to the display.
* *
* <p> Controllers also support the notion of scope. When a panel wishes * <p> Controllers also support the notion of scope. When a panel wishes to
* to post an action, it doesn't do it directly to the controller. Instead * post an action, it doesn't do it directly to the controller. Instead it does
* it does it using a controller utility function called {@link * it using a controller utility function called {@link #postAction}, which
* #postAction}, which searches up the user interface hierarchy looking * searches up the user interface hierarchy looking for a component that
* for a component that implements {@link * implements {@link ControllerProvider} which it will use to obtain the
* com.samskivert.swing.ControllerProvider} which it will use to obtain * controller "in scope" for that component. That controller is requested to
* the controller "in scope" for that component. That controller is * handle the action, but if it cannot handle the action, the next controller
* requested to handle the action, but if it cannot handle the action, the * up the chain is located and requested to process the action.
* next controller up the chain is located and requested to process the *
* action. In this manner, a hierarchy of controllers (often just two: one * <p> In this manner, a hierarchy of controllers (often just two: one
* application wide and one for whatever particular mode the application * application wide and one for whatever particular mode the application is in
* is in at the moment) can provide a set of services that are available * at the moment) can provide a set of services that are available to all user
* to all user interface elements in the entire application and in a way * interface elements in the entire application and in a way that doesn't
* that doesn't require tight connectedness between the UI elements and * require tight connectedness between the UI elements and the controllers.
* the controllers.
*/ */
public abstract class Controller public abstract class Controller
implements ActionListener implements ActionListener
@@ -150,49 +147,48 @@ public abstract class Controller
} }
/** /**
* Instructs this controller to process this action event. When an * Instructs this controller to process this action event. When an action
* action is posted by a user interface element, it will be posted to * is posted by a user interface element, it will be posted to the
* the controller in closest scope for that element. If that * controller in closest scope for that element. If that controller handles
* controller handles the event, it should return true from this * the event, it should return true from this method to indicate that
* method to indicate that processing should stop. If it cannot handle * processing should stop. If it cannot handle the event, it can return
* the event, it can return false to indicate that the event should be * false to indicate that the event should be propagated to the next
* propagated to the next controller up the chain. * controller up the chain.
* *
* <p> This method will be called on the AWT thread, so the controller * <p> This method will be called on the AWT thread, so the controller can
* can safely manipulate user interface components while handling an * safely manipulate user interface components while handling an action.
* action. However, this means that action handling cannot block and * However, this means that action handling cannot block and should not
* should not take an undue amount of time. If the controller needs to * take an undue amount of time. If the controller needs to perform
* perform complicated, lengthy processing it should do so with a * complicated, lengthy processing it should do so with a separate thread,
* separate thread, for example via {@link * for example via {@link com.samskivert.swing.util.TaskMaster}.
* com.samskivert.swing.util.TaskMaster}.
* *
* <p> The default implementation of this method will reflect on the * <p> The default implementation of this method will reflect on the
* controller class, looking for a method that matches the name of the * controller class, looking for a method that matches the name of the
* action event. For example, if the action was "Exit" a method named * action event. For example, if the action was "exit" a method named
* "handleExit" would be sought. A handler method must provide one of * "exit" would be sought. A handler method must provide one of three
* three signatures: one accepting no arguments, one including only a * signatures: one accepting no arguments, one including only a reference
* reference to the source object, or one including the source object * to the source object, or one including the source object and an extra
* and an extra argument (which can be used only if the action event * argument (which can be used only if the action event is an instance of
* is an instance of {@link CommandEvent}). For example: * {@link CommandEvent}). For example:
* *
* <pre> * <pre>
* public void handleCancelClicked (Object source); * public void cancelClicked (Object source);
* public void handleTextEntered (Object source, String text); * public void textEntered (Object source, String text);
* </pre> * </pre>
* *
* The arguments to the method can be as specific or as generic as * The arguments to the method can be as specific or as generic as desired
* desired and reflection will perform the appropriate conversions at * and reflection will perform the appropriate conversions at runtime. For
* runtime. For example, a method could be declared like so: * example, a method could be declared like so:
* *
* <pre> * <pre>
* public void handleCancelClicked (JButton source); * public void cancelClicked (JButton source);
* </pre> * </pre>
* *
* One would have to ensure that the only action events generated with * One would have to ensure that the only action events generated with the
* the action command string "CancelClicked" were generated by * action command string "cancelClicked" were generated by JButton
* <code>JButton</code> instances if such a signature were used. * instances if such a signature were used.
* *
* @param action The action to be processed. * @param action the action to be processed.
* *
* @return true if the action was processed, false if it should be * @return true if the action was processed, false if it should be
* propagated up to the next controller in scope. * propagated up to the next controller in scope.
@@ -217,12 +213,13 @@ public abstract class Controller
try { try {
// look for the appropriate method // look for the appropriate method
String targetName = "handle" + action;
Method[] methods = getClass().getMethods(); Method[] methods = getClass().getMethods();
int mcount = methods.length; int mcount = methods.length;
for (int i = 0; i < mcount; i++) { for (int i = 0; i < mcount; i++) {
if (methods[i].getName().equals(targetName)) { if (methods[i].getName().equals(action) ||
// handle our old style of prepending "handle"
methods[i].getName().equals("handle" + action)) {
// see if we can generate the appropriate arguments // see if we can generate the appropriate arguments
args = generateArguments(methods[i], source, arg); args = generateArguments(methods[i], source, arg);
// if we were able to, go ahead and use this method // if we were able to, go ahead and use this method
@@ -243,7 +240,6 @@ public abstract class Controller
if (method != null) { if (method != null) {
method.invoke(this, args); method.invoke(this, args);
return true; return true;
} else { } else {
return false; return false;
} }
@@ -319,13 +315,13 @@ public abstract class Controller
/** /**
* Posts the specified action to the nearest controller in scope. The * Posts the specified action to the nearest controller in scope. The
* controller search begins with the source component of the action * controller search begins with the source component of the action and
* and traverses up the component tree looking for a controller to * traverses up the component tree looking for a controller to handle the
* handle the action. The controller location and action event * action. The controller location and action event processing is
* processing is guaranteed to take place on the AWT thread regardless * guaranteed to take place on the AWT thread regardless of what thread
* of what thread calls <code>postAction</code> and that processing * calls <code>postAction</code> and that processing will not occur
* will not occur immediately but is instead appended to the AWT event * immediately but is instead appended to the AWT event dispatch queue for
* dispatch queue for processing. * processing.
*/ */
public static void postAction (ActionEvent action) public static void postAction (ActionEvent action)
{ {