1 package edu.uci.ics.jung.samples;
2
3
4
5
6
7
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
69
70
71
72 @SuppressWarnings("serial")
73 public class TreeCollapseDemo extends JApplet {
74
75
76
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
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
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
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
183 vv.setGraphLayout(radialLayout);
184 vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
185 vv.addPreRenderPaintable(rings);
186 } else {
187
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
208 e1.printStackTrace();
209 } catch (IllegalAccessException e1) {
210
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
323
324
325
326
327
328
329
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
356
357
358
359
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
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 }