001/* A menu item factory that creates actions for firing actions
002
003 Copyright (c) 2000-2016 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.vergil.toolbox;
029
030import java.lang.ref.WeakReference;
031import java.util.Iterator;
032import java.util.LinkedList;
033import java.util.List;
034
035import javax.swing.Action;
036import javax.swing.JMenu;
037import javax.swing.JMenuItem;
038
039import diva.gui.toolbox.JContextMenu;
040import ptolemy.kernel.util.NamedObj;
041
042///////////////////////////////////////////////////////////////////
043//// MenuActionFactory
044
045/**
046 A factory that adds a given action or set of actions
047 to a context menu. If an array of actions is given to
048 the constructor, then the actions will be put in a submenu
049 with the specified label.
050
051 @author Steve Neuendorffer
052 @version $Id$
053 @since Ptolemy II 1.0
054 @Pt.ProposedRating Red (eal)
055 @Pt.AcceptedRating Red (johnr)
056 */
057public class MenuActionFactory implements MenuItemFactory {
058    /** Construct a factory that adds a given action to a given context menu.
059     *  @param action The action to be associated with the context menu.
060     */
061    public MenuActionFactory(Action action) {
062        _action = action;
063    }
064
065    /** Construct a factory that adds a given group of actions
066     *  to a given context menu in a submenu with the specified label.
067     *  @param actions The actions to be in the submenu.
068     *  @param label The label for the submenu.
069     */
070    public MenuActionFactory(Action[] actions, String label) {
071        _actions = actions;
072        _label = label;
073    }
074
075    /** Add an action to the pre-existing group of actions.
076     *  @param action The action to add.
077     */
078    public void addAction(Action action) {
079        addAction(action, null);
080    }
081
082    /** Add an action to the pre-existing group of actions.
083     *  If this was constructed with the single argument, then this
084     *  converts the menu action into a submenu with the specified label.
085     *  @param action The action to add.
086     *  @param label The label to give to the menu group.
087     */
088    public void addAction(Action action, String label) {
089        if (_action != null) {
090            // Previously, there was only one action.
091            // Convert to a subaction.
092            _actions = new Action[2];
093            _actions[0] = _action;
094            _actions[1] = action;
095            _action = null;
096        } else {
097            // Create a new actions array.
098            Action[] newActions = new Action[_actions.length + 1];
099            System.arraycopy(_actions, 0, newActions, 0, _actions.length);
100            newActions[_actions.length] = action;
101            _actions = newActions;
102        }
103        if (label != null) {
104            _label = label;
105        }
106    }
107
108    /** Add a set of action to the pre-existing group of actions.
109     *  If this was constructed with the single argument, then this
110     *  converts the menu action into a submenu with the specified label.
111     *  @param actions The actions to add.
112     *  @param label The label to give to the menu group if it
113     *   previously not a menu group.
114     */
115    public void addActions(Action[] actions, String label) {
116        int start = 0;
117        if (_action != null) {
118            // Previously, there was only one action.
119            // Convert to a subaction.
120            _actions = new Action[actions.length + 1];
121            _actions[0] = _action;
122            start = 1;
123            _action = null;
124        } else {
125            Action[] newActions = new Action[_actions.length + actions.length];
126            System.arraycopy(_actions, 0, newActions, 0, _actions.length);
127            start = _actions.length;
128            _actions = newActions;
129        }
130        System.arraycopy(actions, 0, _actions, start, actions.length);
131        _label = label;
132    }
133
134    /** Add a menu item listener to the list of menu item listeners.
135     *
136     *  @param listener The menu item listener.
137     */
138    public void addMenuItemListener(MenuItemListener listener) {
139        if (_menuItemListeners == null) {
140            _menuItemListeners = new LinkedList();
141        }
142        _menuItemListeners.add(new WeakReference(listener));
143    }
144
145    /** Add an item to the given context menu that will configure the
146     *  parameters on the given target.
147     *  @param menu The context menu to add to.
148     *  @param object The object that the menu item command will operate on.
149     *  @return A menu item, or null to decline to provide a menu item.
150     */
151    @Override
152    public JMenuItem create(JContextMenu menu, NamedObj object) {
153        JMenuItem menuItem;
154        if (_action != null) {
155            // Single action as a simple menu entry.
156            menuItem = _add(menu, _action,
157                    (String) _action.getValue(Action.NAME));
158        } else {
159            // Requested a submenu with a group of actions.
160            final JMenu submenu = new JMenu(_label);
161            menu.add(submenu, _label);
162            for (Action _action2 : _actions) {
163                _add(submenu, _action2);
164            }
165            menuItem = submenu;
166        }
167        if (_menuItemListeners != null) {
168            Iterator listeners = _menuItemListeners.iterator();
169            while (listeners.hasNext()) {
170                WeakReference reference = (WeakReference) listeners.next();
171                Object contents = reference.get();
172                if (contents instanceof MenuItemListener) {
173                    ((MenuItemListener) contents).menuItemCreated(menu, object,
174                            menuItem);
175                }
176            }
177        }
178        return menuItem;
179    }
180
181    /** Substitute the old action with the new action, if the old action is
182     *  added to this factory.
183     *  @param oldAction The old action.
184     *  @param newAction The new action.
185     *  @return true if the old action is found and is substituted; false if the
186     *  old action is not added to this factory.
187     */
188    public boolean substitute(Action oldAction, Action newAction) {
189        if (_action != null) {
190            if (_action == oldAction) {
191                _action = newAction;
192                return true;
193            } else {
194                return false;
195            }
196        } else {
197            for (int i = 0; i < _actions.length; i++) {
198                if (_actions[i] == oldAction) {
199                    _actions[i] = newAction;
200                    return true;
201                }
202            }
203            return false;
204        }
205    }
206
207    /** Add an action to the context menu.
208     *  @param menu The context menu.
209     *  @param action The action to be added to the context menu.
210     *  @param tooltip The tooltip for the action.
211     *  @return The added menu item.
212     */
213    protected JMenuItem _add(JContextMenu menu, Action action, String tooltip) {
214        return menu.add(action, tooltip);
215    }
216
217    /** Add an action to the submenu.
218     *  @param submenu The submenu.
219     *  @param action The action to be added to the submenu.
220     *  @return The added menu item.
221     */
222    protected JMenuItem _add(JMenu submenu, Action action) {
223        return submenu.add(action);
224    }
225
226    ///////////////////////////////////////////////////////////////////
227    ////                         private variables                 ////
228
229    /** The action that will be added to the context menu. */
230    private Action _action;
231
232    /** The group of actions that will be added in a submenu. */
233    private Action[] _actions;
234
235    /** The submenu label, if one was given. */
236    private String _label;
237
238    /** the list of menu item listeners. */
239    private List _menuItemListeners;
240}