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

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: ActionContainerFactory.java,v 1.6 2005/10/10 18:02:43 rbair 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.Insets;
  23. import java.util.Arrays;
  24. import java.util.HashMap;
  25. import java.util.Iterator;
  26. import java.util.List;
  27. import java.util.Map;
  28. import javax.swing.AbstractButton;
  29. import javax.swing.Action;
  30. import javax.swing.ButtonGroup;
  31. import javax.swing.Icon;
  32. import javax.swing.JButton;
  33. import javax.swing.JCheckBoxMenuItem;
  34. import javax.swing.JComponent;
  35. import javax.swing.JMenu;
  36. import javax.swing.JMenuBar;
  37. import javax.swing.JMenuItem;
  38. import javax.swing.JPopupMenu;
  39. import javax.swing.JRadioButtonMenuItem;
  40. import javax.swing.JToggleButton;
  41. import javax.swing.JToolBar;
  42. /**
  43.  * Creates user interface elements based on action ids and lists of action ids.
  44.  * All action ids must represent actions managed by the ActionManager.
  45.  * <p>
  46.  * <h3>Action Lists</h3>
  47.  * Use the createXXX(List) methods to construct containers of actions like menu 
  48.  * bars, menus, popups and toolbars from actions represented as action ids in a 
  49.  * <i>java.util.List</i>. Each element in the action-list can be one of 3 types:
  50.  * <ul>
  51.  * <li>action id: corresponds to an action managed by the ActionManager
  52.  * <li>null: indicates a separator should be inserted.
  53.  * <li>java.util.List: represents a submenu. See the note below which describes 
  54.  * the configuration of menus. 
  55.  * </li>
  56.  * The order of elements in an action-list determines the arrangement of the ui 
  57.  * components which are contructed from the action-list.
  58.  * <p>
  59.  * For a menu or submenu, the first element in the action-list represents a menu 
  60.  * and subsequent elements represent menu items or separators (if null). 
  61.  * <p>
  62.  * This class can be used as a general component factory which will construct
  63.  * components from Actions if the <code>create&lt;comp&gt;(Action,...)</code>
  64.  * methods are used.
  65.  *
  66.  * @see ActionManager
  67.  */
  68. public class ActionContainerFactory {
  69.     /**
  70.      * Standard margin for toolbar buttons to improve their look
  71.      */
  72.     private static Insets TOOLBAR_BUTTON_MARGIN = new Insets(1, 1, 1, 1);
  73.     
  74.     private ActionManager manager;
  75.     // Map between group id + component and the ButtonGroup
  76.     private Map groupMap;
  77.     /**
  78.      * Constructs an container factory which uses managed actions.
  79.      *
  80.      * @param manager use the actions managed with this manager for
  81.      *                constructing ui componenents.
  82.      */
  83.     public ActionContainerFactory(ActionManager manager) {
  84.         setActionManager(manager);
  85.     }
  86.     /**
  87.      * Gets the ActionManager instance. If the ActionManager has not been explicitly
  88.      * set then the default ActionManager instance will be used.
  89.      *
  90.      * @return the ActionManager used by the ActionContainerFactory.
  91.      * @see #setActionManager
  92.      */
  93.     public ActionManager getActionManager() {
  94.         if (manager == null) {
  95.             manager = ActionManager.getInstance();
  96.         }
  97.         return manager;
  98.     }
  99.     /**
  100.      * Sets the ActionManager instance that will be used by this
  101.      * ActionContainerFactory
  102.      */
  103.     public void setActionManager(ActionManager manager) {
  104.         ActionManager oldManager = this.manager;
  105.         if (oldManager != null) {
  106.             oldManager.setFactory(null);
  107.         }
  108.         this.manager = manager;
  109.         
  110.         if (manager != null) {
  111.             manager.setFactory(this);
  112.         }
  113.     }
  114.     /**
  115.      * Constructs a toolbar from an action-list id. By convention,
  116.      * the identifier of the main toolbar should be "main-toolbar"
  117.      *
  118.      * @param list a list of action ids used to construct the toolbar.
  119.      * @return the toolbar or null
  120.      */
  121.     private JToolBar createToolBar(Object[] list) {
  122.         return createToolBar(Arrays.asList(list));
  123.     }
  124.     /**
  125.      * Constructs a toolbar from an action-list id. By convention,
  126.      * the identifier of the main toolbar should be "main-toolbar"
  127.      *
  128.      * @param list a list of action ids used to construct the toolbar.
  129.      * @return the toolbar or null
  130.      */
  131.     public JToolBar createToolBar(List list) {
  132.         JToolBar toolbar = new JToolBar();
  133.         Iterator iter = list.iterator();
  134.         while(iter.hasNext()) {
  135.             Object element = iter.next();
  136.             if (element == null) {
  137.                 toolbar.addSeparator();
  138.             } else {
  139.                 AbstractButton button = createButton(element, toolbar);
  140.                 // toolbar buttons shouldn't steal focus
  141.                 button.setFocusable(false);
  142.                 /*
  143.                  * TODO
  144.                  * The next two lines improve the default look of the buttons.
  145.                  * This code should be changed to retrieve the default look
  146.                  * from some UIDefaults object.
  147.                  */
  148.                 button.setMargin(TOOLBAR_BUTTON_MARGIN);
  149.                 button.setBorderPainted(false);
  150.                 
  151.                 toolbar.add(button);
  152.             }
  153.         }
  154.         return toolbar;
  155.     }
  156.     /**
  157.      * Constructs a popup menu from an array of action ids.  
  158.      *
  159.      * @param list an array of action ids used to construct the popup.
  160.      * @return the popup or null
  161.      */
  162.     private JPopupMenu createPopup(Object[] list) {
  163.         return createPopup(Arrays.asList(list));
  164.     }
  165.     /**
  166.      * Constructs a popup menu from a list of action ids.
  167.      *
  168.      * @param list a list of action ids used to construct the popup.
  169.      * @return the popup or null
  170.      */
  171.     public JPopupMenu createPopup(List list) {
  172.         JPopupMenu popup = new JPopupMenu();
  173.         Iterator iter = list.iterator();
  174.         while(iter.hasNext()) {
  175.             Object element = iter.next();
  176.             if (element == null) {
  177.                 popup.addSeparator();
  178.             } else if (element instanceof List) {
  179.                 JMenu newMenu= createMenu((List)element);
  180.                 if (newMenu!= null) {
  181.                     popup.add(newMenu);
  182.                 }
  183.             } else {
  184.                 popup.add(createMenuItem(element, popup));
  185.             }
  186.         }
  187.         return popup;
  188.     }
  189.     /**
  190.      * Constructs a menu tree from a list of actions or lists of lists or actions.
  191.      * TODO This method is broken. It <em>should</em> expect either that every
  192.      * entry is a List (thus, the sub menus off the main MenuBar), or it should
  193.      * handle normal actions properly. By submitting a List of all Actions, nothing
  194.      * is created....
  195.      * <p>
  196.      * For example, If my list is [action, action, action], then nothing is added
  197.      * to the menu bar. However, if my list is [list[action], action, action, action] then
  198.      * I get a menu and under it the tree actions. This should not be, because if I
  199.      * wanted those actions to be on the sub menu, then they should have been
  200.      * listed within the sub list!
  201.      *
  202.      * @param list a list which represents the root item.
  203.      * @return a menu bar which represents the menu bar tree
  204.      */
  205.     public JMenuBar createMenuBar(List list) {
  206.         JMenuBar menubar = new JMenuBar();
  207.         JMenu menu = null;
  208.         Iterator iter = list.iterator();
  209.         while(iter.hasNext()) {
  210.             Object element = iter.next();
  211.             if (element == null) {
  212.                 if (menu != null) {
  213.                     menu.addSeparator();
  214.                 }
  215.             } else if (element instanceof List) {
  216.                 menu = createMenu((List)element);
  217.                 if (menu != null) {
  218.                     menubar.add(menu);
  219.                 }
  220.             } else  {
  221.                 if (menu != null) {
  222.                     menu.add(createMenuItem(element, menu));
  223.                 }
  224.             }
  225.         }
  226.         return menubar;
  227.     }
  228.     /**
  229.      * Creates and returns a menu from a List which represents actions, separators
  230.      * and sub-menus. The menu
  231.      * constructed will have the attributes from the first action in the List.
  232.      * Subsequent actions in the list represent menu items.
  233.      *
  234.      * @param list a list of action ids used to construct the menu and menu items.
  235.      *             the first element represents the action used for the menu,
  236.      * @return the constructed JMenu or null
  237.      */
  238.     public JMenu createMenu(List list) {
  239.         // The first item will be the action for the JMenu
  240.         Action action = getAction(list.get(0));
  241.         if (action == null) {
  242.             return null;
  243.         }
  244.         JMenu menu = new JMenu(action);
  245.         // The rest of the items represent the menu items.
  246.         Iterator iter = list.listIterator(1);
  247.         while(iter.hasNext()) {
  248.             Object element = iter.next();
  249.             if (element == null) {
  250.                 menu.addSeparator();
  251.             } else if (element instanceof List) {
  252.                 JMenu newMenu = createMenu((List)element);
  253.                 if (newMenu != null) {
  254.                     menu.add(newMenu);
  255.                 }
  256.             } else  {
  257.                 menu.add(createMenuItem(element, menu));
  258.             }
  259.         }
  260.         return menu;
  261.     }
  262.     /**
  263.      * Convenience method to get the action from an ActionManager.
  264.      */
  265.     private Action getAction(Object id) {
  266.         Action action = getActionManager().getAction(id);
  267.         if (action == null) {
  268.             throw new RuntimeException("ERROR: No Action for " + id);
  269.         }
  270.         return action;
  271.     }
  272.     /**
  273.      * Returns the button group corresponding to the groupid
  274.      *
  275.      * @param groupid the value of the groupid attribute for the action element
  276.      * @param container a container which will further identify the ButtonGroup
  277.      */
  278.     private ButtonGroup getGroup(String groupid, JComponent container) {
  279.         if (groupMap == null) {
  280.             groupMap = new HashMap();
  281.         }
  282.         int intCode = groupid.hashCode();
  283.         if (container != null) {
  284.             intCode ^= container.hashCode();
  285.         }
  286.         Integer hashCode = new Integer(intCode);
  287.         ButtonGroup group = (ButtonGroup)groupMap.get(hashCode);
  288.         if (group == null) {
  289.             group = new ButtonGroup();
  290.             groupMap.put(hashCode, group);
  291.         }
  292.         return group;
  293.     }
  294.     /**
  295.      * Creates a menu item based on the attributes of the action element.
  296.      * Will return a JMenuItem, JRadioButtonMenuItem or a JCheckBoxMenuItem
  297.      * depending on the context of the Action.
  298.      *
  299.      * @return a JMenuItem or subclass depending on type.
  300.      */
  301.     private JMenuItem createMenuItem(Object id, JComponent container) {
  302.         return createMenuItem(getAction(id), container);
  303.     }
  304.     /**
  305.      * Creates a menu item based on the attributes of the action element.
  306.      * Will return a JMenuItem, JRadioButtonMenuItem or a JCheckBoxMenuItem
  307.      * depending on the context of the Action.
  308.      *
  309.      * @param action a mangaged Action
  310.      * @param container the parent container may be null for non-group actions.
  311.      * @return a JMenuItem or subclass depending on type.
  312.      */
  313.     public JMenuItem createMenuItem(Action action, JComponent container) {
  314.         JMenuItem menuItem = null;
  315.         if (action instanceof AbstractActionExt) {
  316.             AbstractActionExt ta = (AbstractActionExt)action;
  317.             if (ta.isStateAction()) {
  318.                 String groupid = (String)ta.getGroup();
  319.                 if (groupid != null) {
  320.                     // If this action has a groupid attribute then it's a
  321.                     // GroupAction
  322.                     menuItem = createRadioButtonMenuItem(getGroup(groupid, container),
  323.                                                          (AbstractActionExt)action);
  324.                 } else {
  325.                     menuItem = createCheckBoxMenuItem((AbstractActionExt)action);
  326.                 }
  327.             }
  328.         }
  329.         if (menuItem == null) {
  330.             menuItem= new JMenuItem(action);
  331.             configureMenuItem(menuItem, action);
  332.         }
  333.         return menuItem;
  334.     }
  335.     /**
  336.      * Creates a menu item based on the attributes of the action.
  337.      * Will return a JMenuItem, JRadioButtonMenuItem or a JCheckBoxMenuItem
  338.      * depending on the context of the Action.
  339.      *
  340.      * @param action an action used to create the menu item
  341.      * @return a JMenuItem or subclass depending on type.
  342.      */
  343.     public JMenuItem createMenuItem(Action action) {
  344.         return createMenuItem(action, null);
  345.     }
  346.     /**
  347.      * Creates a button based on the attributes of the action element.
  348.      * Will return a JButton or a JToggleButton.
  349.      */
  350.     private AbstractButton createButton(Object id, JComponent container) {
  351.         return createButton(getAction(id), container);
  352.     }
  353.     /**
  354.      * Creates a button based on the attributes of the action. If the container
  355.      * parameter is non-null then it will be used to uniquely identify
  356.      * the returned component within a ButtonGroup. If the action doesn't
  357.      * represent a grouped component then this value can be null.
  358.      *
  359.      * @param action an action used to create the button
  360.      * @param container the parent container to uniquely identify
  361.      *        grouped components or null
  362.      * @return will return a JButton or a JToggleButton.
  363.      */
  364.     public AbstractButton createButton(Action action, JComponent container) {
  365.         if (action == null) {
  366.             return null;
  367.         }
  368.         AbstractButton button = null;
  369.         if (action instanceof AbstractActionExt) {
  370.             // Check to see if we should create a toggle button
  371.             AbstractActionExt ta = (AbstractActionExt)action;
  372.             if (ta.isStateAction()) {
  373.                 // If this action has a groupid attribute then it's a
  374.                 // GroupAction
  375.                 String groupid = (String)ta.getGroup();
  376.                 if (groupid == null) {
  377.                     button = createToggleButton(ta);
  378.                 } else {
  379.                     button = createToggleButton(ta, getGroup(groupid, container));
  380.                 }
  381.             }
  382.         }
  383.         if (button == null) {
  384.             // Create a regular button
  385.             button = new JButton(action);
  386.             configureButton(button, action);
  387.         }
  388.         return button;
  389.     }
  390.     /**
  391.      * Creates a button based on the attributes of the action.
  392.      *
  393.      * @param action an action used to create the button
  394.      * @return will return a JButton or a JToggleButton.
  395.      */
  396.     public AbstractButton createButton(Action action)  {
  397.         return createButton(action, null);
  398.     }
  399.     /**
  400.      * Adds and configures a toggle button.
  401.      * @param a an abstraction of a toggle action.
  402.      */
  403.     private JToggleButton createToggleButton(AbstractActionExt a)  {
  404.         return createToggleButton(a, null);
  405.     }
  406.     /**
  407.      * Adds and configures a toggle button.
  408.      * @param a an abstraction of a toggle action.
  409.      * @param group the group to add the toggle button or null
  410.      */
  411.     private JToggleButton createToggleButton(AbstractActionExt a, ButtonGroup group)  {
  412.         JToggleButton button = new JToggleButton();
  413.         configureButton(button, a, group);
  414.         return button;
  415.     }
  416.     /**
  417.      * 
  418.      * @param button
  419.      * @param a
  420.      * @param group
  421.      * @return
  422.      */
  423.     public void configureButton(JToggleButton button, AbstractActionExt a, ButtonGroup group) {
  424.         button.setAction(a);
  425.         button.addItemListener(a);
  426.         button.setSelected(a.isSelected());
  427.         if (group != null) {
  428.             group.add(button);
  429.         }
  430.         configureToggleButton(button, a);
  431.     }
  432.     /**
  433.      * This method will be called after toggle buttons are created.
  434.      * Override for custom configuration but the overriden method should be called
  435.      * first.
  436.      *
  437.      * @param button the button to be configured
  438.      * @param action the action used to construct the menu item.
  439.      */
  440.     protected void configureToggleButton(JToggleButton button, Action action) {
  441.         configureButton(button, action);
  442.         // The PropertyChangeListener that gets added
  443.         // to the Action doesn't know how to handle the "selected" property change
  444.         // in the meantime, the corect thing to do is to add another PropertyChangeListener
  445.         // to the AbstractActionExt until this is fixed.
  446.         action.addPropertyChangeListener(new ToggleActionPropertyChangeListener(button));
  447.     }
  448.     /**
  449.      * This method will be called after buttons created from an action.
  450.      * Override for custom configuration.
  451.      *
  452.      * @param button the button to be configured
  453.      * @param action the action used to construct the menu item.
  454.      */
  455.     protected void configureButton(AbstractButton button, Action action)  {
  456.         if (action.getValue(Action.SHORT_DESCRIPTION) == null) {
  457.             button.setToolTipText((String)action.getValue(Action.NAME));
  458.         }
  459.         // Use the large icon for toolbar buttons.
  460.         if (action.getValue(AbstractActionExt.LARGE_ICON) != null) {
  461.             button.setIcon((Icon)action.getValue(AbstractActionExt.LARGE_ICON));
  462.         }
  463.         // Don't show the text under the toolbar buttons if they have an icon
  464.         if (button.getIcon() != null) {
  465.             button.setText("");
  466.         }
  467.     }
  468.     /**
  469.      * This method will be called after toggle type menu items (like
  470.      * JRadioButtonMenuItem and JCheckBoxMenuItem) are created.
  471.      * Override for custom configuration but the overriden method should be called
  472.      * first.
  473.      *
  474.      * @param menuItem the menu item to be configured
  475.      * @param action the action used to construct the menu item.
  476.      */
  477.     protected void configureToggleMenuItem(JMenuItem menuItem, Action action) {
  478.         configureMenuItem(menuItem, action);
  479.         // The PropertyChangeListener that gets added
  480.         // to the Action doesn't know how to handle the "selected" property change
  481.         // in the meantime, the corect thing to do is to add another PropertyChangeListener
  482.         // to the AbstractActionExt until this is fixed.
  483.         action.addPropertyChangeListener(new ToggleActionPropertyChangeListener(menuItem));
  484.     }
  485.     /**
  486.      * This method will be called after menu items are created.
  487.      * Override for custom configuration.
  488.      *
  489.      * @param menuItem the menu item to be configured
  490.      * @param action the action used to construct the menu item.
  491.      */
  492.     protected void configureMenuItem(JMenuItem menuItem, Action action) {
  493.     }
  494.     /**
  495.      * Helper method to add a checkbox menu item.
  496.      */
  497.     private JCheckBoxMenuItem createCheckBoxMenuItem(AbstractActionExt a) {
  498.         JCheckBoxMenuItem mi = new JCheckBoxMenuItem(a);
  499.         mi.addItemListener(a);
  500.         mi.setSelected(a.isSelected());
  501.         configureToggleMenuItem(mi, a);
  502.         return mi;
  503.     }
  504.     /**
  505.      * Helper method to add a radio button menu item.
  506.      */
  507.     private JRadioButtonMenuItem createRadioButtonMenuItem(ButtonGroup group,
  508.                                                                   AbstractActionExt a)  {
  509.         JRadioButtonMenuItem mi = new JRadioButtonMenuItem(a);
  510.         mi.addItemListener(a);
  511.         mi.setSelected(a.isSelected());
  512.         if (group != null) {
  513.             group.add(mi);
  514.         }
  515.         configureToggleMenuItem(mi, a);
  516.         return mi;
  517.     }
  518. }