View Javadoc

1   package edu.uci.ics.jung.samples;
2   /*
3    * Copyright (c) 2003, the JUNG Project and the Regents of the University of
4    * California All rights reserved.
5    * 
6    * This software is open-source under the BSD license; see either "license.txt"
7    * or http://jung.sourceforge.net/license.txt for a description.
8    * 
9    */
10  
11  
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.Shape;
20  import java.awt.event.ActionEvent;
21  import java.awt.event.ActionListener;
22  import java.awt.event.ItemEvent;
23  import java.awt.event.ItemListener;
24  import java.awt.geom.Ellipse2D;
25  import java.awt.geom.Point2D;
26  import java.util.Collection;
27  import java.util.HashSet;
28  import java.util.Map;
29  import java.util.Set;
30  
31  import javax.swing.BorderFactory;
32  import javax.swing.JApplet;
33  import javax.swing.JButton;
34  import javax.swing.JComboBox;
35  import javax.swing.JFrame;
36  import javax.swing.JPanel;
37  import javax.swing.JToggleButton;
38  
39  import org.apache.commons.collections15.Factory;
40  import org.apache.commons.collections15.Transformer;
41  import org.apache.commons.collections15.functors.ConstantTransformer;
42  
43  import edu.uci.ics.jung.algorithms.layout.FRLayout;
44  import edu.uci.ics.jung.algorithms.layout.PolarPoint;
45  import edu.uci.ics.jung.algorithms.layout.RadialTreeLayout;
46  import edu.uci.ics.jung.algorithms.layout.TreeLayout;
47  import edu.uci.ics.jung.graph.DirectedGraph;
48  import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
49  import edu.uci.ics.jung.graph.Forest;
50  import edu.uci.ics.jung.graph.Graph;
51  import edu.uci.ics.jung.graph.DelegateForest;
52  import edu.uci.ics.jung.graph.DelegateTree;
53  import edu.uci.ics.jung.graph.Tree;
54  import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
55  import edu.uci.ics.jung.visualization.Layer;
56  import edu.uci.ics.jung.visualization.VisualizationServer;
57  import edu.uci.ics.jung.visualization.VisualizationViewer;
58  import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
59  import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
60  import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
61  import edu.uci.ics.jung.visualization.control.ScalingControl;
62  import edu.uci.ics.jung.visualization.decorators.EdgeShape;
63  import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer;
64  import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
65  import edu.uci.ics.jung.visualization.subLayout.TreeCollapser;
66  
67  /**
68   * Demonstrates "collapsing"/"expanding" of a tree's subtrees.
69   * @author Tom Nelson
70   * 
71   */
72  @SuppressWarnings("serial")
73  public class TreeCollapseDemo extends JApplet {
74  
75      /**
76       * the graph
77       */
78      Forest<String,Integer> graph;
79  
80      Factory<DirectedGraph<String,Integer>> graphFactory = 
81      	new Factory<DirectedGraph<String,Integer>>() {
82  
83  			public DirectedGraph<String, Integer> create() {
84  				return new DirectedSparseMultigraph<String,Integer>();
85  			}
86  		};
87  			
88          Factory<Tree<String,Integer>> treeFactory =
89  		new Factory<Tree<String,Integer>> () {
90  
91  		public Tree<String, Integer> create() {
92  			return new DelegateTree<String,Integer>(graphFactory);
93  		}
94  	};
95  	
96  	
97  	
98  	Factory<Integer> edgeFactory = new Factory<Integer>() {
99  		int i=0;
100 		public Integer create() {
101 			return i++;
102 		}};
103 
104     Factory<String> vertexFactory = new Factory<String>() {
105     	int i=0;
106 		public String create() {
107 			return "V"+i++;
108 		}};
109 
110     /**
111      * the visual component and renderer for the graph
112      */
113     VisualizationViewer<String,Integer> vv;
114 
115     VisualizationServer.Paintable rings;
116 
117     String root;
118 
119     TreeLayout<String,Integer> layout;
120     @SuppressWarnings("unchecked")
121 	FRLayout layout1;
122 
123     TreeCollapser collapser;
124 
125     RadialTreeLayout<String,Integer> radialLayout;
126 
127     @SuppressWarnings("unchecked")
128 	public TreeCollapseDemo() {
129 
130         // create a simple graph for the demo
131         graph = new DelegateForest<String,Integer>();
132 
133         createTree();
134 
135         layout = new TreeLayout<String,Integer>(graph);
136         collapser = new TreeCollapser();
137 
138         radialLayout = new RadialTreeLayout<String,Integer>(graph);
139         radialLayout.setSize(new Dimension(600,600));
140         vv =  new VisualizationViewer<String,Integer>(layout, new Dimension(600,600));
141         vv.setBackground(Color.white);
142         vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line());
143         vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
144         vv.getRenderContext().setVertexShapeTransformer(new ClusterVertexShapeFunction());
145         // add a listener for ToolTips
146         vv.setVertexToolTipTransformer(new ToStringLabeller());
147         vv.getRenderContext().setArrowFillPaintTransformer(new ConstantTransformer(Color.lightGray));
148         rings = new Rings();
149 
150         Container content = getContentPane();
151         final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
152         content.add(panel);
153 
154         final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();
155 
156         vv.setGraphMouse(graphMouse);
157 
158         JComboBox modeBox = graphMouse.getModeComboBox();
159         modeBox.addItemListener(graphMouse.getModeListener());
160         graphMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);
161 
162         final ScalingControl scaler = new CrossoverScalingControl();
163 
164         JButton plus = new JButton("+");
165         plus.addActionListener(new ActionListener() {
166             public void actionPerformed(ActionEvent e) {
167                 scaler.scale(vv, 1.1f, vv.getCenter());
168             }
169         });
170         JButton minus = new JButton("-");
171         minus.addActionListener(new ActionListener() {
172             public void actionPerformed(ActionEvent e) {
173                 scaler.scale(vv, 1/1.1f, vv.getCenter());
174             }
175         });
176 
177         JToggleButton radial = new JToggleButton("Radial");
178         radial.addItemListener(new ItemListener() {
179 
180 			public void itemStateChanged(ItemEvent e) {
181 				if(e.getStateChange() == ItemEvent.SELECTED) {
182 //					layout.setRadial(true);
183 					vv.setGraphLayout(radialLayout);
184 					vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
185 					vv.addPreRenderPaintable(rings);
186 				} else {
187 //					layout.setRadial(false);
188 					vv.setGraphLayout(layout);
189 					vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
190 					vv.removePreRenderPaintable(rings);
191 				}
192 				vv.repaint();
193 			}});
194 
195         JButton collapse = new JButton("Collapse");
196         collapse.addActionListener(new ActionListener() {
197 
198             public void actionPerformed(ActionEvent e) {
199                 Collection picked =new HashSet(vv.getPickedVertexState().getPicked());
200                 if(picked.size() == 1) {
201                 	Object root = picked.iterator().next();
202                     Forest inGraph = (Forest)layout.getGraph();
203 
204                     try {
205 						collapser.collapse(vv.getGraphLayout(), inGraph, root);
206 					} catch (InstantiationException e1) {
207 						// TODO Auto-generated catch block
208 						e1.printStackTrace();
209 					} catch (IllegalAccessException e1) {
210 						// TODO Auto-generated catch block
211 						e1.printStackTrace();
212 					}
213 
214                     vv.getPickedVertexState().clear();
215                     vv.repaint();
216                 }
217             }});
218 
219         JButton expand = new JButton("Expand");
220         expand.addActionListener(new ActionListener() {
221 
222             public void actionPerformed(ActionEvent e) {
223                 Collection picked = vv.getPickedVertexState().getPicked();
224                 for(Object v : picked) {
225                     if(v instanceof Forest) {
226                         Forest inGraph = (Forest)layout.getGraph();
227             			collapser.expand(inGraph, (Forest)v);
228                     }
229                     vv.getPickedVertexState().clear();
230                    vv.repaint();
231                 }
232             }});
233 
234         JPanel scaleGrid = new JPanel(new GridLayout(1,0));
235         scaleGrid.setBorder(BorderFactory.createTitledBorder("Zoom"));
236 
237         JPanel controls = new JPanel();
238         scaleGrid.add(plus);
239         scaleGrid.add(minus);
240         controls.add(radial);
241         controls.add(scaleGrid);
242         controls.add(modeBox);
243         controls.add(collapse);
244         controls.add(expand);
245         content.add(controls, BorderLayout.SOUTH);
246     }
247 
248     class Rings implements VisualizationServer.Paintable {
249     	
250     	Collection<Double> depths;
251     	
252     	public Rings() {
253     		depths = getDepths();
254     	}
255     	
256     	private Collection<Double> getDepths() {
257     		Set<Double> depths = new HashSet<Double>();
258     		Map<String,PolarPoint> polarLocations = radialLayout.getPolarLocations();
259     		for(String v : graph.getVertices()) {
260     			PolarPoint pp = polarLocations.get(v);
261     			depths.add(pp.getRadius());
262     		}
263     		return depths;
264     	}
265 
266 		public void paint(Graphics g) {
267 			g.setColor(Color.lightGray);
268 		
269 			Graphics2D g2d = (Graphics2D)g;
270 			Point2D center = radialLayout.getCenter();
271 
272 			Ellipse2D ellipse = new Ellipse2D.Double();
273 			for(double d : depths) {
274 				ellipse.setFrameFromDiagonal(center.getX()-d, center.getY()-d, 
275 						center.getX()+d, center.getY()+d);
276 				Shape shape = vv.getRenderContext().
277 						getMultiLayerTransformer().getTransformer(Layer.LAYOUT).transform(ellipse);
278 				g2d.draw(shape);
279 			}
280 		}
281 
282 		public boolean useTransform() {
283 			return true;
284 		}
285     }
286 
287     /**
288      * 
289      */
290     private void createTree() {
291     	graph.addVertex("V0");
292     	graph.addEdge(edgeFactory.create(), "V0", "V1");
293     	graph.addEdge(edgeFactory.create(), "V0", "V2");
294     	graph.addEdge(edgeFactory.create(), "V1", "V4");
295     	graph.addEdge(edgeFactory.create(), "V2", "V3");
296     	graph.addEdge(edgeFactory.create(), "V2", "V5");
297     	graph.addEdge(edgeFactory.create(), "V4", "V6");
298     	graph.addEdge(edgeFactory.create(), "V4", "V7");
299     	graph.addEdge(edgeFactory.create(), "V3", "V8");
300     	graph.addEdge(edgeFactory.create(), "V6", "V9");
301     	graph.addEdge(edgeFactory.create(), "V4", "V10");
302     	
303        	graph.addVertex("A0");
304        	graph.addEdge(edgeFactory.create(), "A0", "A1");
305        	graph.addEdge(edgeFactory.create(), "A0", "A2");
306        	graph.addEdge(edgeFactory.create(), "A0", "A3");
307        	
308        	graph.addVertex("B0");
309     	graph.addEdge(edgeFactory.create(), "B0", "B1");
310     	graph.addEdge(edgeFactory.create(), "B0", "B2");
311     	graph.addEdge(edgeFactory.create(), "B1", "B4");
312     	graph.addEdge(edgeFactory.create(), "B2", "B3");
313     	graph.addEdge(edgeFactory.create(), "B2", "B5");
314     	graph.addEdge(edgeFactory.create(), "B4", "B6");
315     	graph.addEdge(edgeFactory.create(), "B4", "B7");
316     	graph.addEdge(edgeFactory.create(), "B3", "B8");
317     	graph.addEdge(edgeFactory.create(), "B6", "B9");
318        	
319     }
320 
321         /**
322      * a demo class that will create a vertex shape that is either a
323      * polygon or star. The number of sides corresponds to the number
324      * of vertices that were collapsed into the vertex represented by
325      * this shape.
326      * 
327      * @author Tom Nelson
328      *
329      * @param <V>
330      */
331     class ClusterVertexShapeFunction<V> extends EllipseVertexShapeTransformer<V>
332 {
333 
334         ClusterVertexShapeFunction() {
335             setSizeTransformer(new ClusterVertexSizeFunction<V>(20));
336         }
337         @SuppressWarnings("unchecked")
338 		@Override
339         public Shape transform(V v) {
340             if(v instanceof Graph) {
341                 int size = ((Graph)v).getVertexCount();
342                 if (size < 8) {   
343                     int sides = Math.max(size, 3);
344                     return factory.getRegularPolygon(v, sides);
345                 }
346                 else {
347                     return factory.getRegularStar(v, size);
348                 }
349             }
350             return super.transform(v);
351         }
352     }
353 
354     /**
355      * A demo class that will make vertices larger if they represent
356      * a collapsed collection of original vertices
357      * @author Tom Nelson
358      *
359      * @param <V>
360      */
361     class ClusterVertexSizeFunction<V> implements Transformer<V,Integer> {
362     	int size;
363         public ClusterVertexSizeFunction(Integer size) {
364             this.size = size;
365         }
366 
367         public Integer transform(V v) {
368             if(v instanceof Graph) {
369                 return 30;
370             }
371             return size;
372         }
373     }
374 
375 
376 
377     /**
378      * a driver for this demo
379      */
380     public static void main(String[] args) {
381         JFrame frame = new JFrame();
382         Container content = frame.getContentPane();
383         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
384 
385         content.add(new TreeCollapseDemo());
386         frame.pack();
387         frame.setVisible(true);
388     }
389 }