View Javadoc

1   /*
2    * Copyright (c) 2003, the JUNG Project and the Regents of the University of
3    * California All rights reserved.
4    * 
5    * This software is open-source under the BSD license; see either "license.txt"
6    * or http://jung.sourceforge.net/license.txt 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.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   * Demonstrates the AggregateLayout
63   * class. In this demo, vertices are visually clustered as they
64   * are selected. The cluster is formed in a new Layout centered at the
65   * middle locations of the selected vertices. The size and layout
66   * algorithm for each new cluster is selectable.
67   * 
68   * @author Tom Nelson
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       * the graph
93       */
94      Graph<String,Number> graph;
95      
96      Map<Graph<String,Number>,Dimension> sizes = new HashMap<Graph<String,Number>,Dimension>();
97  
98      Class[] layoutClasses = new Class[]{CircleLayout.class,SpringLayout.class,FRLayout.class,KKLayout.class};
99      /**
100      * the visual component and renderer for the graph
101      */
102     VisualizationViewer<String,Number> vv;
103 
104     AggregateLayout<String,Number> clusteringLayout;
105     
106     Dimension subLayoutSize;
107     
108     PickedState<String> ps;
109     
110     Class subLayoutType = CircleLayout.class;
111     
112     /**
113      * create an instance of a simple graph with controls to
114      * demo the zoomand hyperbolic features.
115      * 
116      */
117     public SubLayoutDemo() {
118         
119         // create a simple graph for the demo
120         graph = TestGraphs.getOneComponentGraph();
121 
122         // ClusteringLayout is a decorator class that delegates
123         // to another layout, but can also sepately manage the
124         // layout of sub-sets of vertices in circular clusters.
125         clusteringLayout = new AggregateLayout<String,Number>(new FRLayout<String,Number>(graph));
126         	//new SubLayoutDecorator<String,Number>(new FRLayout<String,Number>(graph));
127 
128         Dimension preferredSize = new Dimension(600,600);
129         final VisualizationModel<String,Number> visualizationModel = 
130             new DefaultVisualizationModel<String,Number>(clusteringLayout, preferredSize);
131         vv =  new VisualizationViewer<String,Number>(visualizationModel, preferredSize);
132         
133         ps = vv.getPickedVertexState();
134         vv.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(vv.getPickedEdgeState(), Color.black, Color.red));
135         vv.getRenderContext().setVertexFillPaintTransformer(new PickableVertexPaintTransformer<String>(vv.getPickedVertexState(), 
136                 Color.red, Color.yellow));
137         vv.setBackground(Color.white);
138         
139         // add a listener for ToolTips
140         vv.setVertexToolTipTransformer(new ToStringLabeller());
141         
142         /**
143          * the regular graph mouse for the normal view
144          */
145         final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();
146 
147         vv.setGraphMouse(graphMouse);
148         
149         Container content = getContentPane();
150         GraphZoomScrollPane gzsp = new GraphZoomScrollPane(vv);
151         content.add(gzsp);
152         
153         JComboBox modeBox = graphMouse.getModeComboBox();
154         modeBox.addItemListener(graphMouse.getModeListener());
155         graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
156         
157         final ScalingControl scaler = new CrossoverScalingControl();
158 
159         JButton plus = new JButton("+");
160         plus.addActionListener(new ActionListener() {
161             public void actionPerformed(ActionEvent e) {
162                 scaler.scale(vv, 1.1f, vv.getCenter());
163             }
164         });
165         JButton minus = new JButton("-");
166         minus.addActionListener(new ActionListener() {
167             public void actionPerformed(ActionEvent e) {
168                 scaler.scale(vv, 1/1.1f, vv.getCenter());
169             }
170         });
171         
172         JButton cluster = new JButton("Cluster Picked");
173         cluster.addActionListener(new ActionListener() {
174 			public void actionPerformed(ActionEvent e) {
175 				clusterPicked();
176 			}});
177         
178         JButton uncluster = new JButton("UnCluster All");
179         uncluster.addActionListener(new ActionListener() {
180 			public void actionPerformed(ActionEvent e) {
181 				uncluster();
182 			}});
183         
184         JComboBox layoutTypeComboBox = new JComboBox(layoutClasses);
185         layoutTypeComboBox.setRenderer(new DefaultListCellRenderer() {
186             public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
187                 String valueString = value.toString();
188                 valueString = valueString.substring(valueString.lastIndexOf('.')+1);
189                 return super.getListCellRendererComponent(list, valueString, index, isSelected,
190                         cellHasFocus);
191             }
192         });
193         layoutTypeComboBox.setSelectedItem(FRLayout.class);
194         layoutTypeComboBox.addItemListener(new ItemListener() {
195 
196 			public void itemStateChanged(ItemEvent e) {
197 				if(e.getStateChange() == ItemEvent.SELECTED) {
198 					Class clazz = (Class)e.getItem();
199 					try {
200 						Layout<String,Number> layout = getLayoutFor(clazz, graph);
201 						layout.setInitializer(vv.getGraphLayout());
202 						clusteringLayout.setDelegate(layout);
203 						vv.setGraphLayout(clusteringLayout);
204 					} catch(Exception ex) {
205 						ex.printStackTrace();
206 					}
207 				}
208 			}});
209         
210         JComboBox subLayoutTypeComboBox = new JComboBox(layoutClasses);
211         
212         subLayoutTypeComboBox.setRenderer(new DefaultListCellRenderer() {
213             public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
214                 String valueString = value.toString();
215                 valueString = valueString.substring(valueString.lastIndexOf('.')+1);
216                 return super.getListCellRendererComponent(list, valueString, index, isSelected,
217                         cellHasFocus);
218             }
219         });
220         subLayoutTypeComboBox.addItemListener(new ItemListener() {
221 
222 			public void itemStateChanged(ItemEvent e) {
223 				if(e.getStateChange() == ItemEvent.SELECTED) {
224 					subLayoutType = (Class)e.getItem();
225 				}
226 			}});
227         
228         JComboBox subLayoutDimensionComboBox = 
229         	new JComboBox(new Dimension[]{
230         			new Dimension(75,75),
231         			new Dimension(100,100),
232         			new Dimension(150,150),
233         			new Dimension(200,200),
234         			new Dimension(250,250),
235         			new Dimension(300,300)
236         	}	
237         	);
238         subLayoutDimensionComboBox.setRenderer(new DefaultListCellRenderer() {
239             public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
240                 String valueString = value.toString();
241                 valueString = valueString.substring(valueString.lastIndexOf('['));
242                 valueString = valueString.replaceAll("idth", "");
243                 valueString = valueString.replaceAll("eight","");
244                 return super.getListCellRendererComponent(list, valueString, index, isSelected,
245                         cellHasFocus);
246             }
247         });
248         subLayoutDimensionComboBox.addItemListener(new ItemListener() {
249 
250 			public void itemStateChanged(ItemEvent e) {
251 				if(e.getStateChange() == ItemEvent.SELECTED) {
252 					subLayoutSize = (Dimension)e.getItem();
253 				}
254 			}});
255         subLayoutDimensionComboBox.setSelectedIndex(1);
256 
257         JButton help = new JButton("Help");
258         help.addActionListener(new ActionListener() {
259             public void actionPerformed(ActionEvent e) {
260                 JOptionPane.showMessageDialog((JComponent)e.getSource(), instructions, "Help", JOptionPane.PLAIN_MESSAGE);
261             }
262         });
263         Dimension space = new Dimension(20,20);
264         Box controls = Box.createVerticalBox();
265         controls.add(Box.createRigidArea(space));
266         
267         JPanel zoomControls = new JPanel(new GridLayout(1,2));
268         zoomControls.setBorder(BorderFactory.createTitledBorder("Zoom"));
269         zoomControls.add(plus);
270         zoomControls.add(minus);
271         heightConstrain(zoomControls);
272         controls.add(zoomControls);
273         controls.add(Box.createRigidArea(space));
274         
275         JPanel clusterControls = new JPanel(new GridLayout(0,1));
276         clusterControls.setBorder(BorderFactory.createTitledBorder("Clustering"));
277         clusterControls.add(cluster);
278         clusterControls.add(uncluster);
279         heightConstrain(clusterControls);
280         controls.add(clusterControls);
281         controls.add(Box.createRigidArea(space));
282         
283         JPanel layoutControls = new JPanel(new GridLayout(0,1));
284         layoutControls.setBorder(BorderFactory.createTitledBorder("Layout"));
285         layoutControls.add(layoutTypeComboBox);
286         heightConstrain(layoutControls);
287         controls.add(layoutControls);
288 
289         JPanel subLayoutControls = new JPanel(new GridLayout(0,1));
290         subLayoutControls.setBorder(BorderFactory.createTitledBorder("SubLayout"));
291         subLayoutControls.add(subLayoutTypeComboBox);
292         subLayoutControls.add(subLayoutDimensionComboBox);
293         heightConstrain(subLayoutControls);
294         controls.add(subLayoutControls);
295         controls.add(Box.createRigidArea(space));
296         
297         JPanel modePanel = new JPanel(new GridLayout(1,1));
298         modePanel.setBorder(BorderFactory.createTitledBorder("Mouse Mode"));
299         modePanel.add(modeBox);
300         heightConstrain(modePanel);
301         controls.add(modePanel);
302         controls.add(Box.createRigidArea(space));
303 
304         controls.add(help);
305         controls.add(Box.createVerticalGlue());
306         content.add(controls, BorderLayout.EAST);
307     }
308     
309     private void heightConstrain(Component component) {
310     	Dimension d = new Dimension(component.getMaximumSize().width,
311     			component.getMinimumSize().height);
312     	component.setMaximumSize(d);
313     }
314     
315     private Layout getLayoutFor(Class layoutClass, Graph graph) throws Exception {
316     	Object[] args = new Object[]{graph};
317     	Constructor constructor = layoutClass.getConstructor(new Class[] {Graph.class});
318     	return  (Layout)constructor.newInstance(args);
319     }
320     
321     private void clusterPicked() {
322     	cluster(true);
323     }
324     
325     private void uncluster() {
326     	cluster(false);
327     }
328 
329     private void cluster(boolean state) {
330     	if(state == true) {
331     		// put the picked vertices into a new sublayout 
332     		Collection<String> picked = ps.getPicked();
333     		if(picked.size() > 1) {
334     			Point2D center = new Point2D.Double();
335     			double x = 0;
336     			double y = 0;
337     			for(String vertex : picked) {
338     				Point2D p = clusteringLayout.transform(vertex);
339     				x += p.getX();
340     				y += p.getY();
341     			}
342     			x /= picked.size();
343     			y /= picked.size();
344 				center.setLocation(x,y);
345 
346 //    			String firstVertex = picked.iterator().next();
347 //    			Point2D center = clusteringLayout.transform(firstVertex);
348     			Graph<String, Number> subGraph;
349     			try {
350     				subGraph = graph.getClass().newInstance();
351     				for(String vertex : picked) {
352     					subGraph.addVertex(vertex);
353     					Collection<Number> incidentEdges = graph.getIncidentEdges(vertex);
354     					for(Number edge : incidentEdges) {
355     						Pair<String> endpoints = graph.getEndpoints(edge);
356     						if(picked.containsAll(endpoints)) {
357     							// put this edge into the subgraph
358     							subGraph.addEdge(edge, endpoints.getFirst(), endpoints.getSecond());
359     						}
360     					}
361     				}
362 
363     				Layout<String,Number> subLayout = getLayoutFor(subLayoutType, subGraph);
364     				subLayout.setInitializer(vv.getGraphLayout());
365     				subLayout.setSize(subLayoutSize);
366     				clusteringLayout.put(subLayout,center);
367     				vv.setGraphLayout(clusteringLayout);
368 
369     			} catch (Exception e) {
370     				e.printStackTrace();
371     			}
372     		}
373     	} else {
374     		// remove all sublayouts
375     		this.clusteringLayout.removeAll();
376     		vv.setGraphLayout(clusteringLayout);
377     	}
378     }
379 
380     /**
381      * a driver for this demo
382      */
383     public static void main(String[] args) {
384         JFrame f = new JFrame();
385         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
386         f.getContentPane().add(new SubLayoutDemo());
387         f.pack();
388         f.setVisible(true);
389     }
390 }