View Javadoc
1   /*
2    * Copyright (c) 2003, The JUNG Authors
3    * All rights reserved.
4    * 
5    * This software is open-source under the BSD license; see either "license.txt"
6    * or https://github.com/jrtom/jung/blob/master/LICENSE for a description.
7    * 
8    */
9   package edu.uci.ics.jung.samples;
10  
11  import java.awt.BasicStroke;
12  import java.awt.BorderLayout;
13  import java.awt.Color;
14  import java.awt.Container;
15  import java.awt.Dimension;
16  import java.awt.Graphics;
17  import java.awt.Graphics2D;
18  import java.awt.GridLayout;
19  import java.awt.Rectangle;
20  import java.awt.Shape;
21  import java.awt.event.ActionEvent;
22  import java.awt.event.ActionListener;
23  import java.awt.event.ItemEvent;
24  import java.awt.event.ItemListener;
25  import java.awt.geom.GeneralPath;
26  
27  import javax.swing.JApplet;
28  import javax.swing.JButton;
29  import javax.swing.JCheckBox;
30  import javax.swing.JComboBox;
31  import javax.swing.JDialog;
32  import javax.swing.JFrame;
33  import javax.swing.JLabel;
34  import javax.swing.JPanel;
35  import javax.swing.ToolTipManager;
36  
37  import edu.uci.ics.jung.algorithms.layout.FRLayout;
38  import edu.uci.ics.jung.graph.Graph;
39  import edu.uci.ics.jung.graph.util.TestGraphs;
40  import edu.uci.ics.jung.visualization.DefaultVisualizationModel;
41  import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
42  import edu.uci.ics.jung.visualization.Layer;
43  import edu.uci.ics.jung.visualization.VisualizationModel;
44  import edu.uci.ics.jung.visualization.VisualizationViewer;
45  import edu.uci.ics.jung.visualization.VisualizationServer.Paintable;
46  import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
47  import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
48  import edu.uci.ics.jung.visualization.control.SatelliteVisualizationViewer;
49  import edu.uci.ics.jung.visualization.control.ScalingControl;
50  import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
51  import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
52  import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
53  import edu.uci.ics.jung.visualization.renderers.GradientVertexRenderer;
54  import edu.uci.ics.jung.visualization.renderers.Renderer;
55  import edu.uci.ics.jung.visualization.transform.shape.ShapeTransformer;
56  
57  /**
58   * Demonstrates the construction of a graph visualization with a main and 
59   * a satellite view. The satellite
60   * view is smaller, always contains the entire graph, and contains
61   * a lens shape that shows the boundaries of the visible part of the
62   * graph in the main view. Using the mouse, you can pick, translate,
63   * layout-scale, view-scale, rotate, shear, and region-select in either
64   * view. Using the mouse in either window affects only the main view
65   * and the lens shape in the satellite view.
66   * 
67   * @author Tom Nelson
68   * 
69   */
70  @SuppressWarnings("serial")
71  public class SatelliteViewDemo<V, E> extends JApplet {
72  
73      static final String instructions = 
74          "<html>"+
75          "<b><h2><center>Instructions for Mouse Listeners</center></h2></b>"+
76          "<p>There are two modes, Transforming and Picking."+
77          "<p>The modes are selected with a combo box."+
78          
79          "<p><p><b>Transforming Mode:</b>"+
80          "<ul>"+
81          "<li>Mouse1+drag pans the graph"+
82          "<li>Mouse1+Shift+drag rotates the graph"+
83          "<li>Mouse1+CTRL(or Command)+drag shears the graph"+
84          "</ul>"+
85          
86          "<b>Picking Mode:</b>"+
87          "<ul>"+
88          "<li>Mouse1 on a Vertex selects the vertex"+
89          "<li>Mouse1 elsewhere unselects all Vertices"+
90          "<li>Mouse1+Shift on a Vertex adds/removes Vertex selection"+
91          "<li>Mouse1+drag on a Vertex moves all selected Vertices"+
92          "<li>Mouse1+drag elsewhere selects Vertices in a region"+
93          "<li>Mouse1+Shift+drag adds selection of Vertices in a new region"+
94          "<li>Mouse1+CTRL on a Vertex selects the vertex and centers the display on it"+
95          "</ul>"+
96         "<b>Both Modes:</b>"+
97         "<ul>"+
98          "<li>Mousewheel scales with a crossover value of 1.0.<p>"+
99          "     - scales the graph layout when the combined scale is greater than 1<p>"+
100         "     - scales the graph view when the combined scale is less than 1";
101     
102     JDialog helpDialog;
103     
104     Paintable viewGrid;
105     
106     /**
107      * create an instance of a simple graph in two views with controls to
108      * demo the features.
109      * 
110      */
111     public SatelliteViewDemo() {
112         
113         // create a simple graph for the demo
114         Graph<String, Number> graph = TestGraphs.getOneComponentGraph();
115         
116         // the preferred sizes for the two views
117         Dimension preferredSize1 = new Dimension(600,600);
118         Dimension preferredSize2 = new Dimension(300, 300);
119         
120         // create one layout for the graph
121         FRLayout<String,Number> layout = new FRLayout<String,Number>(graph);
122         layout.setMaxIterations(500);
123         
124         // create one model that both views will share
125         VisualizationModel<String,Number> vm =
126             new DefaultVisualizationModel<String,Number>(layout, preferredSize1);
127         
128         // create 2 views that share the same model
129         final VisualizationViewer<String,Number> vv1 = 
130             new VisualizationViewer<String,Number>(vm, preferredSize1);
131         final SatelliteVisualizationViewer<String,Number> vv2 = 
132             new SatelliteVisualizationViewer<String,Number>(vv1, preferredSize2);
133         vv1.setBackground(Color.white);
134         vv1.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(vv1.getPickedEdgeState(), Color.black, Color.cyan));
135         vv1.getRenderContext().setVertexFillPaintTransformer(new PickableVertexPaintTransformer<String>(vv1.getPickedVertexState(), Color.red, Color.yellow));
136         vv2.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(vv2.getPickedEdgeState(), Color.black, Color.cyan));
137         vv2.getRenderContext().setVertexFillPaintTransformer(new PickableVertexPaintTransformer<String>(vv2.getPickedVertexState(), Color.red, Color.yellow));
138         vv1.getRenderer().setVertexRenderer(new GradientVertexRenderer<String,Number>(Color.red, Color.white, true));
139         vv1.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
140         vv1.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.CNTR);
141         
142         ScalingControl vv2Scaler = new CrossoverScalingControl();
143         vv2.scaleToLayout(vv2Scaler);
144         
145         viewGrid = new ViewGrid(vv2, vv1);
146 
147         // add default listener for ToolTips
148         vv1.setVertexToolTipTransformer(new ToStringLabeller());
149         vv2.setVertexToolTipTransformer(new ToStringLabeller());
150         
151         vv2.getRenderContext().setVertexLabelTransformer(vv1.getRenderContext().getVertexLabelTransformer());
152 
153         
154         ToolTipManager.sharedInstance().setDismissDelay(10000);
155         
156         Container content = getContentPane();
157         Container panel = new JPanel(new BorderLayout());
158         Container rightPanel = new JPanel(new GridLayout(2,1));
159         
160         GraphZoomScrollPane gzsp = new GraphZoomScrollPane(vv1);
161         panel.add(gzsp);
162         rightPanel.add(new JPanel());
163         rightPanel.add(vv2);
164         panel.add(rightPanel, BorderLayout.EAST);
165         
166         helpDialog = new JDialog();
167         helpDialog.getContentPane().add(new JLabel(instructions));
168         
169         // create a GraphMouse for the main view
170         final DefaultModalGraphMouse<String, Number> graphMouse
171         	= new DefaultModalGraphMouse<String, Number>();
172         vv1.setGraphMouse(graphMouse);
173         
174         final ScalingControl scaler = new CrossoverScalingControl();
175 
176         JButton plus = new JButton("+");
177         plus.addActionListener(new ActionListener() {
178             public void actionPerformed(ActionEvent e) {
179                 scaler.scale(vv1, 1.1f, vv1.getCenter());
180             }
181         });
182         JButton minus = new JButton("-");
183         minus.addActionListener(new ActionListener() {
184             public void actionPerformed(ActionEvent e) {
185                 scaler.scale(vv1, 1/1.1f, vv1.getCenter());
186             }
187         });
188         
189         JComboBox<?> modeBox = graphMouse.getModeComboBox();
190         modeBox.addItemListener(((DefaultModalGraphMouse<?, ?>)vv2.getGraphMouse())
191         	.getModeListener());
192         
193         JCheckBox gridBox = new JCheckBox("Show Grid");
194         gridBox.addItemListener(new ItemListener() {
195 			public void itemStateChanged(ItemEvent e) {
196 				showGrid(vv2, e.getStateChange() == ItemEvent.SELECTED);
197 			}});
198         JButton help = new JButton("Help");
199         help.addActionListener(new ActionListener() {
200             public void actionPerformed(ActionEvent e) {
201                 helpDialog.pack();
202                 helpDialog.setVisible(true);
203             }
204         });
205 
206         JPanel controls = new JPanel();
207         controls.add(plus);
208         controls.add(minus);
209         controls.add(modeBox);
210         controls.add(gridBox);
211         controls.add(help);
212         content.add(panel);
213         content.add(controls, BorderLayout.SOUTH);
214     }
215     
216     protected void showGrid(VisualizationViewer<?, ?> vv, boolean state) {
217     		if(state == true) {
218     			vv.addPreRenderPaintable(viewGrid);
219     		} else {
220     			vv.removePreRenderPaintable(viewGrid);
221     		}
222         vv.repaint();
223     }
224     
225     /**
226      * draws a grid on the SatelliteViewer's lens
227      * @author Tom Nelson
228      *
229      */
230     static class ViewGrid implements Paintable {
231 
232         VisualizationViewer<?, ?> master;
233         VisualizationViewer<?, ?> vv;
234         
235         public ViewGrid(VisualizationViewer<?, ?> vv, VisualizationViewer<?, ?> master) {
236             this.vv = vv;
237             this.master = master;
238         }
239         public void paint(Graphics g) {
240             ShapeTransformer masterViewTransformer = master.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW);
241             ShapeTransformer masterLayoutTransformer = master.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT);
242             ShapeTransformer vvLayoutTransformer = vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT);
243 
244             Rectangle rect = master.getBounds();
245             GeneralPath path = new GeneralPath();
246             path.moveTo(rect.x, rect.y);
247             path.lineTo(rect.width,rect.y);
248             path.lineTo(rect.width, rect.height);
249             path.lineTo(rect.x, rect.height);
250             path.lineTo(rect.x, rect.y);
251             
252             for(int i=0; i<=rect.width; i+=rect.width/10) {
253             		path.moveTo(rect.x+i, rect.y);
254             		path.lineTo(rect.x+i, rect.height);
255             }
256             for(int i=0; i<=rect.height; i+=rect.height/10) {
257             		path.moveTo(rect.x, rect.y+i);
258             		path.lineTo(rect.width, rect.y+i);
259             }
260             Shape lens = path;
261             lens = masterViewTransformer.inverseTransform(lens);
262             lens = masterLayoutTransformer.inverseTransform(lens);
263             lens = vvLayoutTransformer.transform(lens);
264             Graphics2D g2d = (Graphics2D)g;
265             Color old = g.getColor();
266             g.setColor(Color.cyan);
267             g2d.draw(lens);
268             
269             path = new GeneralPath();
270             path.moveTo((float)rect.getMinX(), (float)rect.getCenterY());
271             path.lineTo((float)rect.getMaxX(), (float)rect.getCenterY());
272             path.moveTo((float)rect.getCenterX(), (float)rect.getMinY());
273             path.lineTo((float)rect.getCenterX(), (float)rect.getMaxY());
274             Shape crosshairShape = path;
275             crosshairShape = masterViewTransformer.inverseTransform(crosshairShape);
276             crosshairShape = masterLayoutTransformer.inverseTransform(crosshairShape);
277             crosshairShape = vvLayoutTransformer.transform(crosshairShape);
278             g.setColor(Color.black);
279             g2d.setStroke(new BasicStroke(3));
280             g2d.draw(crosshairShape);
281             
282             g.setColor(old);
283         }
284 
285         public boolean useTransform() {
286             return true;
287         }
288     }
289 
290     
291     public static void main(String[] args) {
292         JFrame f = new JFrame();
293         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
294         f.getContentPane().add(new SatelliteViewDemo<String, Number>());
295         f.pack();
296         f.setVisible(true);
297     }
298 }