1
2
3
4
5
6
7
8
9 package edu.uci.ics.jung.samples;
10
11 import java.awt.BorderLayout;
12 import java.awt.Color;
13 import java.awt.Component;
14 import java.awt.Container;
15 import java.awt.Dimension;
16 import java.awt.GridLayout;
17 import java.awt.Shape;
18 import java.awt.event.ActionEvent;
19 import java.awt.event.ActionListener;
20 import java.awt.geom.Point2D;
21 import java.lang.reflect.Constructor;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Set;
27
28 import javax.swing.BorderFactory;
29 import javax.swing.DefaultListCellRenderer;
30 import javax.swing.JApplet;
31 import javax.swing.JButton;
32 import javax.swing.JComboBox;
33 import javax.swing.JComponent;
34 import javax.swing.JFrame;
35 import javax.swing.JList;
36 import javax.swing.JOptionPane;
37 import javax.swing.JPanel;
38
39 import org.apache.commons.collections15.Predicate;
40 import org.apache.commons.collections15.Transformer;
41
42 import edu.uci.ics.jung.algorithms.layout.CircleLayout;
43 import edu.uci.ics.jung.algorithms.layout.FRLayout;
44 import edu.uci.ics.jung.algorithms.layout.ISOMLayout;
45 import edu.uci.ics.jung.algorithms.layout.KKLayout;
46 import edu.uci.ics.jung.algorithms.layout.Layout;
47 import edu.uci.ics.jung.algorithms.layout.SpringLayout;
48 import edu.uci.ics.jung.algorithms.layout.SpringLayout2;
49 import edu.uci.ics.jung.graph.Graph;
50 import edu.uci.ics.jung.graph.util.Pair;
51 import edu.uci.ics.jung.graph.util.TestGraphs;
52 import edu.uci.ics.jung.visualization.DefaultVisualizationModel;
53 import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
54 import edu.uci.ics.jung.visualization.VisualizationModel;
55 import edu.uci.ics.jung.visualization.VisualizationViewer;
56 import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
57 import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
58 import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
59 import edu.uci.ics.jung.visualization.control.ScalingControl;
60 import edu.uci.ics.jung.visualization.decorators.EllipseVertexShapeTransformer;
61 import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
62 import edu.uci.ics.jung.visualization.layout.LayoutTransition;
63 import edu.uci.ics.jung.visualization.subLayout.GraphCollapser;
64 import edu.uci.ics.jung.visualization.util.Animator;
65 import edu.uci.ics.jung.visualization.util.PredicatedParallelEdgeIndexFunction;
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82 @SuppressWarnings("serial")
83 public class VertexCollapseDemoWithLayouts extends JApplet {
84
85 String instructions =
86 "<html>Use the mouse to select multiple vertices"+
87 "<p>either by dragging a region, or by shift-clicking"+
88 "<p>on multiple vertices."+
89 "<p>After you select vertices, use the Collapse button"+
90 "<p>to combine them into a single vertex."+
91 "<p>Select a 'collapsed' vertex and use the Expand button"+
92 "<p>to restore the collapsed vertices."+
93 "<p>The Restore button will restore the original graph."+
94 "<p>If you select 2 (and only 2) vertices, then press"+
95 "<p>the Compress Edges button, parallel edges between"+
96 "<p>those two vertices will no longer be expanded."+
97 "<p>If you select 2 (and only 2) vertices, then press"+
98 "<p>the Expand Edges button, parallel edges between"+
99 "<p>those two vertices will be expanded."+
100 "<p>You can drag the vertices with the mouse." +
101 "<p>Use the 'Picking'/'Transforming' combo-box to switch"+
102 "<p>between picking and transforming mode.</html>";
103
104
105
106 Graph graph;
107 Graph collapsedGraph;
108
109
110
111
112 VisualizationViewer vv;
113
114 Layout layout;
115
116 GraphCollapser collapser;
117
118 public VertexCollapseDemoWithLayouts() {
119
120
121 graph =
122 TestGraphs.getOneComponentGraph();
123 collapsedGraph = graph;
124 collapser = new GraphCollapser(graph);
125
126 layout = new FRLayout(graph);
127
128 Dimension preferredSize = new Dimension(400,400);
129 final VisualizationModel visualizationModel =
130 new DefaultVisualizationModel(layout, preferredSize);
131 vv = new VisualizationViewer(visualizationModel, preferredSize);
132
133 vv.getRenderContext().setVertexShapeTransformer(new ClusterVertexShapeFunction());
134
135 final PredicatedParallelEdgeIndexFunction eif = PredicatedParallelEdgeIndexFunction.getInstance();
136 final Set exclusions = new HashSet();
137 eif.setPredicate(new Predicate() {
138
139 public boolean evaluate(Object e) {
140
141 return exclusions.contains(e);
142 }});
143
144
145 vv.getRenderContext().setParallelEdgeIndexFunction(eif);
146
147 vv.setBackground(Color.white);
148
149
150 vv.setVertexToolTipTransformer(new ToStringLabeller() {
151
152
153
154
155 @Override
156 public String transform(Object v) {
157 if(v instanceof Graph) {
158 return ((Graph)v).getVertices().toString();
159 }
160 return super.transform(v);
161 }});
162
163
164
165
166 final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();
167
168 vv.setGraphMouse(graphMouse);
169
170 Container content = getContentPane();
171 GraphZoomScrollPane gzsp = new GraphZoomScrollPane(vv);
172 content.add(gzsp);
173
174 JComboBox modeBox = graphMouse.getModeComboBox();
175 modeBox.addItemListener(graphMouse.getModeListener());
176 graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
177
178 final ScalingControl scaler = new CrossoverScalingControl();
179
180 JButton plus = new JButton("+");
181 plus.addActionListener(new ActionListener() {
182 public void actionPerformed(ActionEvent e) {
183 scaler.scale(vv, 1.1f, vv.getCenter());
184 }
185 });
186 JButton minus = new JButton("-");
187 minus.addActionListener(new ActionListener() {
188 public void actionPerformed(ActionEvent e) {
189 scaler.scale(vv, 1/1.1f, vv.getCenter());
190 }
191 });
192
193 JButton collapse = new JButton("Collapse");
194 collapse.addActionListener(new ActionListener() {
195
196 public void actionPerformed(ActionEvent e) {
197 Collection picked = new HashSet(vv.getPickedVertexState().getPicked());
198 if(picked.size() > 1) {
199 Graph inGraph = layout.getGraph();
200 Graph clusterGraph = collapser.getClusterGraph(inGraph, picked);
201
202 Graph g = collapser.collapse(layout.getGraph(), clusterGraph);
203 collapsedGraph = g;
204 double sumx = 0;
205 double sumy = 0;
206 for(Object v : picked) {
207 Point2D p = (Point2D)layout.transform(v);
208 sumx += p.getX();
209 sumy += p.getY();
210 }
211 Point2D cp = new Point2D.Double(sumx/picked.size(), sumy/picked.size());
212 vv.getRenderContext().getParallelEdgeIndexFunction().reset();
213 layout.setGraph(g);
214 layout.setLocation(clusterGraph, cp);
215 vv.getPickedVertexState().clear();
216 vv.repaint();
217 }
218 }});
219
220 JButton compressEdges = new JButton("Compress Edges");
221 compressEdges.addActionListener(new ActionListener() {
222
223 public void actionPerformed(ActionEvent e) {
224 Collection picked = vv.getPickedVertexState().getPicked();
225 if(picked.size() == 2) {
226 Pair pair = new Pair(picked);
227 Graph graph = layout.getGraph();
228 Collection edges = new HashSet(graph.getIncidentEdges(pair.getFirst()));
229 edges.retainAll(graph.getIncidentEdges(pair.getSecond()));
230 exclusions.addAll(edges);
231 vv.repaint();
232 }
233
234 }});
235
236 JButton expandEdges = new JButton("Expand Edges");
237 expandEdges.addActionListener(new ActionListener() {
238
239 public void actionPerformed(ActionEvent e) {
240 Collection picked = vv.getPickedVertexState().getPicked();
241 if(picked.size() == 2) {
242 Pair pair = new Pair(picked);
243 Graph graph = layout.getGraph();
244 Collection edges = new HashSet(graph.getIncidentEdges(pair.getFirst()));
245 edges.retainAll(graph.getIncidentEdges(pair.getSecond()));
246 exclusions.removeAll(edges);
247 vv.repaint();
248 }
249
250 }});
251
252 JButton expand = new JButton("Expand");
253 expand.addActionListener(new ActionListener() {
254
255 public void actionPerformed(ActionEvent e) {
256 Collection picked = new HashSet(vv.getPickedVertexState().getPicked());
257 for(Object v : picked) {
258 if(v instanceof Graph) {
259
260 Graph g = collapser.expand(layout.getGraph(), (Graph)v);
261 vv.getRenderContext().getParallelEdgeIndexFunction().reset();
262 layout.setGraph(g);
263 }
264 vv.getPickedVertexState().clear();
265 vv.repaint();
266 }
267 }});
268
269 JButton reset = new JButton("Reset");
270 reset.addActionListener(new ActionListener() {
271
272 public void actionPerformed(ActionEvent e) {
273 layout.setGraph(graph);
274 exclusions.clear();
275 vv.repaint();
276 }});
277
278 JButton help = new JButton("Help");
279 help.addActionListener(new ActionListener() {
280 public void actionPerformed(ActionEvent e) {
281 JOptionPane.showMessageDialog((JComponent)e.getSource(), instructions, "Help", JOptionPane.PLAIN_MESSAGE);
282 }
283 });
284 Class[] combos = getCombos();
285 final JComboBox jcb = new JComboBox(combos);
286
287 jcb.setRenderer(new DefaultListCellRenderer() {
288 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
289 String valueString = value.toString();
290 valueString = valueString.substring(valueString.lastIndexOf('.')+1);
291 return super.getListCellRendererComponent(list, valueString, index, isSelected,
292 cellHasFocus);
293 }
294 });
295 jcb.addActionListener(new LayoutChooser(jcb, vv));
296 jcb.setSelectedItem(FRLayout.class);
297
298
299 JPanel controls = new JPanel();
300 JPanel zoomControls = new JPanel(new GridLayout(2,1));
301 zoomControls.setBorder(BorderFactory.createTitledBorder("Zoom"));
302 zoomControls.add(plus);
303 zoomControls.add(minus);
304 controls.add(zoomControls);
305 JPanel collapseControls = new JPanel(new GridLayout(3,1));
306 collapseControls.setBorder(BorderFactory.createTitledBorder("Picked"));
307 collapseControls.add(collapse);
308 collapseControls.add(expand);
309 collapseControls.add(compressEdges);
310 collapseControls.add(expandEdges);
311 collapseControls.add(reset);
312 controls.add(collapseControls);
313 controls.add(modeBox);
314 controls.add(help);
315 controls.add(jcb);
316 content.add(controls, BorderLayout.SOUTH);
317 }
318
319
320
321
322
323
324
325
326
327
328
329 class ClusterVertexShapeFunction<V> extends EllipseVertexShapeTransformer<V> {
330
331 ClusterVertexShapeFunction() {
332 setSizeTransformer(new ClusterVertexSizeFunction<V>(20));
333 }
334 @Override
335 public Shape transform(V v) {
336 if(v instanceof Graph) {
337 int size = ((Graph)v).getVertexCount();
338 if (size < 8) {
339 int sides = Math.max(size, 3);
340 return factory.getRegularPolygon(v, sides);
341 }
342 else {
343 return factory.getRegularStar(v, size);
344 }
345 }
346 return super.transform(v);
347 }
348 }
349
350
351
352
353
354
355
356
357 class ClusterVertexSizeFunction<V> implements Transformer<V,Integer> {
358 int size;
359 public ClusterVertexSizeFunction(Integer size) {
360 this.size = size;
361 }
362
363 public Integer transform(V v) {
364 if(v instanceof Graph) {
365 return 30;
366 }
367 return size;
368 }
369 }
370
371 private class LayoutChooser implements ActionListener
372 {
373 private final JComboBox jcb;
374 private final VisualizationViewer vv;
375
376 private LayoutChooser(JComboBox jcb, VisualizationViewer vv)
377 {
378 super();
379 this.jcb = jcb;
380 this.vv = vv;
381 }
382
383 public void actionPerformed(ActionEvent arg0)
384 {
385 Object[] constructorArgs =
386 { collapsedGraph };
387
388 Class<? extends Layout> layoutC =
389 (Class<? extends Layout>) jcb.getSelectedItem();
390
391 try
392 {
393 Constructor<? extends Layout> constructor = layoutC
394 .getConstructor(new Class[] {Graph.class});
395 Object o = constructor.newInstance(constructorArgs);
396 Layout l = (Layout) o;
397 l.setInitializer(vv.getGraphLayout());
398 l.setSize(vv.getSize());
399 layout = l;
400 LayoutTransition lt =
401 new LayoutTransition(vv, vv.getGraphLayout(), l);
402 Animator animator = new Animator(lt);
403 animator.start();
404 vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
405 vv.repaint();
406
407 }
408 catch (Exception e)
409 {
410 e.printStackTrace();
411 }
412 }
413 }
414
415
416
417 @SuppressWarnings("unchecked")
418 private Class<? extends Layout>[] getCombos()
419 {
420 List<Class<? extends Layout>> layouts = new ArrayList<Class<? extends Layout>>();
421 layouts.add(KKLayout.class);
422 layouts.add(FRLayout.class);
423 layouts.add(CircleLayout.class);
424 layouts.add(SpringLayout.class);
425 layouts.add(SpringLayout2.class);
426 layouts.add(ISOMLayout.class);
427 return layouts.toArray(new Class[0]);
428 }
429
430
431
432
433 public static void main(String[] args) {
434 JFrame f = new JFrame();
435 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
436 f.getContentPane().add(new VertexCollapseDemoWithLayouts());
437 f.pack();
438 f.setVisible(true);
439 }
440 }
441
442