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