/** * Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.bushe.swing.action; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.awt.Color; import java.awt.Dimension; import javax.swing.AbstractButton; import javax.swing.Action; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JRadioButtonMenuItem; import javax.swing.JSeparator; import javax.swing.JToggleButton; import javax.swing.JToolBar; /** * Creates user interface elements based on Actions. * <p> * Menus, popup menus and toolbars are created with ActionLists or ids of * ActionLists. When using ids, the ActionLists are retrieved from the * ActionManager. The default ActionManager is used, but another ActionManager * can be set on this class. * <p> * When creating toolbars, ActionLists are treated as single-dimentional. When * creating menu's sub lists in ActionLists caus rethe creation of sub menus. * <p> * When creating menus, the ActionList's tigger action is respected if non-null. * When present, the corresponding Action becomes the Menu's Action, which * differs from the Menu Item actions, since it is the action that gets fired * when the menu is displayed. This gives a chance to customize the menu before * it is displayed. * <p> * Besides the standard Swing AbstractAction values, the ActionUIManager * respects the following Action attributes (action.getValue(Object)): * <pre> * ActionManager.MENU_SHOWS_ICON - sometimes an action has an icon defined that * you want to appear in the toolbar, but not in the menu item. Setting this * value to Boolean.FALSE will have this effect. * ActionManager.BUTTON_TYPE - when set to "radio", "checkbox" or "toggle" * then a radio button, toggle button, or checkbox is created. GROUP overrides * this property. * ActionManager.WEIGHT - orders menu items and separators * ActionManager.GROUP - when set, groups buttons together so that only one * is selected at a time. Internally a ButtonGroup is created (if you really * want the button's button group, you can get it from a button's model). A * toggle button is created for toolbars and check button is created for menus. * @todo - allow override of hard coded group rule for toolbars or menus * </pre> * <p> * The instantiate* methods are provided to allow the custom menus and buttons * to be created instead of the default Swing classes. * <p> * Inspired partly from <a href="http://www.javadesktop.org/articles/actions/"> * Mark Davidson's Easy Actions'</a> UIFactory, though Mark and Michael Bushe * developed similar frameworks simultaneously. Renamed since apps * have many UIFactories and this one doesn't create all you would need. * * @todo - Popups are different from regular menus since they don't have actions * they figure you don't need them since you are deciding when the popup * appears and can customize then. So how about adding a popup menu listener * that asks the actions if they should be removed or * @see ActionManager */ public class ActionUIFactory { private static ActionUIFactory INSTANCE; /** Used to hold named instances*/ private static Map NAMED_INSTANCES; private static Object INSTANCE_LOCK = new Object(); /** If 1.4, need to set request focus enabled on toolbar buttons*/ private static boolean sToolbarRequestFocusEnabled14 = !(System.getProperty( "java.vm.version").indexOf("1.3") > -1); /** Check the VM version to determine some default settings. JDK 1.4 * works nicely, but 1.3 needs some hand holding.*/ private static boolean sSetButtonSizeFor13 = System.getProperty( "java.vm.version").indexOf("1.3") > -1; /** Allows configuration of size of toolbar buttons.*/ private Dimension toolbarButtonPreferredSize = null; // Pass -Ddebug=true to enable debugging private static boolean DEBUG = false; private ActionManager actionManager; /** * Cannot instantiate this directly, only because if someone is using the API * quickly, then they are steered to the commonly used getInstance() method. * <p> * However, since more than one ActionUIFactory may be useful in certain situations, the constructor * is made protected to allow multiple ActionUIFactory's to exist by extension. It's a bit of a pain, * but it's a bigger pain to expose this publicly when it would rarely be needed. * @param manager the manager to use with the factory, if null the ActionManager.getInstance() will be used. */ protected ActionUIFactory(ActionManager manager) { if (manager == null) { manager = ActionManager.getInstance(); } this.actionManager = manager; } /** * Return the instance of the ActionUIFactory if this will be used as a singleton. The instance will be created * if it hasn't previously been set. * * @return the UIFactory instance. * @see #setInstance */ public static ActionUIFactory getInstance() { synchronized (INSTANCE_LOCK) { if (INSTANCE == null) { INSTANCE = new ActionUIFactory(ActionManager.getInstance()); setInstance(null, INSTANCE); } } return INSTANCE; } /** * Creates a new default ActionUIFactory instance, associates it with the provided ActionManager * and adds it as an instance with the given name. Typically not needed, but can be useful * if using mulitple named factories with multiple managers (without specialized factories). * <p> * Calling this method twice with the same name silently replaces the old factory with the new one. * @param name the name to use in getInstance(String) to get the instance, if null it replaces * the default ActionUIFactory returned via getInstance(). * @param manager the ActionManager to associate with the newly created ActionUIFactory */ public static ActionUIFactory createNamedInstance(String name, ActionManager manager) { ActionUIFactory factory = new ActionUIFactory(manager); setInstance(name, factory); return factory; } /** * Add a named static ActionUIFactory instance. Typically not needed, but can be useful * if using mulitple named factories and the factories are customized. * <p> * Calling this method twice with the same name silently replaces the old factory with the new one. * @param name the name to use in getInstance(String) to get the instance, if null it replaces * the default ActionUIFactory returned via getInstance(). * @param factory the ActionUIFactory to match to the name */ public static void setInstance(String name, ActionUIFactory factory) { setInstance(name, factory, factory==null?null:factory.actionManager); } /** * Add a named static ActionUIFactory instance with an associated manager. Typically not needed, * but can be useful if using mulitple named managers. * <p> * Calling this method twice with the same name silently replaces the old factory with the new one. * @param name the name to use in getInstance(String) to get the instance, if null it replaces * the default ActionUIFactory returned via getInstance(). * @param factory the ActionUIFactory to match to the name */ public static void setInstance(String name, ActionUIFactory factory, ActionManager manager) { synchronized (INSTANCE_LOCK) { if (NAMED_INSTANCES == null) { NAMED_INSTANCES = Collections.synchronizedMap(new HashMap()); } if (factory != null) { factory.actionManager = manager; } NAMED_INSTANCES.put(name, factory); if (name == null) { INSTANCE = factory; } } } /** * Get a named static ActionUIFactory instance. * @param name the name of the instance as added by setInstance(), if null call is * same as getInstance(); * @return the named ActionUIFactory instance, null if not found. */ public static ActionUIFactory getInstance(String name) { synchronized (INSTANCE_LOCK) { if (NAMED_INSTANCES == null) { if (name == null) { return getInstance(); } else { return null; } } else { return (ActionUIFactory)NAMED_INSTANCES.get(name); } } } /** * Gets the ActionManager this factory uses. If the ActionManager has not been * explicitly set then the default ActionManager instance will be used. * * @return the ActionManager used by the ActionUIFactory. */ public ActionManager getActionManager() { return actionManager; } /** * Set the preferred size of toolbar buttons that are created by the factory. */ public void setToolbarButtonPreferredSize(Dimension toolbarButtonPreferredSize) { this.toolbarButtonPreferredSize = toolbarButtonPreferredSize; } /** * Constructs a new toolbar from an action-list id by getting an ActionList * from the ActionManager and calling {@link #createToolBar(ActionList)}. * By convention, the identifier of the main toolbar should be * "main-toolbar". * <p> * This method depends on the ActionManager and calls getActionList(listId), * on the ActionManager, which creates the actions on first use and reuse * the same actions when another component is created using the same id. * If you want a new set of actions (say, one toolbar for each of two * panels of the same type), then use * {@link #createToolBar(ActionList) createToolBar(List)} with a list * of new Actions (use {@link ActionManager#createActionList(Object) * createActionList(Object)} to create the new set of Actions from an action * list id.) * <p> * @param actionListId action-list id which should be used to construct the toolbar. * The id must have been registered with the ActionManager * @return a new toolbar or null if the id doesn't match a registered * list in the ActionManager */ public JToolBar createToolBar(Object actionListId) { ActionList actions = getActionManager().getActionList(actionListId); if (actions == null) { return null; } //note: treated as 1 dimensional list return createToolBar(actions); } /** * Constructs a new menubar from an action-list id by getting its ActionList * from the ActionManager and calling {@link #createMenuBar(ActionList)}. * By convention, the identifier of the main toolbar should be * "main-toolbar". * <p> * This method depends on the ActionManager and calls getActionList(listId), * on the ActionManager, which creates the actions on first use and reuse * the same actions when another component is created using the same id. * If you want a new set of actions (say, one toolbar for each of two * panels of the same type), then use * {@link #createMenuBar(ActionList) createMenuBar(List)} with a list * of new Actions (use {@link ActionManager#createActionList(Object) * createActionList(Object)} to create the new set of Actions from an action * list id.) * <p> * @param actionListId action-list id which should be used to construct the menubar. * The id must have been registered with the ActionManager * @return a new menubar or null if the id doesn't match a registered * list in the ActionManager */ public JMenuBar createMenuBar(Object actionListId) { ActionList list = getActionManager().getActionList(actionListId); if (list == null) { return null; } JMenuBar menubar = instantiateJMenuBar(); loadActions(list, menubar); return menubar; } /** * Create a toolbar using the list of actions provided. * <p> * Toolbars are 1 dimensional, so sublists in ActionLists are ignored. * <p> * See class documentation as to what is created for different Actions. * <p> * @param actions an ActionList of actions, put a Separator or * null in the list if you want separators * @return a new JToolBar with the actions set. */ public JToolBar createToolBar(ActionList actions) { JToolBar toolBar = instantiateJToolBar(); loadActions(actions, toolBar); return toolBar; } /** * Constructs a new menu bar from an an ActionList. By convention, * the identifier of the main menu bar should be "main-menu-bar". * <p> * Menus and menubars are multi-dimensional, so if the List of Actions has * sub-Lists implemented by ActionList, then menus and submenus are created. * <p> * @param actions action list id which should be used to construct the menu. * Must have been registered with the ActionManager * @return a new JMenuBar or null if the id doesn't match a registered * list in the ActionManager * @return a new JMenu with actions */ public JMenuBar createMenuBar(ActionList actions) { JMenuBar menuBar = instantiateJMenuBar(); loadActions(actions, menuBar); return menuBar; } /** * Constructs a new menu from an action-list id. * <p> * Menus are multi-dimensional, so if the List of Actions has * sub-Lists implemented by ActionList, then submenus are created. * <p> * This method depends on the ActionManager and calls getActionList(listId), * which creates the actions on first use. If you want a new * set of actions (say, for a local menu or popup menu instead of the * frame's main menu, then use {@link #createMenu(ActionList)} * with a list of new Actions * (use {@link ActionManager#createActionList(Object) * createActionList(Object)} to create a new set of Actions from an action * list id.) * <p> * @param listId action-list id which should be used to construct the menu. * Must have been registered with the ActionManager * @return a new JMenu or null if the id doesn't match a registered * list in the ActionManager */ public JMenu createMenu(Object listId) { return createMenu(getActionManager().getActionList(listId)); } /** * Constructs a new menu from an action-list. The action list's * getTriggerActionId() (in XML the idref or a reuse of the aciton-list id * is respected, see the dtd). If the action is not created from the XML, * use createMenu(name, actions) or new ActionList(Object id, String menuName). * <p> * Menus are multi-dimensional, so if the List of Actions has * sub-Lists implemented by ActionList, then submenus are created. * <p> * This method depends on the ActionManager and calls getActionList(listId), * which creates the actions on first use. If you want a new * set of actions (say, for a local menu or popup menu instead of the * frame's main menu, then use {@link #createMenu(ActionList)} * with a list of new Actions * (use {@link ActionManager#createActionList(Object) * createActionList(Object)} to create a new set of Actions from an action * list id.) * <p> * @param actions action list which should be used to construct the menu. * Must have been registered with the ActionManager * @return a new JMenu or null if the id doesn't match a registered * list in the ActionManager */ public JMenu createMenu(ActionList actions) { if (actions == null) { return null; } //This extra if exists to the menu can respect the ActionList's //trigger action. Action triggerAction = getActionManager().getAction(actions.getTriggerActionId()); return createMenu(triggerAction, actions); } /** * Creates a (multilevel) menu and calls loadActions for it with the list * of actions. * @param menuTriggerAction the action for the menu itself (the File Action * or Edit Action ...) * @param actions a list of actions for each menu item. If an entry in * the list is an {@link ActionList}, then a submenu is created with the * actions in the sub List as entries. * @return a new JMenu with the actions set, no actions set if there * are no actions for the group (and empty menubar is returned) */ public JMenu createMenu(Action menuTriggerAction, ActionList actions) { JMenu menu = instantiateJMenu(menuTriggerAction); loadActions(menu, actions); return menu; } /** * Same as {@link #createMenu(javax.swing.Action, ActionList)}, * except the menu itself only has a name, not an action. If set, the * action list's trigger id is ignored. * @param menuName The name of the menu. * @param actions an ActionList of actions, ActionLists, * or a Separator or null for separators * @return a new JMenu with the actions set. */ public JMenu createMenu(String menuName, ActionList actions) { JMenu menu = instantiateJMenu(menuName); loadActions(menu, actions); return menu; } /** * Constructs a new popup menu from an action-list id. * <p> * Menus are multi-dimensional, so if the List of Actions has * sub-Lists implemented by ActionList, then submenus are created. * <p> * This method depends on the ActionManager and calls getActionList(listId), * which creates the actions on first use. If you want a new * set of actions (say, for a two popup menus on different views instead of, * then use {@link #createPopupMenu(ActionList)} twice * with a list of new Actions for each call * (use {@link ActionManager#createActionList(Object) * createActionList(Object)} to create a new set of Actions from an action * list id). * <p> * @param listId action-list id which should be used to construct the menu. * Must have been registered with the ActionManager * @return a new JPopupMenu or null if the id doesn't match a registered * list in the ActionManager */ public JPopupMenu createPopupMenu(Object listId) { ActionList actions = getActionManager().getActionList(listId); if (actions == null) { return null; } return createPopupMenu(actions); } /** * Create a popup menu using the list of actions provided. * @param list an ActionList of actions, put a Separator or * null in the list if you want separators * @return a new JToolBar with the actions set. */ public JPopupMenu createPopupMenu(ActionList list) { JPopupMenu popup = new JPopupMenu(); loadActions(popup, list); return popup; } /** * Creates a menu item based on an action id by looking up the Action in * the ActionManager and calling {@link #createMenuItem(Action)} * @param id the id of the action as registered with the ActionManager * @return a JMenuItem based onthe action */ private JMenuItem createMenuItem(Object id) { Action action = getActionManager().getAction(id); if (action == null) { return null; } JMenuItem menuItem = createMenuItem(action); return menuItem; } /** * Creates a menu item based on the action. * Will return a JMenuItem, JRadioButtonMenuItem or a JCheckBoxMenuItem. * <p> * Will return a JRadioButtonMenuItem if action.getValue(ActionManager.GROUP) * is non-null. If ActionManager.GROUP is not null then the type depends * on the ActionManager.BUTTON_TYPE property: * <ul> * <li>null -> JButton * <li>ActionManager.BUTTON_TYPE_VALUE_TOGGLE -> JCheckBoxMenuItem * <li>ActionManager.BUTTON_TYPE_VALUE_RADIO -> JRadioMenuItem * <li>ActionManager.BUTTON_TYPE_VALUE_CHECKBOX -> JCheckBoxMenuItem * <p> * <p> * The menu items are created via the instantiateXXX methods, allowing * derived classes a hook into the types of button this facotry creates. * After the button is created, the configureButton methods is called * allowing derived classes a hook into setting up created buttons. * * @return a JMenuItem or subclass depending on type. * @todo throw excpetion for useCheckBox and group - but in DTD/Schema */ public JMenuItem createMenuItem(Action action) { JMenuItem menuItem; String buttonType = ""+action.getValue(ActionManager.BUTTON_TYPE); if (action.getValue(ActionManager.GROUP) != null) { menuItem = instantiateCheckBoxMenuItem(action); } else if (ActionManager.BUTTON_TYPE_VALUE_TOGGLE.equals(buttonType)) { menuItem = instantiateCheckBoxMenuItem(action); } else if (ActionManager.BUTTON_TYPE_VALUE_RADIO.equals(buttonType)) { menuItem = instantiateRadioButtonMenuItem(action); } else if (ActionManager.BUTTON_TYPE_VALUE_CHECKBOX.equals(buttonType)) { menuItem = instantiateCheckBoxMenuItem(action); } else { menuItem = instantiateJMenuItem(action); } configureMenuItem(menuItem); return menuItem; } /** * Creates a button based on an action id by looking up the Action in * the ActionManager and calling {@link #createButton(Action)} * @param id the id of the action as registered with the ActionManager * @return a JButton based on the action */ public AbstractButton createButton(Object id) { Action action = getActionManager().getAction(id); if (action == null) { return null; } else { return createButton(action); } } /** * Creates a button based on the action. * Will return a JButton, JRadioButton or a JCheckBox. * <p> * Will return a JRadioButton if action.geValue(ActionManager.GROUP) * is non-null. If ActionManager.GROUP is not null then the type depends * on the ActionManager.BUTTON_TYPE property: * <ul> * <li>null -> JButton * <li>ActionManager.BUTTON_TYPE_VALUE_TOGGLE -> JToggleButton * <li>ActionManager.BUTTON_TYPE_VALUE_RADIO -> JRadioButton * <li>ActionManager.BUTTON_TYPE_VALUE_CHECKBOX -> JCheckBox * <p> * The buttons are created via the instantiateXXX methods, allowing * derived classes a hook into the types of button this factory creates. * After the button is created, the configureButton methods is called * allowing derived classes a hook into setting up created buttons. * * @return a JButton or subclass depending on above * @todo throw excpetion for useCheckBox and group - but in DTD/Schema */ public AbstractButton createButton(Action action) { AbstractButton button = null; Object buttonType = action.getValue(ActionManager.BUTTON_TYPE); if (action.getValue(ActionManager.GROUP) != null) { button = instantiateToggleButton(action); } else if (ActionManager.BUTTON_TYPE_VALUE_TOGGLE.equals(buttonType)) { button = instantiateToggleButton(action); } else if (ActionManager.BUTTON_TYPE_VALUE_RADIO.equals(buttonType)) { button = instantiateRadioButton(action); } else if (ActionManager.BUTTON_TYPE_VALUE_CHECKBOX.equals(buttonType)) { button = instantiateJCheckBox(action); } else { button = instantiateJButton(action); } configureToolBarButton(button); return button; } /** * This hook method will be called after buttons are instantiated from an * action. Override for custom configuration. * * @param button the button to be configured */ protected void configureToolBarButton(AbstractButton button) { commonConfig(button); // Don't show the text under the toolbar buttons. button.setText(""); Action action = button.getAction(); if (action != null) { if (action.getValue(Action.SHORT_DESCRIPTION) == null) { button.setToolTipText((String) action.getValue(Action.NAME)); } if (action instanceof BasicAction && !((BasicAction) action).getToolbarShowsText()) { button.setText(""); } } if (toolbarButtonPreferredSize != null) { button.setPreferredSize(toolbarButtonPreferredSize); button.setMaximumSize(toolbarButtonPreferredSize); } else if (sSetButtonSizeFor13) { button.setPreferredSize(new Dimension(32, 32)); //the size of the 1.4 icons button.setMaximumSize(new Dimension(32, 32)); //the size of the 1.4 icons } if (sToolbarRequestFocusEnabled14) { button.setRequestFocusEnabled(false); } } /** * This method will be called after menu items are created. * Override for custom configuration. Overrides should start with * super.configureMenuItem(), since this method does significant work. * <p> * Specifically, menu items are configured by * <ul> * <li>Setting the menu's action command to the action's Action.ACTION_COMMAND_KEY property * <li>Respecting the ActionManager.MENU_SHOWS_ICON so that toolbars can * show the action's icon and not the menu. * <li>If the menu's action is an * <p> * * @param menuItem the menu item to be configured * @see #createMenuItem(Action) * @todo except if action with TOGGLE does not implement ItemListener */ protected void configureMenuItem(JMenuItem menuItem) { commonConfig(menuItem); Action action = menuItem.getAction(); if (action == null) { return; } //respect the action's show-the-icon-in-a-menu property try { Boolean shows = (Boolean) action.getValue(ActionManager.MENU_SHOWS_ICON); if (shows != null && !shows.booleanValue()) { menuItem.setIcon(null); } } catch (ClassCastException ex) { //todo -warn } } /** * Common configuration for buttons and menus * @param buttonOrMenuItem the button to configure */ private void commonConfig(AbstractButton buttonOrMenuItem) { Action action = buttonOrMenuItem.getAction(); if (action == null) { return; } // Need to explicitly set the action command key property as //this is not set by default in AbstractButton. buttonOrMenuItem.setActionCommand((String) action.getValue(Action.ACTION_COMMAND_KEY)); if (isShouldSyncSelectedProperty(buttonOrMenuItem, action)) { ActionSelectionSynchronizer syncher = new ActionSelectionSynchronizer(buttonOrMenuItem, action); } Boolean selected = (Boolean)action.getValue(ActionManager.SELECTED); if (selected != null) { buttonOrMenuItem.setSelected(selected.booleanValue()); } } /** * This method determines if an action and the components created from it * have their selected states synchronized. For example, a toggle button and * a check box menu item sharing an action should have their selected * states synchronized (one checked the other pushed in). By default all * components created for actions are synched. * @param buttonOrMenuItem that will or will not be synced * @param action the action in question */ protected boolean isShouldSyncSelectedProperty(AbstractButton buttonOrMenuItem, Action action) { return true; } /** * When a JToolBar needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized toolbars. * @return new JToolBar(); */ protected JToolBar instantiateJToolBar() { JToolBar toolBar = new JToolBar(); return toolBar; } /** * When a JMenuBar needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized menu bars. * @return new JMenuBar(); */ protected JMenuBar instantiateJMenuBar() { JMenuBar menubar = new JMenuBar(); return menubar; } /** * When a JMenu needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized menus. * @param menuAction the menu's action that gets triggered when the * menu pops up, can be null * @return new JMenu(itemAction); */ protected JMenu instantiateJMenu(Action menuAction) { JMenu menu = new JMenu(menuAction); return menu; } /** * When a JMenu needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized menus. * @param menuName the menu's name * @return new JMenu(itemAction); */ protected JMenu instantiateJMenu(String menuName) { JMenu menu = new JMenu(menuName); return menu; } /** * When a regular JMenuItem needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized menu items. * @return new JMenuItem(itemAction); */ protected JMenuItem instantiateJMenuItem(Action itemAction) { return new JMenuItem(itemAction); } /** * When a RadioButtonMenuItem needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized menu items. * @return new JRadioButtonMenuItem(itemAction); */ protected JRadioButtonMenuItem instantiateRadioButtonMenuItem(Action itemAction) { return new JRadioButtonMenuItem(itemAction); } /** * When a CheckBoxMenuItem needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized menu items. * @return new JCheckBoxMenuItem(itemAction); */ protected JCheckBoxMenuItem instantiateCheckBoxMenuItem(Action itemAction) { return new JCheckBoxMenuItem(itemAction); } /** * When a regular JButton needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized toolbar buttons. * @return new JButton(action); */ protected JButton instantiateJButton(Action action) { return new JButton(action); } /** * When a JCheckBox toobar button needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized toolbar buttons. * @param action the buttons's action * @return new JButton(action); */ protected JCheckBox instantiateJCheckBox(Action action) { JCheckBox menu = new JCheckBox(action); return menu; } /** * When a JToggleButton needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized toolbar buttons * @return new JToggleButton(action); */ protected JToggleButton instantiateToggleButton(Action action) { return new JToggleButton(action); } /** * When a JRadioButton needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized toolbar buttons * @return new JRadioButton(action); */ protected JRadioButton instantiateRadioButton(Action action) { return new JRadioButton(action); } /** * When a JSeparator needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized toolbar buttons * @return a new instance of the JToolbar's default separator */ protected JSeparator instantiateSeparator() { return new JToolBar.Separator(null); } /** * When an invisible JSeaprator needs to be created by the factory, this * method is called. Available to allow derived classes to create their * own specialized toolbar buttons * @return a new instance of the JToolbar's default separator, but with * the foreground color set to the background color. This is used * byt hte JSeparatorUI */ protected JSeparator instantiateInvisibleSeparator() { return new JToolBar.Separator(null) { public Color getForeground() { return getBackground(); } }; } /** * Loads a toolbar with a list of actions. * @param actions a List of actions, add in null or a Separator * if you want separators * @param toolBar the JToolBar to set the actions on */ public void loadActions(ActionList actions, JToolBar toolBar) { if (actions == null) { return; } HashMap buttonGroupsByGroupID = new HashMap(); Iterator iter = actions.iterator(); while (iter.hasNext()) { Object elem = iter.next(); if (elem == null || elem instanceof Separator) { if (elem instanceof Separator && !((Separator)elem).isLineVisible()) { toolBar.add(instantiateSeparator()); } else { toolBar.add(instantiateInvisibleSeparator()); } } else { Action action = (Action) elem; AbstractButton button = createButton(action); toolBar.add(button); if (action.getValue(ActionManager.GROUP) != null) { ButtonGroup buttonGroup = (ButtonGroup)buttonGroupsByGroupID.get(action.getValue(ActionManager.GROUP)); if (buttonGroup == null) { buttonGroup = new ButtonGroup(); buttonGroupsByGroupID.put(action.getValue(ActionManager.GROUP), buttonGroup); } buttonGroup.add(button); } } } if (sToolbarRequestFocusEnabled14) { toolBar.setRequestFocusEnabled(false); } } private void loadActions(ActionList list, JMenuBar menubar) { JMenu menu = null; Iterator iter = list.iterator(); while (iter.hasNext()) { Object element = iter.next(); if (element == null || element instanceof Separator) { if (menu != null) { menu.addSeparator(); } } else if (element instanceof ActionList) { menu = createMenu((ActionList) element); if (menu != null) { menubar.add(menu); } } else { if (menu != null) { if (element instanceof Action) { menu.add(createMenuItem((Action) element)); } else { //assume it is an action id menu.add(createMenuItem(element)); } } } } } private void loadActions(JMenu menu, ActionList actions) { Iterator iter = actions.iterator(); while(iter.hasNext()) { Object element = iter.next(); if (element == null || element instanceof Separator) { menu.addSeparator(); } else if (element instanceof ActionList) { JMenu newMenu = createMenu((ActionList)element); if (newMenu != null) { menu.add(newMenu); } } else if (element instanceof Action) { menu.add(createMenuItem((Action)element)); } else { //assume it is an action id menu.add(createMenuItem(element)); } } } private void loadActions(JPopupMenu popup, ActionList actions) { HashMap buttonGroups = new HashMap(); Iterator iter = actions.iterator(); while(iter.hasNext()) { Object element = iter.next(); if (element == null || element instanceof Separator) { popup.addSeparator(); } else if (element instanceof ActionList) { JMenu newMenu = createMenu((ActionList)element); if (newMenu != null) { popup.add(newMenu); } } else if (element instanceof Action) { JMenuItem mi = createMenuItem((Action)element); handleButtonGroups(mi, buttonGroups); popup.add(mi); } else { //assume it is an action id JMenuItem mi = createMenuItem(element); handleButtonGroups(mi, buttonGroups); popup.add(mi); } } } private void handleButtonGroups(AbstractButton buttonOrMenu, Map buttonGroups) { if (buttonOrMenu == null) { return; } if (buttonOrMenu.getAction() != null) { Object group = buttonOrMenu.getAction().getValue(ActionManager.GROUP); if (group != null) { ButtonGroup bg = (ButtonGroup) buttonGroups.get(group); if (bg == null) { bg = new ButtonGroup(); buttonGroups.put(group, bg); } bg.add(buttonOrMenu); } } } }