View Javadoc
1   package edu.uci.ics.jung.visualization.control;
2   
3   import java.awt.Cursor;
4   import java.awt.event.MouseEvent;
5   import java.awt.event.MouseListener;
6   import java.awt.event.MouseMotionListener;
7   import java.awt.geom.Point2D;
8   
9   import javax.swing.JComponent;
10  
11  import com.google.common.base.Supplier;
12  
13  import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
14  import edu.uci.ics.jung.algorithms.layout.Layout;
15  import edu.uci.ics.jung.graph.DirectedGraph;
16  import edu.uci.ics.jung.graph.Graph;
17  import edu.uci.ics.jung.graph.UndirectedGraph;
18  import edu.uci.ics.jung.graph.util.EdgeType;
19  import edu.uci.ics.jung.visualization.VisualizationViewer;
20  
21  /**
22   * A plugin that can create vertices, undirected edges, and directed edges
23   * using mouse gestures.
24   * 
25   * vertexSupport and edgeSupport member classes are responsible for actually
26   * creating the new graph elements, and for repainting the view when changes
27   * were made.
28   * 
29   * @author Tom Nelson
30   *
31   */
32  public class EditingGraphMousePlugin<V,E> extends AbstractGraphMousePlugin implements
33      MouseListener, MouseMotionListener {
34      
35  	protected VertexSupport<V,E> vertexSupport;
36  	protected EdgeSupport<V,E> edgeSupport;
37  	private Creating createMode = Creating.UNDETERMINED;
38  	private enum Creating { EDGE, VERTEX, UNDETERMINED }
39      
40      /**
41       * Creates an instance and prepares shapes for visual effects, using the default modifiers
42       * of BUTTON1_MASK.
43       * @param vertexFactory for creating vertices
44       * @param edgeFactory for creating edges
45       */
46      public EditingGraphMousePlugin(Supplier<V> vertexFactory, Supplier<E> edgeFactory) {
47          this(MouseEvent.BUTTON1_MASK, vertexFactory, edgeFactory);
48      }
49  
50      /**
51       * Creates an instance and prepares shapes for visual effects.
52       * @param modifiers the mouse event modifiers to use
53       * @param vertexFactory for creating vertices
54       * @param edgeFactory for creating edges
55       */
56      public EditingGraphMousePlugin(int modifiers, Supplier<V> vertexFactory, Supplier<E> edgeFactory) {
57          super(modifiers);
58  		this.cursor = Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);
59  		this.vertexSupport = new SimpleVertexSupport<V,E>(vertexFactory);
60  		this.edgeSupport = new SimpleEdgeSupport<V,E>(edgeFactory);
61      }
62      
63      /**
64       * Overridden to be more flexible, and pass events with
65       * key combinations. The default responds to both ButtonOne
66       * and ButtonOne+Shift
67       */
68      @Override
69      public boolean checkModifiers(MouseEvent e) {
70          return (e.getModifiers() & modifiers) != 0;
71      }
72  
73      /**
74       * If the mouse is pressed in an empty area, create a new vertex there.
75       * If the mouse is pressed on an existing vertex, prepare to create
76       * an edge from that vertex to another
77       */
78      @SuppressWarnings("unchecked")
79  	public void mousePressed(MouseEvent e) {
80          if(checkModifiers(e)) {
81              final VisualizationViewer<V,E> vv =
82                  (VisualizationViewer<V,E>)e.getSource();
83              final Point2D p = e.getPoint();
84              GraphElementAccessor<V,E> pickSupport = vv.getPickSupport();
85              if(pickSupport != null) {
86                  final V vertex = pickSupport.getVertex(vv.getModel().getGraphLayout(), p.getX(), p.getY());
87                  if(vertex != null) { // get ready to make an edge
88                  	this.createMode = Creating.EDGE;
89                  	Graph<V,E> graph = vv.getModel().getGraphLayout().getGraph();
90                  	// set default edge type
91                  	EdgeType edgeType = (graph instanceof DirectedGraph) ?
92                  			EdgeType.DIRECTED : EdgeType.UNDIRECTED;
93                      if((e.getModifiers() & MouseEvent.SHIFT_MASK) != 0
94                      		&& graph instanceof UndirectedGraph == false) {
95                          edgeType = EdgeType.DIRECTED;
96                      }
97                      edgeSupport.startEdgeCreate(vv, vertex, e.getPoint(), edgeType);
98                  } else { // make a new vertex
99                  	this.createMode = Creating.VERTEX;
100                 	vertexSupport.startVertexCreate(vv, e.getPoint());
101                 }
102             }
103         }
104     }
105     
106     /**
107      * If startVertex is non-null, and the mouse is released over an
108      * existing vertex, create an undirected edge from startVertex to
109      * the vertex under the mouse pointer. If shift was also pressed,
110      * create a directed edge instead.
111      */
112     @SuppressWarnings("unchecked")
113 	public void mouseReleased(MouseEvent e) {
114         if(checkModifiers(e)) {
115             final VisualizationViewer<V,E> vv =
116                 (VisualizationViewer<V,E>)e.getSource();
117             final Point2D p = e.getPoint();
118             Layout<V,E> layout = vv.getGraphLayout();
119             if(createMode == Creating.EDGE) {
120                 GraphElementAccessor<V,E> pickSupport = vv.getPickSupport();
121                 V vertex = null;
122                 if(pickSupport != null) {
123                     vertex = pickSupport.getVertex(layout, p.getX(), p.getY());
124                 }
125                 edgeSupport.endEdgeCreate(vv, vertex);
126             } else if(createMode == Creating.VERTEX){
127             	vertexSupport.endVertexCreate(vv, e.getPoint());
128             }
129         }
130         createMode = Creating.UNDETERMINED;
131     }
132 
133     /**
134      * If startVertex is non-null, stretch an edge shape between
135      * startVertex and the mouse pointer to simulate edge creation
136      */
137     @SuppressWarnings("unchecked")
138     public void mouseDragged(MouseEvent e) {
139         if(checkModifiers(e)) {
140             VisualizationViewer<V,E> vv =
141                 (VisualizationViewer<V,E>)e.getSource();
142             if(createMode == Creating.EDGE) {
143             	edgeSupport.midEdgeCreate(vv, e.getPoint());
144             } else if(createMode == Creating.VERTEX){
145             	vertexSupport.midVertexCreate(vv, e.getPoint());
146             }
147         }
148     }
149     
150     public void mouseClicked(MouseEvent e) {}
151     public void mouseEntered(MouseEvent e) {
152         JComponent c = (JComponent)e.getSource();
153         c.setCursor(cursor);
154     }
155     public void mouseExited(MouseEvent e) {
156         JComponent c = (JComponent)e.getSource();
157         c.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
158     }
159     public void mouseMoved(MouseEvent e) {}
160 
161 	public VertexSupport<V,E> getVertexSupport() {
162 		return vertexSupport;
163 	}
164 
165 	public void setVertexSupport(VertexSupport<V,E> vertexSupport) {
166 		this.vertexSupport = vertexSupport;
167 	}
168 
169 	public EdgeSupport<V,E> getEdgeSupport() {
170 		return edgeSupport;
171 	}
172 
173 	public void setEdgeSupport(EdgeSupport<V,E> edgeSupport) {
174 		this.edgeSupport = edgeSupport;
175 	}
176     
177     
178 }