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.event.ActionEvent;
18 import java.awt.event.ActionListener;
19 import java.awt.event.ItemEvent;
20 import java.awt.event.ItemListener;
21 import java.awt.geom.Point2D;
22 import java.lang.reflect.Constructor;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.Map;
26
27 import javax.swing.BorderFactory;
28 import javax.swing.Box;
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 edu.uci.ics.jung.algorithms.layout.AggregateLayout;
40 import edu.uci.ics.jung.algorithms.layout.CircleLayout;
41 import edu.uci.ics.jung.algorithms.layout.FRLayout;
42 import edu.uci.ics.jung.algorithms.layout.KKLayout;
43 import edu.uci.ics.jung.algorithms.layout.Layout;
44 import edu.uci.ics.jung.algorithms.layout.SpringLayout;
45 import edu.uci.ics.jung.graph.Graph;
46 import edu.uci.ics.jung.graph.util.Pair;
47 import edu.uci.ics.jung.graph.util.TestGraphs;
48 import edu.uci.ics.jung.visualization.DefaultVisualizationModel;
49 import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
50 import edu.uci.ics.jung.visualization.VisualizationModel;
51 import edu.uci.ics.jung.visualization.VisualizationViewer;
52 import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
53 import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
54 import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
55 import edu.uci.ics.jung.visualization.control.ScalingControl;
56 import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
57 import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
58 import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
59 import edu.uci.ics.jung.visualization.picking.PickedState;
60
61
62
63
64
65
66
67
68
69
70
71 @SuppressWarnings("serial")
72 public class SubLayoutDemo extends JApplet {
73
74 String instructions =
75 "<html>"+
76 "Use the Layout combobox to select the "+
77 "<p>underlying layout."+
78 "<p>Use the SubLayout combobox to select "+
79 "<p>the type of layout for any clusters you create."+
80 "<p>To create clusters, use the mouse to select "+
81 "<p>multiple vertices, either by dragging a region, "+
82 "<p>or by shift-clicking on multiple vertices."+
83 "<p>After you select vertices, use the "+
84 "<p>Cluster Picked button to cluster them using the "+
85 "<p>layout and size specified in the Sublayout comboboxen."+
86 "<p>Use the Uncluster All button to remove all"+
87 "<p>clusters."+
88 "<p>You can drag the cluster with the mouse." +
89 "<p>Use the 'Picking'/'Transforming' combo-box to switch"+
90 "<p>between picking and transforming mode.</html>";
91
92
93
94 Graph<String,Number> graph;
95
96 Map<Graph<String,Number>,Dimension> sizes = new HashMap<Graph<String,Number>,Dimension>();
97
98 @SuppressWarnings({ "unchecked", "rawtypes" })
99 Class<Layout>[] layoutClasses = new Class[] {
100 CircleLayout.class,SpringLayout.class,FRLayout.class,KKLayout.class
101 };
102
103
104
105 VisualizationViewer<String,Number> vv;
106
107 AggregateLayout<String,Number> clusteringLayout;
108
109 Dimension subLayoutSize;
110
111 PickedState<String> ps;
112
113 @SuppressWarnings("rawtypes")
114 Class<CircleLayout> subLayoutType = CircleLayout.class;
115
116
117
118
119
120
121 public SubLayoutDemo() {
122
123
124 graph = TestGraphs.getOneComponentGraph();
125
126
127
128
129 clusteringLayout = new AggregateLayout<String,Number>(new FRLayout<String,Number>(graph));
130
131
132 Dimension preferredSize = new Dimension(600,600);
133 final VisualizationModel<String,Number> visualizationModel =
134 new DefaultVisualizationModel<String,Number>(clusteringLayout, preferredSize);
135 vv = new VisualizationViewer<String,Number>(visualizationModel, preferredSize);
136
137 ps = vv.getPickedVertexState();
138 vv.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(vv.getPickedEdgeState(), Color.black, Color.red));
139 vv.getRenderContext().setVertexFillPaintTransformer(new PickableVertexPaintTransformer<String>(vv.getPickedVertexState(),
140 Color.red, Color.yellow));
141 vv.setBackground(Color.white);
142
143
144 vv.setVertexToolTipTransformer(new ToStringLabeller());
145
146
147
148
149 final DefaultModalGraphMouse<?, ?> graphMouse = new DefaultModalGraphMouse<Object, Object>();
150
151 vv.setGraphMouse(graphMouse);
152
153 Container content = getContentPane();
154 GraphZoomScrollPane gzsp = new GraphZoomScrollPane(vv);
155 content.add(gzsp);
156
157 JComboBox<?> modeBox = graphMouse.getModeComboBox();
158 modeBox.addItemListener(graphMouse.getModeListener());
159 graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
160
161 final ScalingControl scaler = new CrossoverScalingControl();
162
163 JButton plus = new JButton("+");
164 plus.addActionListener(new ActionListener() {
165 public void actionPerformed(ActionEvent e) {
166 scaler.scale(vv, 1.1f, vv.getCenter());
167 }
168 });
169 JButton minus = new JButton("-");
170 minus.addActionListener(new ActionListener() {
171 public void actionPerformed(ActionEvent e) {
172 scaler.scale(vv, 1/1.1f, vv.getCenter());
173 }
174 });
175
176 JButton cluster = new JButton("Cluster Picked");
177 cluster.addActionListener(new ActionListener() {
178 public void actionPerformed(ActionEvent e) {
179 clusterPicked();
180 }});
181
182 JButton uncluster = new JButton("UnCluster All");
183 uncluster.addActionListener(new ActionListener() {
184 public void actionPerformed(ActionEvent e) {
185 uncluster();
186 }});
187
188 JComboBox<?> layoutTypeComboBox = new JComboBox<Object>(layoutClasses);
189 layoutTypeComboBox.setRenderer(new DefaultListCellRenderer() {
190 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
191 String valueString = value.toString();
192 valueString = valueString.substring(valueString.lastIndexOf('.')+1);
193 return super.getListCellRendererComponent(list, valueString, index, isSelected,
194 cellHasFocus);
195 }
196 });
197 layoutTypeComboBox.setSelectedItem(FRLayout.class);
198 layoutTypeComboBox.addItemListener(new ItemListener() {
199
200 public void itemStateChanged(ItemEvent e) {
201 if(e.getStateChange() == ItemEvent.SELECTED) {
202 @SuppressWarnings({ "unchecked", "rawtypes" })
203 Class<CircleLayout> clazz = (Class<CircleLayout>)e.getItem();
204 try {
205 Layout<String,Number> layout = getLayoutFor(clazz, graph);
206 layout.setInitializer(vv.getGraphLayout());
207 clusteringLayout.setDelegate(layout);
208 vv.setGraphLayout(clusteringLayout);
209 } catch(Exception ex) {
210 ex.printStackTrace();
211 }
212 }
213 }});
214
215 JComboBox<?> subLayoutTypeComboBox = new JComboBox<Object>(layoutClasses);
216
217 subLayoutTypeComboBox.setRenderer(new DefaultListCellRenderer() {
218 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
219 String valueString = value.toString();
220 valueString = valueString.substring(valueString.lastIndexOf('.')+1);
221 return super.getListCellRendererComponent(list, valueString, index, isSelected,
222 cellHasFocus);
223 }
224 });
225 subLayoutTypeComboBox.addItemListener(new ItemListener() {
226
227 @SuppressWarnings({ "unchecked", "rawtypes" })
228 public void itemStateChanged(ItemEvent e) {
229 if(e.getStateChange() == ItemEvent.SELECTED) {
230 subLayoutType = (Class<CircleLayout>)e.getItem();
231 }
232 }});
233
234 JComboBox<?> subLayoutDimensionComboBox =
235 new JComboBox<Object>(new Dimension[]{
236 new Dimension(75,75),
237 new Dimension(100,100),
238 new Dimension(150,150),
239 new Dimension(200,200),
240 new Dimension(250,250),
241 new Dimension(300,300)
242 }
243 );
244 subLayoutDimensionComboBox.setRenderer(new DefaultListCellRenderer() {
245 public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
246 String valueString = value.toString();
247 valueString = valueString.substring(valueString.lastIndexOf('['));
248 valueString = valueString.replaceAll("idth", "");
249 valueString = valueString.replaceAll("eight","");
250 return super.getListCellRendererComponent(list, valueString, index, isSelected,
251 cellHasFocus);
252 }
253 });
254 subLayoutDimensionComboBox.addItemListener(new ItemListener() {
255
256 public void itemStateChanged(ItemEvent e) {
257 if(e.getStateChange() == ItemEvent.SELECTED) {
258 subLayoutSize = (Dimension)e.getItem();
259 }
260 }});
261 subLayoutDimensionComboBox.setSelectedIndex(1);
262
263 JButton help = new JButton("Help");
264 help.addActionListener(new ActionListener() {
265 public void actionPerformed(ActionEvent e) {
266 JOptionPane.showMessageDialog((JComponent)e.getSource(), instructions, "Help", JOptionPane.PLAIN_MESSAGE);
267 }
268 });
269 Dimension space = new Dimension(20,20);
270 Box controls = Box.createVerticalBox();
271 controls.add(Box.createRigidArea(space));
272
273 JPanel zoomControls = new JPanel(new GridLayout(1,2));
274 zoomControls.setBorder(BorderFactory.createTitledBorder("Zoom"));
275 zoomControls.add(plus);
276 zoomControls.add(minus);
277 heightConstrain(zoomControls);
278 controls.add(zoomControls);
279 controls.add(Box.createRigidArea(space));
280
281 JPanel clusterControls = new JPanel(new GridLayout(0,1));
282 clusterControls.setBorder(BorderFactory.createTitledBorder("Clustering"));
283 clusterControls.add(cluster);
284 clusterControls.add(uncluster);
285 heightConstrain(clusterControls);
286 controls.add(clusterControls);
287 controls.add(Box.createRigidArea(space));
288
289 JPanel layoutControls = new JPanel(new GridLayout(0,1));
290 layoutControls.setBorder(BorderFactory.createTitledBorder("Layout"));
291 layoutControls.add(layoutTypeComboBox);
292 heightConstrain(layoutControls);
293 controls.add(layoutControls);
294
295 JPanel subLayoutControls = new JPanel(new GridLayout(0,1));
296 subLayoutControls.setBorder(BorderFactory.createTitledBorder("SubLayout"));
297 subLayoutControls.add(subLayoutTypeComboBox);
298 subLayoutControls.add(subLayoutDimensionComboBox);
299 heightConstrain(subLayoutControls);
300 controls.add(subLayoutControls);
301 controls.add(Box.createRigidArea(space));
302
303 JPanel modePanel = new JPanel(new GridLayout(1,1));
304 modePanel.setBorder(BorderFactory.createTitledBorder("Mouse Mode"));
305 modePanel.add(modeBox);
306 heightConstrain(modePanel);
307 controls.add(modePanel);
308 controls.add(Box.createRigidArea(space));
309
310 controls.add(help);
311 controls.add(Box.createVerticalGlue());
312 content.add(controls, BorderLayout.EAST);
313 }
314
315 private void heightConstrain(Component component) {
316 Dimension d = new Dimension(component.getMaximumSize().width,
317 component.getMinimumSize().height);
318 component.setMaximumSize(d);
319 }
320
321 @SuppressWarnings({ "rawtypes", "unchecked" })
322 private Layout<String, Number> getLayoutFor(Class<CircleLayout> layoutClass, Graph<String, Number> graph) throws Exception {
323 Object[] args = new Object[]{graph};
324 Constructor<CircleLayout> constructor = layoutClass.getConstructor(new Class[] {Graph.class});
325 return constructor.newInstance(args);
326 }
327
328 private void clusterPicked() {
329 cluster(true);
330 }
331
332 private void uncluster() {
333 cluster(false);
334 }
335
336 @SuppressWarnings("unchecked")
337 private void cluster(boolean state) {
338 if(state == true) {
339
340 Collection<String> picked = ps.getPicked();
341 if(picked.size() > 1) {
342 Point2D center = new Point2D.Double();
343 double x = 0;
344 double y = 0;
345 for(String vertex : picked) {
346 Point2D p = clusteringLayout.apply(vertex);
347 x += p.getX();
348 y += p.getY();
349 }
350 x /= picked.size();
351 y /= picked.size();
352 center.setLocation(x,y);
353
354 Graph<String, Number> subGraph;
355 try {
356 subGraph = graph.getClass().newInstance();
357 for(String vertex : picked) {
358 subGraph.addVertex(vertex);
359 Collection<Number> incidentEdges = graph.getIncidentEdges(vertex);
360 for(Number edge : incidentEdges) {
361 Pair<String> endpoints = graph.getEndpoints(edge);
362 if(picked.containsAll(endpoints)) {
363
364 subGraph.addEdge(edge, endpoints.getFirst(), endpoints.getSecond());
365 }
366 }
367 }
368
369 Layout<String,Number> subLayout = getLayoutFor(subLayoutType, subGraph);
370 subLayout.setInitializer(vv.getGraphLayout());
371 subLayout.setSize(subLayoutSize);
372 clusteringLayout.put(subLayout,center);
373 vv.setGraphLayout(clusteringLayout);
374
375 } catch (Exception e) {
376 e.printStackTrace();
377 }
378 }
379 } else {
380
381 this.clusteringLayout.removeAll();
382 vv.setGraphLayout(clusteringLayout);
383 }
384 }
385
386 public static void main(String[] args) {
387 JFrame f = new JFrame();
388 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
389 f.getContentPane().add(new SubLayoutDemo());
390 f.pack();
391 f.setVisible(true);
392 }
393 }