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.BorderLayout;
12  import java.awt.Color;
13  import java.awt.Container;
14  import java.awt.Dimension;
15  import java.awt.Font;
16  import java.awt.GridLayout;
17  import java.awt.event.ActionEvent;
18  import java.awt.event.ActionListener;
19  
20  import javax.swing.BorderFactory;
21  import javax.swing.JApplet;
22  import javax.swing.JButton;
23  import javax.swing.JFrame;
24  import javax.swing.JLabel;
25  import javax.swing.JPanel;
26  
27  import com.google.common.base.Functions;
28  
29  import edu.uci.ics.jung.algorithms.layout.KKLayout;
30  import edu.uci.ics.jung.algorithms.layout.Layout;
31  import edu.uci.ics.jung.algorithms.layout.StaticLayout;
32  import edu.uci.ics.jung.algorithms.layout.TreeLayout;
33  import edu.uci.ics.jung.algorithms.shortestpath.MinimumSpanningForest2;
34  import edu.uci.ics.jung.graph.DelegateForest;
35  import edu.uci.ics.jung.graph.DelegateTree;
36  import edu.uci.ics.jung.graph.Forest;
37  import edu.uci.ics.jung.graph.Graph;
38  import edu.uci.ics.jung.graph.util.TestGraphs;
39  import edu.uci.ics.jung.visualization.DefaultVisualizationModel;
40  import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
41  import edu.uci.ics.jung.visualization.VisualizationModel;
42  import edu.uci.ics.jung.visualization.VisualizationViewer;
43  import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
44  import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
45  import edu.uci.ics.jung.visualization.control.ScalingControl;
46  import edu.uci.ics.jung.visualization.decorators.EdgeShape;
47  import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
48  import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
49  import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
50  import edu.uci.ics.jung.visualization.picking.MultiPickedState;
51  import edu.uci.ics.jung.visualization.picking.PickedState;
52  import edu.uci.ics.jung.visualization.renderers.Renderer;
53  import edu.uci.ics.jung.visualization.transform.MutableTransformer;
54  
55  /**
56   * Demonstrates a single graph with 3 layouts in 3 views.
57   * The first view is an undirected graph using KKLayout
58   * The second view show a TreeLayout view of a MinimumSpanningTree
59   * of the first graph. The third view shows the complete graph
60   * of the first view, using the layout positions of the 
61   * MinimumSpanningTree tree view.
62   * 
63   * @author Tom Nelson
64   * 
65   */
66  @SuppressWarnings("serial")
67  public class MinimumSpanningTreeDemo extends JApplet {
68  
69       /**
70       * the graph
71       */
72      Graph<String,Number> graph;
73      Forest<String,Number> tree;
74  
75      /**
76       * the visual components and renderers for the graph
77       */
78      VisualizationViewer<String,Number> vv0;
79      VisualizationViewer<String,Number> vv1;
80      VisualizationViewer<String,Number> vv2;
81      
82      /**
83       * the normal Function
84       */
85      MutableTransformer layoutTransformer;
86      
87      Dimension preferredSize = new Dimension(300,300);
88      Dimension preferredLayoutSize = new Dimension(400,400);
89      Dimension preferredSizeRect = new Dimension(500,250);
90      
91      /**
92       * create an instance of a simple graph in two views with controls to
93       * demo the zoom features.
94       * 
95       */
96      public MinimumSpanningTreeDemo() {
97          
98          // create a simple graph for the demo
99          // both models will share one graph
100         graph = 
101         	TestGraphs.getDemoGraph();
102         
103         MinimumSpanningForest2<String,Number> prim = 
104         	new MinimumSpanningForest2<String,Number>(graph,
105         		new DelegateForest<String,Number>(), DelegateTree.<String,Number>getFactory(),
106         		Functions.<Double>constant(1.0));
107         
108         tree = prim.getForest();
109         
110         // create two layouts for the one graph, one layout for each model
111         Layout<String,Number> layout0 = new KKLayout<String,Number>(graph);
112         layout0.setSize(preferredLayoutSize);
113         Layout<String,Number> layout1 = new TreeLayout<String,Number>(tree);
114         Layout<String,Number> layout2 = new StaticLayout<String,Number>(graph, layout1);
115 
116         // create the two models, each with a different layout
117         VisualizationModel<String,Number> vm0 =
118             new DefaultVisualizationModel<String,Number>(layout0, preferredSize);
119         VisualizationModel<String,Number> vm1 =
120             new DefaultVisualizationModel<String,Number>(layout1, preferredSizeRect);
121         VisualizationModel<String,Number> vm2 = 
122             new DefaultVisualizationModel<String,Number>(layout2, preferredSizeRect);
123         	
124         // create the two views, one for each model
125         // they share the same renderer
126         vv0 = new VisualizationViewer<String,Number>(vm0, preferredSize);
127         vv1 = new VisualizationViewer<String,Number>(vm1, preferredSizeRect);
128         vv2 = new VisualizationViewer<String,Number>(vm2, preferredSizeRect);
129         
130         vv1.getRenderContext().setMultiLayerTransformer(vv0.getRenderContext().getMultiLayerTransformer());
131         vv2.getRenderContext().setMultiLayerTransformer(vv0.getRenderContext().getMultiLayerTransformer());
132 
133         vv1.getRenderContext().setEdgeShapeTransformer(EdgeShape.line(graph));
134         
135         vv0.addChangeListener(vv1);
136         vv1.addChangeListener(vv2);
137         
138         vv0.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
139         vv2.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
140         
141         Color back = Color.decode("0xffffbb");
142         vv0.setBackground(back);
143         vv1.setBackground(back);
144         vv2.setBackground(back);
145         
146         vv0.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.CNTR);
147         vv0.setForeground(Color.darkGray);
148         vv1.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.CNTR);
149         vv1.setForeground(Color.darkGray);
150         vv2.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.CNTR);
151         vv2.setForeground(Color.darkGray);
152         
153         // share one PickedState between the two views
154         PickedState<String> ps = new MultiPickedState<String>();
155         vv0.setPickedVertexState(ps);
156         vv1.setPickedVertexState(ps);
157         vv2.setPickedVertexState(ps);
158 
159         PickedState<Number> pes = new MultiPickedState<Number>();
160         vv0.setPickedEdgeState(pes);
161         vv1.setPickedEdgeState(pes);
162         vv2.setPickedEdgeState(pes);
163 
164         
165         // set an edge paint function that will show picking for edges
166         vv0.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(vv0.getPickedEdgeState(), Color.black, Color.red));
167         vv0.getRenderContext().setVertexFillPaintTransformer(new PickableVertexPaintTransformer<String>(vv0.getPickedVertexState(),
168                 Color.red, Color.yellow));
169         vv1.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(vv1.getPickedEdgeState(), Color.black, Color.red));
170         vv1.getRenderContext().setVertexFillPaintTransformer(new PickableVertexPaintTransformer<String>(vv1.getPickedVertexState(),
171                 Color.red, Color.yellow));
172         
173         // add default listeners for ToolTips
174         vv0.setVertexToolTipTransformer(new ToStringLabeller());
175         vv1.setVertexToolTipTransformer(new ToStringLabeller());
176         vv2.setVertexToolTipTransformer(new ToStringLabeller());
177         
178         vv0.setLayout(new BorderLayout());
179         vv1.setLayout(new BorderLayout());
180         vv2.setLayout(new BorderLayout());
181         
182         Font font = vv0.getFont().deriveFont(Font.BOLD, 16);
183         JLabel vv0Label = new JLabel("<html>Original Graph<p>using KKLayout");
184         vv0Label.setFont(font);
185         JLabel vv1Label = new JLabel("Minimum Spanning Trees");
186         vv1Label.setFont(font);
187         JLabel vv2Label = new JLabel("Original Graph using TreeLayout");
188         vv2Label.setFont(font);
189         JPanel flow0 = new JPanel();
190         flow0.setOpaque(false);
191         JPanel flow1 = new JPanel();
192         flow1.setOpaque(false);
193         JPanel flow2 = new JPanel();
194         flow2.setOpaque(false);
195         flow0.add(vv0Label);
196         flow1.add(vv1Label);
197         flow2.add(vv2Label);
198         vv0.add(flow0, BorderLayout.NORTH);
199         vv1.add(flow1, BorderLayout.NORTH);
200         vv2.add(flow2, BorderLayout.NORTH);
201         
202         Container content = getContentPane();
203         JPanel grid = new JPanel(new GridLayout(0,1));
204         JPanel panel = new JPanel(new BorderLayout());
205         panel.add(new GraphZoomScrollPane(vv0), BorderLayout.WEST);
206         grid.add(new GraphZoomScrollPane(vv1));
207         grid.add(new GraphZoomScrollPane(vv2));
208         panel.add(grid);
209 
210         content.add(panel);
211         
212         // create a GraphMouse for each view
213         DefaultModalGraphMouse<String, Number> gm0 = new DefaultModalGraphMouse<String, Number>();
214         DefaultModalGraphMouse<String, Number> gm1 = new DefaultModalGraphMouse<String, Number>();
215         DefaultModalGraphMouse<String, Number> gm2 = new DefaultModalGraphMouse<String, Number>();
216 
217         vv0.setGraphMouse(gm0);
218         vv1.setGraphMouse(gm1);
219         vv2.setGraphMouse(gm2);
220 
221         // create zoom buttons for scaling the Function that is
222         // shared between the two models.
223         final ScalingControl scaler = new CrossoverScalingControl();
224         
225         vv0.scaleToLayout(scaler);
226         vv1.scaleToLayout(scaler);
227         vv2.scaleToLayout(scaler);
228 
229         JButton plus = new JButton("+");
230         plus.addActionListener(new ActionListener() {
231             public void actionPerformed(ActionEvent e) {
232                 scaler.scale(vv1, 1.1f, vv1.getCenter());
233             }
234         });
235         JButton minus = new JButton("-");
236         minus.addActionListener(new ActionListener() {
237             public void actionPerformed(ActionEvent e) {
238                 scaler.scale(vv1, 1/1.1f, vv1.getCenter());
239             }
240         });
241         
242         JPanel zoomPanel = new JPanel(new GridLayout(1,2));
243         zoomPanel.setBorder(BorderFactory.createTitledBorder("Zoom"));
244         
245         JPanel modePanel = new JPanel();
246         modePanel.setBorder(BorderFactory.createTitledBorder("Mouse Mode"));
247         gm1.getModeComboBox().addItemListener(gm2.getModeListener());
248         gm1.getModeComboBox().addItemListener(gm0.getModeListener());
249         modePanel.add(gm1.getModeComboBox());
250 
251         JPanel controls = new JPanel();
252         zoomPanel.add(plus);
253         zoomPanel.add(minus);
254         controls.add(zoomPanel);
255         controls.add(modePanel);
256         content.add(controls, BorderLayout.SOUTH);
257     }
258 
259     public static void main(String[] args) {
260         JFrame f = new JFrame();
261         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
262         f.getContentPane().add(new MinimumSpanningTreeDemo());
263         f.pack();
264         f.setVisible(true);
265     }
266 }