View Javadoc

1   /*
2    * TouchGraph LLC. Apache-Style Software License
3    *
4    *
5    * Copyright (c) 2001-2002 Alexander Shapiro. All rights reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer. 
13   *
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in
16   *    the documentation and/or other materials provided with the
17   *    distribution.
18   *
19   * 3. The end-user documentation included with the redistribution,
20   *    if any, must include the following acknowledgment:  
21   *       "This product includes software developed by 
22   *        TouchGraph LLC (http://www.touchgraph.com/)."
23   *    Alternately, this acknowledgment may appear in the software itself,
24   *    if and wherever such third-party acknowledgments normally appear.
25   *
26   * 4. The names "TouchGraph" or "TouchGraph LLC" must not be used to endorse 
27   *    or promote products derived from this software without prior written 
28   *    permission.  For written permission, please contact 
29   *    alex@touchgraph.com
30   *
31   * 5. Products derived from this software may not be called "TouchGraph",
32   *    nor may "TouchGraph" appear in their name, without prior written
33   *    permission of alex@touchgraph.com.
34   *
35   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38   * DISCLAIMED.  IN NO EVENT SHALL TOUCHGRAPH OR ITS CONTRIBUTORS BE 
39   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
40   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
41   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
42   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
43   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
44   * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
45   * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46   * ====================================================================
47   *
48   */
49  
50  package com.touchgraph.graphlayout.interaction;
51  
52  import java.awt.event.*;
53  
54  import javax.swing.*;
55  import javax.swing.event.*;
56  
57  import com.touchgraph.graphlayout.*;
58  
59  /*** GLEditUI:  User Interface for editing the graph.
60    *
61    * @author   Alexander Shapiro
62    * @version  1.21  $Id: GLEditUI.java,v 1.1.1.1 2004/02/06 08:44:07 keesj Exp $
63    */
64  public class GLEditUI extends TGUserInterface {
65  
66      /*** True when the current UI is active. */
67      
68      TGPanel tgPanel;
69      DragAddUI dragAddUI;
70      DragNodeUI dragNodeUI;
71      DragMultiselectUI dragMultiselectUI;
72      TGAbstractClickUI switchSelectUI;
73      TGAbstractDragUI hvDragUI;
74  
75      GLEditMouseListener ml;
76      GLEditMouseMotionListener mml;
77  
78      JPopupMenu nodePopup;
79      JPopupMenu edgePopup;
80      JPopupMenu backPopup;
81      Node popupNode;
82      Edge popupEdge;
83  
84      AbstractAction deleteSelectAction;
85      final KeyStroke deleteKey = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
86  
87    // ............
88  
89     /*** Constructor with TGPanel <tt>tgp</tt>.
90       */
91      public GLEditUI( TGPanel tgp ) {
92          active = false;
93          tgPanel = tgp;
94  
95          ml = new GLEditMouseListener();
96          mml = new GLEditMouseMotionListener();
97  
98          deleteSelectAction = new AbstractAction("DeleteSelect") {
99              public void actionPerformed(ActionEvent e) {
100                 Node select = tgPanel.getSelect();
101                 if(select!=null) {
102                     tgPanel.deleteNode(select);
103                     tgPanel.repaint();
104                 }
105             }
106         };
107 
108         dragAddUI = new DragAddUI(tgPanel);
109         dragNodeUI = new DragNodeUI(tgPanel);
110         dragMultiselectUI = new DragMultiselectUI(tgPanel);
111         switchSelectUI = tgPanel.getSwitchSelectUI();
112 
113         setUpNodePopup();
114         setUpEdgePopup();
115         setUpBackPopup();
116     }
117 
118     public GLEditUI( GLPanel glPanel ) {
119         this(glPanel.getTGPanel());
120         hvDragUI = glPanel.hvScroll.getHVDragUI();
121     }
122 
123     public void activate() {
124         tgPanel.addMouseListener(ml);
125         tgPanel.addMouseMotionListener(mml);
126         tgPanel.getActionMap().put("DeleteSelect", deleteSelectAction);
127         ComponentInputMap cim = new ComponentInputMap(tgPanel);
128         cim.put(deleteKey, "DeleteSelect");
129         tgPanel.setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, cim);
130         active = true;
131     }
132 
133     public void deactivate() {
134         //A hack.  Want to prevent dragMultiselect from remaining active when user switches to
135         //navigate mode.  Keeping an "active" variable resolves some comlex issues with the flow
136         //of controll, caused by dragMultiselect calling it's parents deactivate method when it
137         //is activated.
138         if (!active) dragMultiselectUI.deactivate();
139 
140         tgPanel.removeMouseListener(ml);
141         tgPanel.removeMouseMotionListener(mml);
142         tgPanel.getInputMap().put(deleteKey, null);
143         tgPanel.getActionMap().put("DeleteSelect", null);
144         active = false;
145     }
146 
147     class GLEditMouseListener extends MouseAdapter {
148         public void mousePressed(MouseEvent e) {
149             Node mouseOverN = tgPanel.getMouseOverN();
150             Node select = tgPanel.getSelect();
151 
152 
153             if (e.getModifiers() == MouseEvent.BUTTON1_MASK) {
154                 if (mouseOverN != null) {
155                     if(mouseOverN!=select)
156                         dragNodeUI.activate(e);
157                     else
158                         dragAddUI.activate(e);
159                 }
160                 else
161                     if(hvDragUI!=null) hvDragUI.activate(e);
162             }
163 
164         }
165 
166         public void mouseClicked(MouseEvent e) {
167             if (e.getModifiers() == MouseEvent.BUTTON1_MASK)
168                 switchSelectUI.activate(e);
169 
170         }
171 
172         public void mouseReleased(MouseEvent e) {
173               if (e.isPopupTrigger()) {
174                    popupNode = tgPanel.getMouseOverN();
175                    popupEdge = tgPanel.getMouseOverE();
176                    if (popupNode!=null) {
177                        tgPanel.setMaintainMouseOver(true);
178                     nodePopup.show(e.getComponent(), e.getX(), e.getY());
179                 }
180                 else if (popupEdge!=null) {
181                     tgPanel.setMaintainMouseOver(true);
182                     edgePopup.show(e.getComponent(), e.getX(), e.getY());
183                 }
184                 else {
185                     backPopup.show(e.getComponent(), e.getX(), e.getY());
186                 }
187                }
188          }
189     }
190 
191     class GLEditMouseMotionListener extends MouseMotionAdapter {
192         public void mouseMoved(MouseEvent e) {
193             //tgPanel.startDamper();
194         }
195     }
196 
197     private void setUpNodePopup() {
198         nodePopup = new JPopupMenu();
199         JMenuItem menuItem;
200         JMenu navigateMenu = new JMenu("Navigate");
201 
202         menuItem = new JMenuItem("Delete Node");
203         ActionListener deleteNodeAction = new ActionListener() {
204                 public void actionPerformed(ActionEvent e) {
205                     if(popupNode!=null) {
206                         tgPanel.deleteNode(popupNode);
207                     }
208                 }
209             };
210 
211         menuItem.addActionListener(deleteNodeAction);
212         nodePopup.add(menuItem);
213 
214         menuItem = new JMenuItem("Expand Node");
215         ActionListener expandAction = new ActionListener() {
216                 public void actionPerformed(ActionEvent e) {
217                     if(popupNode!=null) {
218                         tgPanel.expandNode(popupNode);
219                     }
220                 }
221             };
222 
223         menuItem.addActionListener(expandAction);
224         navigateMenu.add(menuItem);
225 
226         menuItem = new JMenuItem("Collapse Node");
227         ActionListener collapseAction = new ActionListener() {
228                 public void actionPerformed(ActionEvent e) {                    
229                     if(popupNode!=null) {
230                         tgPanel.collapseNode(popupNode );
231                     }
232                 }
233             };
234 
235         menuItem.addActionListener(collapseAction);
236         navigateMenu.add(menuItem);
237             
238         menuItem = new JMenuItem("Hide Node");
239         ActionListener hideAction = new ActionListener() {
240                 public void actionPerformed(ActionEvent e) {
241                     Node select = tgPanel.getSelect();
242                     if(popupNode!=null) {
243                         tgPanel.hideNode(popupNode);
244                     }
245                 }
246             };
247                                
248         menuItem.addActionListener(hideAction);
249         navigateMenu.add(menuItem);
250 
251         nodePopup.add(navigateMenu);
252 
253         nodePopup.addPopupMenuListener(new PopupMenuListener() {
254             public void popupMenuCanceled(PopupMenuEvent e) {}
255             public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
256                 tgPanel.setMaintainMouseOver(false);
257                 tgPanel.setMouseOverN(null);
258                 tgPanel.repaint();
259             }
260             public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
261         });
262 
263     }
264 
265     private void setUpEdgePopup() {
266         edgePopup = new JPopupMenu();
267         JMenuItem menuItem;
268 
269         menuItem = new JMenuItem("Relax Edge");
270         ActionListener relaxEdgeAction = new ActionListener() {
271                 public void actionPerformed(ActionEvent e) {
272                     if(popupEdge!=null) {
273                         popupEdge.setLength(popupEdge.getLength()*4);
274                         tgPanel.resetDamper();
275                     }
276                 }
277             };
278         menuItem.addActionListener(relaxEdgeAction);
279         edgePopup.add(menuItem);
280 
281         menuItem = new JMenuItem("Tighten Edge");
282         ActionListener tightenEdgeAction = new ActionListener() {
283                 public void actionPerformed(ActionEvent e) {
284                     if(popupEdge!=null) {
285                         popupEdge.setLength(popupEdge.getLength()/4);
286                         tgPanel.resetDamper();
287                     }
288                 }
289             };
290         menuItem.addActionListener(tightenEdgeAction);
291         edgePopup.add(menuItem);
292 
293         menuItem = new JMenuItem("Delete Edge");
294         ActionListener deleteEdgeAction = new ActionListener() {
295                 public void actionPerformed(ActionEvent e) {
296                     if(popupEdge!=null) {
297                         tgPanel.deleteEdge(popupEdge);
298                     }
299                 }
300             };
301         menuItem.addActionListener(deleteEdgeAction);
302         edgePopup.add(menuItem);
303 
304         edgePopup.addPopupMenuListener(new PopupMenuListener() {
305             public void popupMenuCanceled(PopupMenuEvent e) {}
306             public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
307                 tgPanel.setMaintainMouseOver(false);
308                 tgPanel.setMouseOverE(null);
309                 tgPanel.repaint();
310             }
311             public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
312         });
313     }
314 
315     private void setUpBackPopup() {
316         backPopup = new JPopupMenu();
317         JMenuItem menuItem;
318 
319         menuItem = new JMenuItem("Multi-Select");
320         ActionListener multiselectAction = new ActionListener() {
321                 public void actionPerformed(ActionEvent e) {
322                     dragMultiselectUI.activate(GLEditUI.this);
323                 }
324             };
325         menuItem.addActionListener(multiselectAction);
326         backPopup.add(menuItem);
327 
328         menuItem = new JMenuItem("Start Over");
329         ActionListener startOverAction = new ActionListener() {
330                 public void actionPerformed( ActionEvent e ) {
331                     tgPanel.clearAll();
332                     tgPanel.clearSelect();
333                     try {
334                         tgPanel.addNode();
335                     } catch ( TGException tge ) {
336                         System.err.println(tge.getMessage());
337                         tge.printStackTrace(System.err);
338                     }
339                     tgPanel.fireResetEvent();
340                     tgPanel.repaint();
341                 }
342             };
343         menuItem.addActionListener(startOverAction);
344         backPopup.add(menuItem);
345     }
346 
347 } // end com.touchgraph.graphlayout.interaction.GLEditUI