View Javadoc

1   /*
2    * Copyright (c) 2005, the JUNG Project and the Regents of the University 
3    * of California
4    * All rights reserved.
5    *
6    * This software is open-source under the BSD license; see either
7    * "license.txt" or
8    * http://jung.sourceforge.net/license.txt for a description.
9    * Created on Mar 8, 2005
10   *
11   */
12  package edu.uci.ics.jung.visualization.control;
13  
14  import java.awt.Dimension;
15  import java.awt.ItemSelectable;
16  import java.awt.event.ItemEvent;
17  import java.awt.event.ItemListener;
18  import java.awt.event.KeyListener;
19  
20  import javax.swing.ButtonGroup;
21  import javax.swing.Icon;
22  import javax.swing.JComboBox;
23  import javax.swing.JMenu;
24  import javax.swing.JRadioButtonMenuItem;
25  import javax.swing.event.EventListenerList;
26  import javax.swing.plaf.basic.BasicIconFactory;
27  
28  
29  /** 
30   * 
31   * AbstractModalGraphMouse is a PluggableGraphMouse class that
32   * manages a collection of plugins for picking and
33   * transforming the graph. Additionally, it carries the notion
34   * of a Mode: Picking or Translating. Switching between modes
35   * allows for a more natural choice of mouse modifiers to
36   * be used for the various plugins. The default modifiers are
37   * intended to mimick those of mainstream software applications
38   * in order to be intuitive to users.
39   * 
40   * To change between modes, two different controls are offered,
41   * a combo box and a menu system. These controls are lazily created
42   * in their respective 'getter' methods so they don't impact
43   * code that does not intend to use them.
44   * The menu control can be placed in an unused corner of the
45   * GraphZoomScrollPane, which is a common location for mouse
46   * mode selection menus in mainstream applications.
47   * 
48   * Users must implement the loadPlugins() method to create and
49   * install the GraphMousePlugins. The order of the plugins is
50   * important, as they are evaluated against the mask parameters
51   * in the order that they are added.
52   * 
53   * @author Tom Nelson
54   */
55  public abstract class AbstractModalGraphMouse extends PluggableGraphMouse 
56      implements ModalGraphMouse, ItemSelectable {
57      
58  	/**
59  	 * used by the scaling plugins for zoom in
60  	 */
61      protected float in;
62      /**
63       * used by the scaling plugins for zoom out
64       */
65      protected float out;
66      /**
67       * a listener for mode changes
68       */
69      protected ItemListener modeListener;
70      /**
71       * a JComboBox control available to set the mode
72       */
73      protected JComboBox modeBox;
74      /**
75       * a menu available to set the mode
76       */
77      protected JMenu modeMenu;
78      /**
79       * the current mode
80       */
81      protected Mode mode;
82      /**
83       * listeners for mode changes
84       */
85      protected EventListenerList listenerList = new EventListenerList();
86  
87      protected GraphMousePlugin pickingPlugin;
88      protected GraphMousePlugin translatingPlugin;
89      protected GraphMousePlugin animatedPickingPlugin;
90      protected GraphMousePlugin scalingPlugin;
91      protected GraphMousePlugin rotatingPlugin;
92      protected GraphMousePlugin shearingPlugin;
93      protected KeyListener modeKeyListener;
94      
95  
96      protected AbstractModalGraphMouse(float in, float out) {
97  		this.in = in;
98  		this.out = out;
99  	}
100 
101 	/**
102      * create the plugins, and load the plugins for TRANSFORMING mode
103      *
104      */
105     protected abstract void loadPlugins();
106     
107     /**
108      * setter for the Mode.
109      */
110     public void setMode(Mode mode) {
111         if(this.mode != mode) {
112             fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
113                     this.mode, ItemEvent.DESELECTED));
114             this.mode = mode;
115             if(mode == Mode.TRANSFORMING) {
116                 setTransformingMode();
117             } else if(mode == Mode.PICKING) {
118                 setPickingMode();
119             }
120             if(modeBox != null) {
121                 modeBox.setSelectedItem(mode);
122             }
123             fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, mode, ItemEvent.SELECTED));
124         }
125     }
126     /* (non-Javadoc)
127      * @see edu.uci.ics.jung.visualization.control.ModalGraphMouse#setPickingMode()
128      */
129     protected void setPickingMode() {
130         remove(translatingPlugin);
131         remove(rotatingPlugin);
132         remove(shearingPlugin);
133         add(pickingPlugin);
134         add(animatedPickingPlugin);
135     }
136     
137     /* (non-Javadoc)
138      * @see edu.uci.ics.jung.visualization.control.ModalGraphMouse#setTransformingMode()
139      */
140     protected void setTransformingMode() {
141         remove(pickingPlugin);
142         remove(animatedPickingPlugin);
143         add(translatingPlugin);
144         add(rotatingPlugin);
145         add(shearingPlugin);
146     }
147 
148     /**
149      * @param zoomAtMouse The zoomAtMouse to set.
150      */
151     public void setZoomAtMouse(boolean zoomAtMouse) {
152         ((ScalingGraphMousePlugin) scalingPlugin).setZoomAtMouse(zoomAtMouse);
153     }
154     
155     /**
156      * listener to set the mode from an external event source
157      */
158     class ModeListener implements ItemListener {
159         public void itemStateChanged(ItemEvent e) {
160             setMode((Mode) e.getItem());
161         }
162     }
163 
164     /* (non-Javadoc)
165      * @see edu.uci.ics.jung.visualization.control.ModalGraphMouse#getModeListener()
166      */
167     public ItemListener getModeListener() {
168 		if (modeListener == null) {
169 			modeListener = new ModeListener();
170 		}
171 		return modeListener;
172 	}
173     
174     /**
175 	 * @return the modeKeyListener
176 	 */
177 	public KeyListener getModeKeyListener() {
178 		return modeKeyListener;
179 	}
180 
181 	/**
182 	 * @param modeKeyListener the modeKeyListener to set
183 	 */
184 	public void setModeKeyListener(KeyListener modeKeyListener) {
185 		this.modeKeyListener = modeKeyListener;
186 	}
187 
188 	/**
189 	 * @return Returns the modeBox.
190 	 */
191     public JComboBox getModeComboBox() {
192         if(modeBox == null) {
193             modeBox = new JComboBox(new Mode[]{Mode.TRANSFORMING, Mode.PICKING});
194             modeBox.addItemListener(getModeListener());
195         }
196         modeBox.setSelectedItem(mode);
197         return modeBox;
198     }
199     
200     /**
201      * create (if necessary) and return a menu that will change
202      * the mode
203      * @return the menu
204      */
205     public JMenu getModeMenu() {
206         if(modeMenu == null) {
207             modeMenu = new JMenu();// {
208             Icon icon = BasicIconFactory.getMenuArrowIcon();
209             modeMenu.setIcon(BasicIconFactory.getMenuArrowIcon());
210             modeMenu.setPreferredSize(new Dimension(icon.getIconWidth()+10, 
211             		icon.getIconHeight()+10));
212 
213             final JRadioButtonMenuItem transformingButton = 
214                 new JRadioButtonMenuItem(Mode.TRANSFORMING.toString());
215             transformingButton.addItemListener(new ItemListener() {
216                 public void itemStateChanged(ItemEvent e) {
217                     if(e.getStateChange() == ItemEvent.SELECTED) {
218                         setMode(Mode.TRANSFORMING);
219                     }
220                 }});
221             
222             final JRadioButtonMenuItem pickingButton =
223                 new JRadioButtonMenuItem(Mode.PICKING.toString());
224             pickingButton.addItemListener(new ItemListener() {
225                 public void itemStateChanged(ItemEvent e) {
226                     if(e.getStateChange() == ItemEvent.SELECTED) {
227                         setMode(Mode.PICKING);
228                     }
229                 }});
230             ButtonGroup radio = new ButtonGroup();
231             radio.add(transformingButton);
232             radio.add(pickingButton);
233             transformingButton.setSelected(true);
234             modeMenu.add(transformingButton);
235             modeMenu.add(pickingButton);
236             modeMenu.setToolTipText("Menu for setting Mouse Mode");
237             addItemListener(new ItemListener() {
238 				public void itemStateChanged(ItemEvent e) {
239 					if(e.getStateChange() == ItemEvent.SELECTED) {
240 						if(e.getItem() == Mode.TRANSFORMING) {
241 							transformingButton.setSelected(true);
242 						} else if(e.getItem() == Mode.PICKING) {
243 							pickingButton.setSelected(true);
244 						}
245 					}
246 				}});
247         }
248         return modeMenu;
249     }
250     
251     /**
252      * add a listener for mode changes
253      */
254     public void addItemListener(ItemListener aListener) {
255         listenerList.add(ItemListener.class,aListener);
256     }
257 
258     /**
259      * remove a listener for mode changes
260      */
261     public void removeItemListener(ItemListener aListener) {
262         listenerList.remove(ItemListener.class,aListener);
263     }
264 
265     /**
266      * Returns an array of all the <code>ItemListener</code>s added
267      * to this JComboBox with addItemListener().
268      *
269      * @return all of the <code>ItemListener</code>s added or an empty
270      *         array if no listeners have been added
271      * @since 1.4
272      */
273     public ItemListener[] getItemListeners() {
274         return listenerList.getListeners(ItemListener.class);
275     }
276     
277     public Object[] getSelectedObjects() {
278         if ( mode == null )
279             return new Object[0];
280         else {
281             Object result[] = new Object[1];
282             result[0] = mode;
283             return result;
284         }
285     }
286 
287     /**
288      * Notifies all listeners that have registered interest for
289      * notification on this event type.
290      * @param e  the event of interest
291      *  
292      * @see EventListenerList
293      */
294     protected void fireItemStateChanged(ItemEvent e) {
295         // Guaranteed to return a non-null array
296         Object[] listeners = listenerList.getListenerList();
297         // Process the listeners last to first, notifying
298         // those that are interested in this event
299         for ( int i = listeners.length-2; i>=0; i-=2 ) {
300             if ( listeners[i]==ItemListener.class ) {
301                 ((ItemListener)listeners[i+1]).itemStateChanged(e);
302             }
303         }
304     }
305 }