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.Graphics2D;
16  import java.awt.event.ActionEvent;
17  import java.awt.event.ActionListener;
18  import java.awt.image.BufferedImage;
19  import java.awt.print.Printable;
20  import java.awt.print.PrinterJob;
21  import java.io.File;
22  import java.util.HashMap;
23  
24  import javax.imageio.ImageIO;
25  import javax.swing.AbstractAction;
26  import javax.swing.JApplet;
27  import javax.swing.JButton;
28  import javax.swing.JComboBox;
29  import javax.swing.JFileChooser;
30  import javax.swing.JFrame;
31  import javax.swing.JMenu;
32  import javax.swing.JMenuBar;
33  import javax.swing.JOptionPane;
34  import javax.swing.JPanel;
35  import javax.swing.JPopupMenu;
36  
37  import org.apache.commons.collections15.Factory;
38  import org.apache.commons.collections15.functors.MapTransformer;
39  import org.apache.commons.collections15.map.LazyMap;
40  
41  import edu.uci.ics.jung.algorithms.layout.AbstractLayout;
42  import edu.uci.ics.jung.algorithms.layout.StaticLayout;
43  import edu.uci.ics.jung.graph.Graph;
44  import edu.uci.ics.jung.graph.SparseMultigraph;
45  import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
46  import edu.uci.ics.jung.visualization.VisualizationViewer;
47  import edu.uci.ics.jung.visualization.annotations.AnnotationControls;
48  import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
49  import edu.uci.ics.jung.visualization.control.EditingModalGraphMouse;
50  import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
51  import edu.uci.ics.jung.visualization.control.ScalingControl;
52  import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
53  
54  /**
55   * Shows how  to create a graph editor with JUNG.
56   * Mouse modes and actions are explained in the help text.
57   * The application version of GraphEditorDemo provides a
58   * File menu with an option to save the visible graph as
59   * a jpeg file.
60   * 
61   * @author Tom Nelson
62   * 
63   */
64  public class GraphEditorDemo extends JApplet implements Printable {
65  
66      /**
67  	 * 
68  	 */
69  	private static final long serialVersionUID = -2023243689258876709L;
70  
71  	/**
72       * the graph
73       */
74      Graph<Number,Number> graph;
75      
76      AbstractLayout<Number,Number> layout;
77  
78      /**
79       * the visual component and renderer for the graph
80       */
81      VisualizationViewer<Number,Number> vv;
82      
83      String instructions =
84          "<html>"+
85          "<h3>All Modes:</h3>"+
86          "<ul>"+
87          "<li>Right-click an empty area for <b>Create Vertex</b> popup"+
88          "<li>Right-click on a Vertex for <b>Delete Vertex</b> popup"+
89          "<li>Right-click on a Vertex for <b>Add Edge</b> menus <br>(if there are selected Vertices)"+
90          "<li>Right-click on an Edge for <b>Delete Edge</b> popup"+
91          "<li>Mousewheel scales with a crossover value of 1.0.<p>"+
92          "     - scales the graph layout when the combined scale is greater than 1<p>"+
93          "     - scales the graph view when the combined scale is less than 1"+
94  
95          "</ul>"+
96          "<h3>Editing Mode:</h3>"+
97          "<ul>"+
98          "<li>Left-click an empty area to create a new Vertex"+
99          "<li>Left-click on a Vertex and drag to another Vertex to create an Undirected Edge"+
100         "<li>Shift+Left-click on a Vertex and drag to another Vertex to create a Directed Edge"+
101         "</ul>"+
102         "<h3>Picking Mode:</h3>"+
103         "<ul>"+
104         "<li>Mouse1 on a Vertex selects the vertex"+
105         "<li>Mouse1 elsewhere unselects all Vertices"+
106         "<li>Mouse1+Shift on a Vertex adds/removes Vertex selection"+
107         "<li>Mouse1+drag on a Vertex moves all selected Vertices"+
108         "<li>Mouse1+drag elsewhere selects Vertices in a region"+
109         "<li>Mouse1+Shift+drag adds selection of Vertices in a new region"+
110         "<li>Mouse1+CTRL on a Vertex selects the vertex and centers the display on it"+
111         "<li>Mouse1 double-click on a vertex or edge allows you to edit the label"+
112         "</ul>"+
113         "<h3>Transforming Mode:</h3>"+
114         "<ul>"+
115         "<li>Mouse1+drag pans the graph"+
116         "<li>Mouse1+Shift+drag rotates the graph"+
117         "<li>Mouse1+CTRL(or Command)+drag shears the graph"+
118         "<li>Mouse1 double-click on a vertex or edge allows you to edit the label"+
119         "</ul>"+
120         "<h3>Annotation Mode:</h3>"+
121         "<ul>"+
122         "<li>Mouse1 begins drawing of a Rectangle"+
123         "<li>Mouse1+drag defines the Rectangle shape"+
124         "<li>Mouse1 release adds the Rectangle as an annotation"+
125         "<li>Mouse1+Shift begins drawing of an Ellipse"+
126         "<li>Mouse1+Shift+drag defines the Ellipse shape"+
127         "<li>Mouse1+Shift release adds the Ellipse as an annotation"+
128         "<li>Mouse3 shows a popup to input text, which will become"+
129         "<li>a text annotation on the graph at the mouse location"+
130         "</ul>"+
131         "</html>";
132     
133     /**
134      * create an instance of a simple graph with popup controls to
135      * create a graph.
136      * 
137      */
138     public GraphEditorDemo() {
139         
140         // create a simple graph for the demo
141         graph = new SparseMultigraph<Number,Number>();
142 
143         this.layout = new StaticLayout<Number,Number>(graph, 
144         	new Dimension(600,600));
145         
146         vv =  new VisualizationViewer<Number,Number>(layout);
147         vv.setBackground(Color.white);
148 
149         vv.getRenderContext().setVertexLabelTransformer(MapTransformer.<Number,String>getInstance(
150         		LazyMap.<Number,String>decorate(new HashMap<Number,String>(), new ToStringLabeller<Number>())));
151         
152         vv.getRenderContext().setEdgeLabelTransformer(MapTransformer.<Number,String>getInstance(
153         		LazyMap.<Number,String>decorate(new HashMap<Number,String>(), new ToStringLabeller<Number>())));
154 
155         vv.setVertexToolTipTransformer(vv.getRenderContext().getVertexLabelTransformer());
156         
157 
158         Container content = getContentPane();
159         final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
160         content.add(panel);
161         Factory<Number> vertexFactory = new VertexFactory();
162         Factory<Number> edgeFactory = new EdgeFactory();
163         
164         final EditingModalGraphMouse<Number,Number> graphMouse = 
165         	new EditingModalGraphMouse<Number,Number>(vv.getRenderContext(), vertexFactory, edgeFactory);
166         
167         // the EditingGraphMouse will pass mouse event coordinates to the
168         // vertexLocations function to set the locations of the vertices as
169         // they are created
170 //        graphMouse.setVertexLocations(vertexLocations);
171         vv.setGraphMouse(graphMouse);
172         vv.addKeyListener(graphMouse.getModeKeyListener());
173 
174         graphMouse.setMode(ModalGraphMouse.Mode.EDITING);
175         
176         final ScalingControl scaler = new CrossoverScalingControl();
177         JButton plus = new JButton("+");
178         plus.addActionListener(new ActionListener() {
179             public void actionPerformed(ActionEvent e) {
180                 scaler.scale(vv, 1.1f, vv.getCenter());
181             }
182         });
183         JButton minus = new JButton("-");
184         minus.addActionListener(new ActionListener() {
185             public void actionPerformed(ActionEvent e) {
186                 scaler.scale(vv, 1/1.1f, vv.getCenter());
187             }
188         });
189         
190         JButton help = new JButton("Help");
191         help.addActionListener(new ActionListener() {
192 
193             public void actionPerformed(ActionEvent e) {
194                 JOptionPane.showMessageDialog(vv, instructions);
195             }});
196 
197         AnnotationControls<Number,Number> annotationControls = 
198         	new AnnotationControls<Number,Number>(graphMouse.getAnnotatingPlugin());
199         JPanel controls = new JPanel();
200         controls.add(plus);
201         controls.add(minus);
202         JComboBox modeBox = graphMouse.getModeComboBox();
203         controls.add(modeBox);
204         controls.add(annotationControls.getAnnotationsToolBar());
205         controls.add(help);
206         content.add(controls, BorderLayout.SOUTH);
207     }
208     
209     /**
210      * copy the visible part of the graph to a file as a jpeg image
211      * @param file
212      */
213     public void writeJPEGImage(File file) {
214         int width = vv.getWidth();
215         int height = vv.getHeight();
216 
217         BufferedImage bi = new BufferedImage(width, height,
218                 BufferedImage.TYPE_INT_RGB);
219         Graphics2D graphics = bi.createGraphics();
220         vv.paint(graphics);
221         graphics.dispose();
222         
223         try {
224             ImageIO.write(bi, "jpeg", file);
225         } catch (Exception e) {
226             e.printStackTrace();
227         }
228     }
229     
230     public int print(java.awt.Graphics graphics,
231             java.awt.print.PageFormat pageFormat, int pageIndex)
232             throws java.awt.print.PrinterException {
233         if (pageIndex > 0) {
234             return (Printable.NO_SUCH_PAGE);
235         } else {
236             java.awt.Graphics2D g2d = (java.awt.Graphics2D) graphics;
237             vv.setDoubleBuffered(false);
238             g2d.translate(pageFormat.getImageableX(), pageFormat
239                     .getImageableY());
240 
241             vv.paint(g2d);
242             vv.setDoubleBuffered(true);
243 
244             return (Printable.PAGE_EXISTS);
245         }
246     }
247     
248     class VertexFactory implements Factory<Number> {
249 
250     	int i=0;
251 
252 		public Number create() {
253 			return i++;
254 		}
255     }
256     
257     class EdgeFactory implements Factory<Number> {
258 
259     	int i=0;
260     	
261 		public Number create() {
262 			return i++;
263 		}
264     }
265 
266     /**
267      * a driver for this demo
268      */
269     @SuppressWarnings("serial")
270 	public static void main(String[] args) {
271         JFrame frame = new JFrame();
272         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
273         final GraphEditorDemo demo = new GraphEditorDemo();
274         
275         JMenu menu = new JMenu("File");
276         menu.add(new AbstractAction("Make Image") {
277             public void actionPerformed(ActionEvent e) {
278                 JFileChooser chooser  = new JFileChooser();
279                 int option = chooser.showSaveDialog(demo);
280                 if(option == JFileChooser.APPROVE_OPTION) {
281                     File file = chooser.getSelectedFile();
282                     demo.writeJPEGImage(file);
283                 }
284             }});
285         menu.add(new AbstractAction("Print") {
286             public void actionPerformed(ActionEvent e) {
287                     PrinterJob printJob = PrinterJob.getPrinterJob();
288                     printJob.setPrintable(demo);
289                     if (printJob.printDialog()) {
290                         try {
291                             printJob.print();
292                         } catch (Exception ex) {
293                             ex.printStackTrace();
294                         }
295                     }
296             }});
297         JPopupMenu.setDefaultLightWeightPopupEnabled(false);
298         JMenuBar menuBar = new JMenuBar();
299         menuBar.add(menu);
300         frame.setJMenuBar(menuBar);
301         frame.getContentPane().add(demo);
302         frame.pack();
303         frame.setVisible(true);
304     }
305 }
306