TargetManager.java
上传用户:zhengdagz
上传日期:2014-03-06
资源大小:1956k
文件大小:10k
源码类别:

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: TargetManager.java,v 1.3 2005/10/13 08:59:54 kleopatra Exp $
  3.  *
  4.  * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
  5.  * Santa Clara, California 95054, U.S.A. All rights reserved.
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  * 
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  * 
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  20.  */
  21. package org.jdesktop.swingx.action;
  22. import java.awt.Component;
  23. import java.awt.event.ActionEvent;
  24. import java.beans.PropertyChangeListener;
  25. import java.beans.PropertyChangeSupport;
  26. import java.util.ArrayList;
  27. import java.util.Iterator;
  28. import java.util.List;
  29. import javax.swing.Action;
  30. import javax.swing.ActionMap;
  31. import javax.swing.JComponent;
  32. import javax.swing.FocusManager;
  33. /**
  34.  * The target manager dispatches commands to {@link Targetable} objects
  35.  * that it manages. This design of this class is based on the <i>Chain of
  36.  * Responsiblity</i> and <i>Mediator</i> design patterns. The target manager
  37.  * acts as a mediator between {@link TargetableAction}s and the intended targets.
  38.  * This allows Action based components to invoke commands on components
  39.  * without explicitly binding the user Action to the component action.
  40.  * <p>
  41.  * The target manager maintains a reference to a current
  42.  * target and a target list.
  43.  * The target list is managed using the <code>addTarget</code> and
  44.  * <code>removeTarget</code> methods. The current target is managed using the
  45.  * <code>setTarget</code> and <code>getTarget</code> methods.
  46.  * <p>
  47.  * Commands are dispatched to the Targetable objects in the <code>doCommand</code>
  48.  * method in a well defined order. The doCommand method on the Targetable object
  49.  * is called and if it returns true then the command has been handled and
  50.  * command dispatching will stop. If the Targetable doCommand method returns
  51.  * false then the
  52.  * <p>
  53.  * If none of the Targetable objects can handle the command then the default
  54.  * behaviour is to retrieve an Action from the {@link javax.swing.ActionMap} of
  55.  * the permanent focus owner with a key that matches the command key. If an
  56.  * Action can be found thenthe <code>actionPerformed</code>
  57.  * method is invoked using an <code>ActionEvent</code> that was constructed
  58.  * using the command string.
  59.  * <p>
  60.  * If the Action is not found on the focus order then the ActionMaps of the ancestor
  61.  * hierarchy of the focus owner is searched until a matching Action can be found.
  62.  *  Finally, if none
  63.  * of the components can handle the command then it is dispatche to the ActionMap
  64.  * of the current Application instance.
  65.  * <p>
  66.  * The order of command dispatch is as follows:
  67.  * <ul>
  68.  *    <li>Current Targetable object invoking doCommand method
  69.  *    <li>List order of Targetable objects invoking doCommand method
  70.  *    <li>ActionMap entry of the permanent focus owner invoking actionPerfomed
  71.  *    <li>ActionMap entry of the ancestor hierarchy of the permanent focus owner
  72.  *    <li>ActionMap entry of the current Application instance
  73.  * </ul>
  74.  *
  75.  * @see Targetable
  76.  * @see TargetableAction
  77.  * @author Mark Davidson
  78.  */
  79. public class TargetManager {
  80.     private static TargetManager INSTANCE;
  81.     private List targetList;
  82.     private Targetable target;
  83.     private PropertyChangeSupport propertySupport;
  84.     /**
  85.      * Create a target manager. Use this constructor if the application
  86.      * may support many target managers. Otherwise, using the getInstance method
  87.      * will return a singleton.
  88.      */
  89.     public TargetManager() {
  90.         propertySupport = new PropertyChangeSupport(this);
  91.     }
  92.     /**
  93.      * Return the singleton instance.
  94.      */
  95.     public static TargetManager getInstance() {
  96.         if (INSTANCE == null) {
  97.             INSTANCE = new TargetManager();
  98.         }
  99.         return INSTANCE;
  100.     }
  101.     /**
  102.      * Add a target to the target list. Will be appended
  103.      * to the list by default. If the prepend flag is true then
  104.      * the target will be added at the head of the list.
  105.      * <p>
  106.      * Targets added to the head of the list will will be the first
  107.      * to handle the command.
  108.      *
  109.      * @param target the targeted object to add
  110.      * @param prepend if true add at the head of the list; false append
  111.      */
  112.     public void addTarget(Targetable target, boolean prepend) {
  113.         if (targetList == null) {
  114.             targetList = new ArrayList();
  115.         }
  116.         if (prepend) {
  117.             targetList.add(0, target);
  118.         } else {
  119.             targetList.add(target);
  120.         }
  121.         // Should add focus listener to the component.
  122.     }
  123.     /**
  124.      * Appends the target to the target list.
  125.      * @param target the targeted object to add
  126.      */
  127.     public void addTarget(Targetable target) {
  128.         addTarget(target, false);
  129.     }
  130.     /**
  131.      * Remove the target from the list
  132.      */
  133.     public void removeTarget(Targetable target) {
  134.         if (targetList != null) {
  135.             targetList.remove(target);
  136.         }
  137.     }
  138.     /**
  139.      * Returns an array of managed targets that were added with the
  140.      * <code>addTarget</code> methods.
  141.      *
  142.      * @return all the <code>Targetable</code> added or an empty array if no
  143.      *         targets have been added
  144.      */
  145.     public Targetable[] getTargets() {
  146.         Targetable[] targets;
  147.         if (targetList == null) {
  148.             targets = new Targetable[0];
  149.         } else {
  150.             targets = new Targetable[targetList.size()];
  151.             targets = (Targetable[])targetList.toArray(new Targetable[targetList.size()]);
  152.         }
  153.         return targets;
  154.     }
  155.     /**
  156.      * Gets the current targetable component. May or may not
  157.      * in the target list. If the current target is null then
  158.      * the the current targetable component will be the first one
  159.      * in the target list which can execute the command.
  160.      *
  161.      * This is a bound property and will fire a property change event
  162.      * if the value changes.
  163.      *
  164.      * @param newTarget the current targetable component to set or null if
  165.      *       the TargetManager shouldn't have a current targetable component.
  166.      */
  167.     public void setTarget(Targetable newTarget) {
  168.         Targetable oldTarget = target;
  169.         if (oldTarget != newTarget) {
  170.             target = newTarget;
  171.             propertySupport.firePropertyChange("target", oldTarget, newTarget);
  172.         }
  173.     }
  174.     /**
  175.      * Return the current targetable component. The curent targetable component
  176.      * is the first place where commands will be dispatched.
  177.      *
  178.      * @return the current targetable component or null
  179.      */
  180.     public Targetable getTarget() {
  181.         return target;
  182.     }
  183.     public void addPropertyChangeListener(PropertyChangeListener listener) {
  184.         propertySupport.addPropertyChangeListener(listener);
  185.     }
  186.     public void removePropertyChangeListener(PropertyChangeListener listener) {
  187.         propertySupport.removePropertyChangeListener(listener);
  188.     }
  189.     /**
  190.      * Executes the command on the current targetable component.
  191.      * If there isn't current targetable component then the list
  192.      * of targetable components are searched and the first component
  193.      * which can execute the command. If none of the targetable
  194.      * components handle the command then the ActionMaps of the
  195.      * focused components are searched.
  196.      *
  197.      * @param command the key of the command
  198.      * @param value the value of the command; depends on context
  199.      * @return true if the command has been handled otherwise false
  200.      */
  201.     public boolean doCommand(Object command, Object value) {
  202.         // Try to invoked the explicit target.
  203.         if (target != null) {
  204.             if (target.hasCommand(command) && target.doCommand(command, value)) {
  205.                 return true;
  206.             }
  207.         }
  208.         // The target list has the next chance to handle the command.
  209.         if (targetList != null) {
  210.             Iterator iter = targetList.iterator();
  211.             while (iter.hasNext()) {
  212.                 Targetable target = (Targetable)iter.next();
  213.                 if (target.hasCommand(command) &&
  214.                     target.doCommand(command, value)) {
  215.                     return true;
  216.                 }
  217.             }
  218.         }
  219.         ActionEvent evt = null;
  220.         if (value instanceof ActionEvent) {
  221.             evt = (ActionEvent)value;
  222.         }
  223.         // Fall back behavior. Get the component which has focus and search the
  224.         // ActionMaps in the containment hierarchy for matching action.
  225.         Component comp = FocusManager.getCurrentManager().getPermanentFocusOwner();
  226.         while (comp != null) {
  227.             if (comp instanceof JComponent) {
  228.                 ActionMap map = ((JComponent)comp).getActionMap();
  229.                 Action action = map.get(command);
  230.                 if (action != null) {
  231.                     if (evt == null) {
  232.                         evt = new ActionEvent(comp, 0, command.toString());
  233.                     }
  234.                     action.actionPerformed(evt);
  235.                     return true;
  236.                 }
  237.             }
  238.             comp = comp.getParent();
  239.         }
  240.         return false;
  241.     }
  242.     /**
  243.      * Resets the TargetManager.
  244.      * This method is package private and for testing purposes only.
  245.      */
  246.     void reset() {
  247.         if (targetList != null) {
  248.             targetList.clear();
  249.             targetList = null;
  250.         }
  251.         target = null;
  252.         PropertyChangeListener[] listeners = propertySupport.getPropertyChangeListeners();
  253.         for (int i = 0; i < listeners.length; i++) {
  254.             propertySupport.removePropertyChangeListener(listeners[i]);
  255.         }
  256.         INSTANCE = null;
  257.     }
  258. }