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.Container;
14  import java.awt.Dimension;
15  import java.awt.FontMetrics;
16  import java.awt.Graphics;
17  import java.awt.Graphics2D;
18  import java.awt.GridLayout;
19  import java.awt.Insets;
20  import java.awt.Rectangle;
21  import java.awt.Shape;
22  import java.awt.event.ActionEvent;
23  import java.awt.event.ActionListener;
24  import java.awt.event.ItemEvent;
25  import java.awt.event.ItemListener;
26  import java.awt.geom.AffineTransform;
27  import java.awt.geom.Point2D;
28  import java.awt.geom.Rectangle2D;
29  import java.util.HashMap;
30  import java.util.Map;
31  
32  import javax.swing.BorderFactory;
33  import javax.swing.Box;
34  import javax.swing.ButtonGroup;
35  import javax.swing.Icon;
36  import javax.swing.JApplet;
37  import javax.swing.JButton;
38  import javax.swing.JComponent;
39  import javax.swing.JFrame;
40  import javax.swing.JLabel;
41  import javax.swing.JMenuBar;
42  import javax.swing.JPanel;
43  import javax.swing.JRadioButton;
44  import javax.swing.plaf.basic.BasicLabelUI;
45  
46  import org.apache.commons.collections15.Transformer;
47  import org.apache.commons.collections15.TransformerUtils;
48  import org.apache.commons.collections15.functors.ConstantTransformer;
49  
50  import edu.uci.ics.jung.algorithms.layout.FRLayout;
51  import edu.uci.ics.jung.algorithms.layout.Layout;
52  import edu.uci.ics.jung.algorithms.layout.StaticLayout;
53  import edu.uci.ics.jung.graph.Graph;
54  import edu.uci.ics.jung.graph.SparseGraph;
55  import edu.uci.ics.jung.graph.util.TestGraphs;
56  import edu.uci.ics.jung.visualization.DefaultVisualizationModel;
57  import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
58  import edu.uci.ics.jung.visualization.Layer;
59  import edu.uci.ics.jung.visualization.VisualizationModel;
60  import edu.uci.ics.jung.visualization.VisualizationViewer;
61  import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
62  import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
63  import edu.uci.ics.jung.visualization.control.LensMagnificationGraphMousePlugin;
64  import edu.uci.ics.jung.visualization.control.ModalLensGraphMouse;
65  import edu.uci.ics.jung.visualization.control.ScalingControl;
66  import edu.uci.ics.jung.visualization.decorators.PickableEdgePaintTransformer;
67  import edu.uci.ics.jung.visualization.decorators.PickableVertexPaintTransformer;
68  import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
69  import edu.uci.ics.jung.visualization.picking.PickedState;
70  import edu.uci.ics.jung.visualization.transform.HyperbolicTransformer;
71  import edu.uci.ics.jung.visualization.transform.LayoutLensSupport;
72  import edu.uci.ics.jung.visualization.transform.LensSupport;
73  import edu.uci.ics.jung.visualization.transform.MagnifyTransformer;
74  import edu.uci.ics.jung.visualization.transform.shape.HyperbolicShapeTransformer;
75  import edu.uci.ics.jung.visualization.transform.shape.MagnifyShapeTransformer;
76  import edu.uci.ics.jung.visualization.transform.shape.ViewLensSupport;
77  
78  /**
79   * Demonstrates the use of <code>HyperbolicTransform</code>
80   * and <code>MagnifyTransform</code>
81   * applied to either the model (graph layout) or the view
82   * (VisualizationViewer)
83   * The hyperbolic transform is applied in an elliptical lens
84   * that affects that part of the visualization.
85   * 
86   * @author Tom Nelson
87   * 
88   */
89  @SuppressWarnings("serial")
90  public class LensDemo extends JApplet {
91  
92      /**
93       * the graph
94       */
95      Graph<String,Number> graph;
96      
97      Layout<String,Number> graphLayout;
98      
99      /**
100      * a grid shaped graph
101      */
102     Graph<String,Number> grid;
103     
104     Layout<String,Number> gridLayout;
105 
106     /**
107      * the visual component and renderer for the graph
108      */
109     VisualizationViewer<String,Number> vv;
110 
111     /**
112      * provides a Hyperbolic lens for the view
113      */
114     LensSupport hyperbolicViewSupport;
115     /**
116      * provides a magnification lens for the view
117      */
118     LensSupport magnifyViewSupport;
119     
120     /**
121      * provides a Hyperbolic lens for the model
122      */
123     LensSupport hyperbolicLayoutSupport;
124     /**
125      * provides a magnification lens for the model
126      */
127     LensSupport magnifyLayoutSupport;
128     
129     ScalingControl scaler;
130     
131     /**
132      * create an instance of a simple graph with controls to
133      * demo the zoomand hyperbolic features.
134      * 
135      */
136     public LensDemo() {
137         
138         // create a simple graph for the demo
139         graph = TestGraphs.getOneComponentGraph();
140         
141         graphLayout = new FRLayout<String,Number>(graph);
142         ((FRLayout)graphLayout).setMaxIterations(1000);
143 
144         Dimension preferredSize = new Dimension(600,600);
145         Map<String,Point2D> map = new HashMap<String,Point2D>();
146         Transformer<String,Point2D> vlf =
147         	TransformerUtils.mapTransformer(map);
148         grid = this.generateVertexGrid(map, preferredSize, 25);
149         gridLayout = new StaticLayout<String,Number>(grid, vlf, preferredSize);
150         
151         final VisualizationModel<String,Number> visualizationModel = 
152             new DefaultVisualizationModel<String,Number>(graphLayout, preferredSize);
153         vv =  new VisualizationViewer<String,Number>(visualizationModel, preferredSize);
154 
155         PickedState<String> ps = vv.getPickedVertexState();
156         PickedState<Number> pes = vv.getPickedEdgeState();
157         vv.getRenderContext().setVertexFillPaintTransformer(new PickableVertexPaintTransformer<String>(ps, Color.red, Color.yellow));
158         vv.getRenderContext().setEdgeDrawPaintTransformer(new PickableEdgePaintTransformer<Number>(pes, Color.black, Color.cyan));
159         vv.setBackground(Color.white);
160         
161         vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
162         
163         final Transformer<String,Shape> ovals = vv.getRenderContext().getVertexShapeTransformer();
164         final Transformer<String,Shape> squares = 
165         	new ConstantTransformer(new Rectangle2D.Float(-10,-10,20,20));
166 
167         // add a listener for ToolTips
168         vv.setVertexToolTipTransformer(new ToStringLabeller());
169         
170         Container content = getContentPane();
171         GraphZoomScrollPane gzsp = new GraphZoomScrollPane(vv);
172         content.add(gzsp);
173         
174         /**
175          * the regular graph mouse for the normal view
176          */
177         final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();
178 
179         vv.setGraphMouse(graphMouse);
180         vv.addKeyListener(graphMouse.getModeKeyListener());
181         
182         hyperbolicViewSupport = 
183             new ViewLensSupport<String,Number>(vv, new HyperbolicShapeTransformer(vv, 
184             		vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW)), 
185                     new ModalLensGraphMouse());
186         hyperbolicLayoutSupport = 
187             new LayoutLensSupport<String,Number>(vv, new HyperbolicTransformer(vv, 
188             		vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT)),
189                     new ModalLensGraphMouse());
190         magnifyViewSupport = 
191             new ViewLensSupport<String,Number>(vv, new MagnifyShapeTransformer(vv,
192             		vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.VIEW)),
193                     new ModalLensGraphMouse(new LensMagnificationGraphMousePlugin(1.f, 6.f, .2f)));
194         magnifyLayoutSupport = 
195             new LayoutLensSupport<String,Number>(vv, new MagnifyTransformer(vv, 
196             		vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT)),
197                     new ModalLensGraphMouse(new LensMagnificationGraphMousePlugin(1.f, 6.f, .2f)));
198         hyperbolicLayoutSupport.getLensTransformer().setLensShape(hyperbolicViewSupport.getLensTransformer().getLensShape());
199         magnifyViewSupport.getLensTransformer().setLensShape(hyperbolicLayoutSupport.getLensTransformer().getLensShape());
200         magnifyLayoutSupport.getLensTransformer().setLensShape(magnifyViewSupport.getLensTransformer().getLensShape());
201         
202         final ScalingControl scaler = new CrossoverScalingControl();
203 
204         JButton plus = new JButton("+");
205         plus.addActionListener(new ActionListener() {
206             public void actionPerformed(ActionEvent e) {
207                 scaler.scale(vv, 1.1f, vv.getCenter());
208             }
209         });
210         JButton minus = new JButton("-");
211         minus.addActionListener(new ActionListener() {
212             public void actionPerformed(ActionEvent e) {
213                 scaler.scale(vv, 1/1.1f, vv.getCenter());
214             }
215         });
216         
217         ButtonGroup radio = new ButtonGroup();
218         JRadioButton normal = new JRadioButton("None");
219         normal.addItemListener(new ItemListener() {
220             public void itemStateChanged(ItemEvent e) {
221                 if(e.getStateChange() == ItemEvent.SELECTED) {
222                     if(hyperbolicViewSupport != null) {
223                         hyperbolicViewSupport.deactivate();
224                     }
225                     if(hyperbolicLayoutSupport != null) {
226                         hyperbolicLayoutSupport.deactivate();
227                     }
228                     if(magnifyViewSupport != null) {
229                         magnifyViewSupport.deactivate();
230                     }
231                     if(magnifyLayoutSupport != null) {
232                         magnifyLayoutSupport.deactivate();
233                     }
234                 }
235             }
236         });
237 
238         final JRadioButton hyperView = new JRadioButton("Hyperbolic View");
239         hyperView.addItemListener(new ItemListener(){
240             public void itemStateChanged(ItemEvent e) {
241                 hyperbolicViewSupport.activate(e.getStateChange() == ItemEvent.SELECTED);
242             }
243         });
244         final JRadioButton hyperModel = new JRadioButton("Hyperbolic Layout");
245         hyperModel.addItemListener(new ItemListener(){
246             public void itemStateChanged(ItemEvent e) {
247                 hyperbolicLayoutSupport.activate(e.getStateChange() == ItemEvent.SELECTED);
248             }
249         });
250         final JRadioButton magnifyView = new JRadioButton("Magnified View");
251         magnifyView.addItemListener(new ItemListener(){
252             public void itemStateChanged(ItemEvent e) {
253                 magnifyViewSupport.activate(e.getStateChange() == ItemEvent.SELECTED);
254             }
255         });
256         final JRadioButton magnifyModel = new JRadioButton("Magnified Layout");
257         magnifyModel.addItemListener(new ItemListener(){
258             public void itemStateChanged(ItemEvent e) {
259                 magnifyLayoutSupport.activate(e.getStateChange() == ItemEvent.SELECTED);
260             }
261         });
262         JLabel modeLabel = new JLabel("     Mode Menu >>");
263         modeLabel.setUI(new VerticalLabelUI(false));
264         radio.add(normal);
265         radio.add(hyperModel);
266         radio.add(hyperView);
267         radio.add(magnifyModel);
268         radio.add(magnifyView);
269         normal.setSelected(true);
270         
271         graphMouse.addItemListener(hyperbolicLayoutSupport.getGraphMouse().getModeListener());
272         graphMouse.addItemListener(hyperbolicViewSupport.getGraphMouse().getModeListener());
273         graphMouse.addItemListener(magnifyLayoutSupport.getGraphMouse().getModeListener());
274         graphMouse.addItemListener(magnifyViewSupport.getGraphMouse().getModeListener());
275         
276         ButtonGroup graphRadio = new ButtonGroup();
277         JRadioButton graphButton = new JRadioButton("Graph");
278         graphButton.setSelected(true);
279         graphButton.addItemListener(new ItemListener() {
280 
281             public void itemStateChanged(ItemEvent e) {
282                 if(e.getStateChange() == ItemEvent.SELECTED) {
283                     visualizationModel.setGraphLayout(graphLayout);
284                     vv.getRenderContext().setVertexShapeTransformer(ovals);
285                     vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
286                     vv.repaint();
287                 }
288             }});
289         JRadioButton gridButton = new JRadioButton("Grid");
290         gridButton.addItemListener(new ItemListener() {
291 
292             public void itemStateChanged(ItemEvent e) {
293                 if(e.getStateChange() == ItemEvent.SELECTED) {
294                     visualizationModel.setGraphLayout(gridLayout);
295                     vv.getRenderContext().setVertexShapeTransformer(squares);
296                     vv.getRenderContext().setVertexLabelTransformer(new ConstantTransformer(null));
297                     vv.repaint();
298                 }
299             }});
300         graphRadio.add(graphButton);
301         graphRadio.add(gridButton);
302         
303         JPanel modePanel = new JPanel(new GridLayout(3,1));
304         modePanel.setBorder(BorderFactory.createTitledBorder("Display"));
305         modePanel.add(graphButton);
306         modePanel.add(gridButton);
307 
308         JMenuBar menubar = new JMenuBar();
309         menubar.add(graphMouse.getModeMenu());
310         gzsp.setCorner(menubar);
311         
312 
313         Box controls = Box.createHorizontalBox();
314         JPanel zoomControls = new JPanel(new GridLayout(2,1));
315         zoomControls.setBorder(BorderFactory.createTitledBorder("Zoom"));
316         JPanel hyperControls = new JPanel(new GridLayout(3,2));
317         hyperControls.setBorder(BorderFactory.createTitledBorder("Examiner Lens"));
318         zoomControls.add(plus);
319         zoomControls.add(minus);
320         
321         hyperControls.add(normal);
322         hyperControls.add(new JLabel());
323 
324         hyperControls.add(hyperModel);
325         hyperControls.add(magnifyModel);
326         
327         hyperControls.add(hyperView);
328         hyperControls.add(magnifyView);
329         
330         controls.add(zoomControls);
331         controls.add(hyperControls);
332         controls.add(modePanel);
333         controls.add(modeLabel);
334         content.add(controls, BorderLayout.SOUTH);
335     }
336 
337     private Graph<String,Number> generateVertexGrid(Map<String,Point2D> vlf,
338             Dimension d, int interval) {
339         int count = d.width/interval * d.height/interval;
340         Graph<String,Number> graph = new SparseGraph<String,Number>();
341         for(int i=0; i<count; i++) {
342             int x = interval*i;
343             int y = x / d.width * interval;
344             x %= d.width;
345             
346             Point2D location = new Point2D.Float(x, y);
347             String vertex = "v"+i;
348             vlf.put(vertex, location);
349             graph.addVertex(vertex);
350         }
351         return graph;
352     }
353     
354     static class VerticalLabelUI extends BasicLabelUI
355     {
356     	static {
357     		labelUI = new VerticalLabelUI(false);
358     	}
359     	
360     	protected boolean clockwise;
361     	VerticalLabelUI( boolean clockwise )
362     	{
363     		super();
364     		this.clockwise = clockwise;
365     	}
366     	
367 
368         public Dimension getPreferredSize(JComponent c) 
369         {
370         	Dimension dim = super.getPreferredSize(c);
371         	return new Dimension( dim.height, dim.width );
372         }	
373 
374         private static Rectangle paintIconR = new Rectangle();
375         private static Rectangle paintTextR = new Rectangle();
376         private static Rectangle paintViewR = new Rectangle();
377         private static Insets paintViewInsets = new Insets(0, 0, 0, 0);
378 
379     	public void paint(Graphics g, JComponent c) 
380         {
381 
382         	
383             JLabel label = (JLabel)c;
384             String text = label.getText();
385             Icon icon = (label.isEnabled()) ? label.getIcon() : label.getDisabledIcon();
386 
387             if ((icon == null) && (text == null)) {
388                 return;
389             }
390 
391             FontMetrics fm = g.getFontMetrics();
392             paintViewInsets = c.getInsets(paintViewInsets);
393 
394             paintViewR.x = paintViewInsets.left;
395             paintViewR.y = paintViewInsets.top;
396         	
397         	// Use inverted height & width
398             paintViewR.height = c.getWidth() - (paintViewInsets.left + paintViewInsets.right);
399             paintViewR.width = c.getHeight() - (paintViewInsets.top + paintViewInsets.bottom);
400 
401             paintIconR.x = paintIconR.y = paintIconR.width = paintIconR.height = 0;
402             paintTextR.x = paintTextR.y = paintTextR.width = paintTextR.height = 0;
403 
404             String clippedText = 
405                 layoutCL(label, fm, text, icon, paintViewR, paintIconR, paintTextR);
406 
407         	Graphics2D g2 = (Graphics2D) g;
408         	AffineTransform tr = g2.getTransform();
409         	if( clockwise )
410         	{
411     	    	g2.rotate( Math.PI / 2 ); 
412         		g2.translate( 0, - c.getWidth() );
413         	}
414         	else
415         	{
416     	    	g2.rotate( - Math.PI / 2 ); 
417         		g2.translate( - c.getHeight(), 0 );
418         	}
419 
420         	if (icon != null) {
421                 icon.paintIcon(c, g, paintIconR.x, paintIconR.y);
422             }
423 
424             if (text != null) {
425                 int textX = paintTextR.x;
426                 int textY = paintTextR.y + fm.getAscent();
427 
428                 if (label.isEnabled()) {
429                     paintEnabledText(label, g, clippedText, textX, textY);
430                 }
431                 else {
432                     paintDisabledText(label, g, clippedText, textX, textY);
433                 }
434             }
435         	
436         	
437         	g2.setTransform( tr );
438         }
439     }
440 
441 
442 
443 
444     /**
445      * a driver for this demo
446      */
447     public static void main(String[] args) {
448         JFrame f = new JFrame();
449         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
450         f.getContentPane().add(new LensDemo());
451         f.pack();
452         f.setVisible(true);
453     }
454 }