![]() ![]() |
![]() |
![]() ![]() ![]() ![]() |
![]() |
Application writers need a simple method for dynamically determining the target of an action. Also, they need to be able to use off-the-shelf components, including Swing components, with the assurance that actions and their targets will work together correctly. Swing addresses this need by providing objects called Target Managers, which dynamically determine action targets. The dynamic determination of action targets is a new functionality, based on actions, that is provided by Swing as part of Swing Application Services.
This specification describes Target Mangers and explains how they dynamically determine action targets. It also explains how this new capability of Swing can help you create and manage user-interface components.
The current Action specification provided in AWT does not say anything about the connection of an Action with its target. This connection is left up to the Action subclass to define, using an Action-specific interface and a constructor that accepts the target as an argument. The target is currently defined to be immutable, although individual Actions could choose to publish a setTarget() method.
A typical application has many Actions whose targets are determined by the state of the application at any given time. For example, several components might understand how to "cut" a selection using a standard "cut" operation. However, only the currently active application should actually do the cutting when the user fires a "cut" Action. Under current AWT design, the writer of an application has the responsibility of making sure this happens, by either dynamically changing the target of the Action whenever the selection changes -- or, worse, by changing the Action itself if setTarget() is not defined. Another option might be to make the application, or some other object, the target of the Action. This object would forward the Action on to the "real" target, which would be determined dynamically.
Each of these options is unsatisfactory. In the first case, it is left up to the application to determine what sorts of things might cause the recipient of an Action to change. On a case-by-case basis, each Action would have to be stuffed with the proper target.
Managing this kind of situation is quite complex. Providing a common infrastructure to support it is difficult.
Using a dynamically forwarding target seems more promising at first -- but then, because each Action has its own interface, providing a common substructure becomes difficult because a forwarding target class must be defined for each Action. Worse, because Actions have states indicating whether they are enabled or disabled, something has to be created to update dynamically an enabled/disabled flag. So effect of this solution is no different from that of the first option -- on a case-by-case basis, each Action still has to be modified when the state of the application changes.
Swing addresses these problems by dynamically determining action targets -- as noted at the beginning of this specification. In Swing, objects can register with TargetManagers, specifying the Actions that they are capable of supporting. Subsequently, an Action can query a TargetManager to find out what its current target is. (See the "Remaining Questions" section for more details.)
It is important to note that Swing does not make any effort to define the specific policy that a TargetManager applies to determine the proper target of an action. It is up to specific implementations of TargetManager to define that policy. The Swing Application Services toolkit does supply a default implementation, based on Swing's own selection and document model, but application writers are free to supply alternatives.
The following interface acts as a registration center for Actions and potential Targets:
interface TargetManager { /* Tells the TargetManager that object is capable of performing action */ void registerTarget(Action action, Object object); /** * Tells the TargetManager that object is no longer capable of * performing action. */ void unregisterTarget(Action action, Object object); /** * Tells the TargetManager that object is no longer capable of * any Action. */ void unregisterTarget(Object object); /* Returns the current target for action */ Object targetForAction(Action action); /* Returns true if action is currently enabled */ boolean isActionEnabled(Action action); /** * The Util inner class provides the means of discovering the * current TargetManager, based on the current ThreadGroup. It also * supports registering one. */ static public class Util { /** * Gets the TargetManager for the current ThreadGroup. If none * has been registered using setTargetManager() a dummy implementation * that does nothing will be returned. */ public TargetManager getTargetManager() { } /* Sets the TargetManager for the current ThreadGroup */ public void setTargetManager(TargetManager manager) { } } }
Typically, an object locates its TargetManager and then registers with the TargetManger, declaring itself capable of receiving particular Actions. (See the "Remaining Questions" section for details.) It is then up the the particular TargetManager being used to determine a policy that a particular target will use to receive a particular Action at a particular time.
The Target interface, which is defined as follows, allow objects to express more about their behavior regarding Actions:
interface Target { boolean isActionEnabled(Action action); }
NOTE: Any object can be the Target of an Action. The specific type of object, and any type checking that may be used, is defined by the individual Action subclass. But objects that implement Target can interact more effectively with a TargetManager.
The JDynamicAction class supports an Action's interaction with a TargetManager. Actions can be created with a specific TargetManager or can use the TargetManager that is registered with the current ThreadGroup.
NOTE: Any Action can be used with a TargetManager. The JDynamicAction class just simplifies the Action's use of the TargetManager.
The following is the definition of the JDynamicAction class:
public class JDynamicAction extends Action { /** * Associates an Action with a TargetManager. Note that this is an immutable * attribute of an Action. */ public Action(TargetManager manager) { } /** * Creates an action that will use the "current" thread group to determine * its TargetManager when asked for it using getTargetManager() */ public Action() { } /** * Returns the TargetManager associated with the Action. Note that if none * has been specifically set using the constructor the current ThreadGroup * will be used to find the manager. */ public TargetManager getTargetManager() { } /** * Allows an Action to determine the validity of a specific object. * The TargetManager can use this method to help determine the * current target of an Action. */ public boolean isTargetValid(Object target) { } }
At Swing's current stage of development, we are considering the following questions (input from developers is welcome):
Version 0.5. Last modified 09/04/97.
Copyright © 1995-97 Sun
Microsystems, Inc. All Rights Reserved.