001/* An abstract menu factory that creates context menus using item factories
002
003 Copyright (c) 2003-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.tree;
029
030import java.awt.event.MouseAdapter;
031import java.awt.event.MouseEvent;
032import java.util.Collections;
033import java.util.Iterator;
034import java.util.LinkedList;
035import java.util.List;
036
037import javax.swing.tree.TreePath;
038
039import diva.gui.toolbox.JContextMenu;
040import ptolemy.kernel.util.NamedObj;
041import ptolemy.vergil.toolbox.MenuItemFactory;
042
043///////////////////////////////////////////////////////////////////
044//// PTreeMenuCreator
045
046/**
047 A mouse listener that creates context menus for a PTree using menu
048 item factories.  When asked to create a context menu, This class
049 determines the ptolemy object associated with the point in the tree
050 that was clicked on.  Then it passes the ptolemy object to each menu
051 item factory that it contains to add the menu items.  Lastly, it pops
052 up the resulting menu.
053
054 @author Steve Neuendorffer
055 @version $Id$
056 @since Ptolemy II 4.0
057 @Pt.ProposedRating Red (eal)
058 @Pt.AcceptedRating Red (johnr)
059 */
060public class PTreeMenuCreator extends MouseAdapter {
061    /** Create a new menu factory that contains no menu item factories.
062     */
063    public PTreeMenuCreator() {
064        _factoryList = new LinkedList();
065    }
066
067    ///////////////////////////////////////////////////////////////////
068    ////                         public methods                    ////
069
070    /** Add a menu item factory to this creator.
071     *  @param factory The menu item factory to add.
072     */
073    public void addMenuItemFactory(MenuItemFactory factory) {
074        _factoryList.add(factory);
075    }
076
077    /** Create an instance of the menu associated with this factory.
078     *  @param e The mouse event.  If the mouse event is
079     *  a popup event, then menu is created and shown.
080     */
081    @Override
082    public void mousePressed(MouseEvent e) {
083        _doEvent(e);
084    }
085
086    /** Create an instance of the menu associated with this factory.
087     *  @param e The mouse event.  If the mouse event is
088     *  a popup event, then menu is created and shown.
089     */
090    @Override
091    public void mouseReleased(MouseEvent e) {
092        _doEvent(e);
093    }
094
095    /** Return the list of menu item factories.
096     * @return An unmodifiable list.
097     */
098    public List menuItemFactoryList() {
099        return Collections.unmodifiableList(_factoryList);
100    }
101
102    /** Remove the given menu item factory from the factory list.
103     *  @param factory The factory to be removed.
104     */
105    public void removeMenuItemFactory(MenuItemFactory factory) {
106        _factoryList.remove(factory);
107    }
108
109    /** Remove all MenuItemFactories from the factory list.
110     */
111    public void clear() {
112        _factoryList.clear();
113    }
114
115    ///////////////////////////////////////////////////////////////////
116    ////                         private methods                   ////
117
118    /** Process a mousePressed or mouseReleased event.
119     */
120    private void _doEvent(MouseEvent e) {
121        if (!e.isPopupTrigger()) {
122            return;
123        }
124
125        PTree tree = (PTree) e.getComponent();
126        TreePath treePath = tree.getPathForLocation(e.getX(), e.getY());
127        if (treePath == null) {
128            // On the Mac under Java 1.5.0_22, treePath can be null.
129            // 1) Start vergil
130            // 2) Open Actors -> Sources -> GenericSources
131            // 3) Drag a Const into the canvas
132            // 4) Place the mouse over the Const actor and quickly
133            // use two finger to signal a right click.
134
135            // An exception appears:
136            // Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
137            //         at ptolemy.vergil.tree.PTreeMenuCreator._doEvent(PTreeMenuCreator.java:119)
138            //         at ptolemy.vergil.tree.PTreeMenuCreator.mousePressed(PTreeMenuCreator.java:82)
139            //         at java.awt.AWTEventMulticaster.mousePressed(AWTEventMulticaster.java:222)
140            //         at java.awt.Component.processMouseEvent(Component.java:5599)
141            //         at javax.swing.JComponent.processMouseEvent(JComponent.java:3129)
142            //         at java.awt.Component.processEvent(Component.java:5367)
143            //         at java.awt.Container.processEvent(Container.java:2010)
144            //         at java.awt.Component.dispatchEventImpl(Component.java:4068)
145            //         at java.awt.Container.dispatchEventImpl(Container.java:2068)
146            //         at java.awt.Component.dispatchEvent(Component.java:3903)
147            //         at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4256)
148            //         at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3933)
149            //         at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3866)
150            //         at java.awt.Container.dispatchEventImpl(Container.java:2054)
151            //         at java.awt.Window.dispatchEventImpl(Window.java:1801)
152            //         at java.awt.Component.dispatchEvent(Component.java:3903)
153            //         at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
154            //         at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:269)
155            //         at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
156            //         at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:184)
157            //         at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:176)
158            //         at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)
159
160            // I think the problem here is that the actor pane has the focus when
161            // the mouse click occurs.
162            return;
163        }
164        Object object = treePath.getLastPathComponent();
165
166        if (object instanceof NamedObj) {
167            NamedObj namedObj = (NamedObj) object;
168            JContextMenu menu = new JContextMenu(namedObj,
169                    namedObj.getFullName());
170            Iterator i = menuItemFactoryList().iterator();
171
172            while (i.hasNext()) {
173                MenuItemFactory factory = (MenuItemFactory) i.next();
174                factory.create(menu, namedObj);
175            }
176
177            menu.show(tree, e.getX(), e.getY());
178            e.consume();
179        }
180    }
181
182    ///////////////////////////////////////////////////////////////////
183    ////                     private members                       ////
184
185    /** The menu item factories.
186     */
187    private List _factoryList;
188}