1   /****************************************************************************
2    **
3    ** This file is part of the yFiles extension package ySVG-2.3.
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2002-2010 by yWorks GmbH, Vor dem Kreuzberg 28,
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.yext.svg;
15  
16  import y.io.GraphMLIOHandler;
17  import y.option.OptionHandler;
18  import y.util.D;
19  import y.view.EditMode;
20  import y.view.Graph2DPrinter;
21  import y.view.Graph2DView;
22  import y.view.Graph2DViewActions;
23  import y.view.Graph2DViewMouseWheelZoomListener;
24  
25  import javax.swing.AbstractAction;
26  import javax.swing.Action;
27  import javax.swing.ImageIcon;
28  import javax.swing.InputMap;
29  import javax.swing.JComponent;
30  import javax.swing.JFileChooser;
31  import javax.swing.JFrame;
32  import javax.swing.JMenu;
33  import javax.swing.JMenuBar;
34  import javax.swing.JPanel;
35  import javax.swing.JRootPane;
36  import javax.swing.JToolBar;
37  import javax.swing.UIManager;
38  import javax.swing.filechooser.FileFilter;
39  
40  import java.awt.BorderLayout;
41  import java.awt.Rectangle;
42  import java.awt.EventQueue;
43  import java.awt.event.ActionEvent;
44  import java.awt.print.PageFormat;
45  import java.awt.print.PrinterException;
46  import java.awt.print.PrinterJob;
47  import java.io.File;
48  import java.io.IOException;
49  import java.net.URL;
50  
51  /**
52   * Demonstrates basic usage of the Graph2DView.
53   * <p>
54   * Demonstrates how some actions can be performed on the view.
55   * The actions are:
56   * </p>
57   * <ul>
58   *   <li>Remove selected parts of the view content</li>
59   *   <li>Zoom out of the view</li>
60   *   <li>Zoom in on the view</li>
61   *   <li>Reset the zoom in on the view</li>
62   *   <li>Fit view content to the size of the the view</li>
63   *   <li>Print a graph</li>
64   *   <li>Load a graph in GraphML format</li>
65   *   <li>Save a graph in GraphML format</li>
66   * </ul>
67   * <p>
68   * Additionally, this demo shows how to set up the default edit mode
69   * to display tool tips over nodes.
70   * </p>
71   */
72  public class ViewActionDemo extends JPanel {
73  
74    /**
75     * The view component of this demo.
76     */
77    protected Graph2DView view;
78    /**
79     * The view mode to be used with the view.
80     */
81    protected EditMode editMode;
82  
83  
84    public ViewActionDemo() {
85      setLayout(new BorderLayout());
86  
87      view = new Graph2DView();
88      view.setAntialiasedPainting(true);
89      view.getCanvasComponent().addMouseWheelListener(new Graph2DViewMouseWheelZoomListener());
90  
91      editMode = createEditMode();
92      if (editMode != null) {
93        view.addViewMode(editMode);
94      }
95  
96      Graph2DViewActions actions = new Graph2DViewActions(view);
97      InputMap imap = actions.createDefaultInputMap();
98      view.getCanvasComponent().setInputMap(JComponent.WHEN_FOCUSED, imap);
99  
100     add(view, BorderLayout.CENTER);
101     add(createToolBar(), BorderLayout.NORTH);
102   }
103 
104   protected EditMode createEditMode() {
105     final EditMode editMode = new EditMode();
106     editMode.showNodeTips(true);
107     return editMode;
108   }
109 
110   /**
111    * Creates a toolbar for this demo.
112    * @return the application toolbar.
113    */
114   protected JToolBar createToolBar() {
115     JToolBar bar = new JToolBar();
116     bar.add(new DeleteSelection());
117     bar.add(new Zoom(1.2));
118     bar.add(new Zoom(0.8));
119     bar.add(new ResetZoom());
120     bar.add(new FitContent());
121 
122     return bar;
123   }
124 
125   /**
126    * Create a menu bar for this demo.
127    * @return the application menu bar.
128    */
129   protected JMenuBar createMenuBar() {
130     JMenuBar bar = new JMenuBar();
131     JMenu menu = new JMenu("File");
132     menu.add(createLoadAction());
133     menu.add(createSaveAction());
134     menu.addSeparator();
135     menu.add(new PrintAction());
136     menu.addSeparator();
137     menu.add(new ExitAction());
138     bar.add(menu);
139     return bar;
140   }
141 
142   protected Action createLoadAction() {
143     return new LoadAction();
144   }
145 
146   protected Action createSaveAction() {
147     return new SaveAction();
148   }
149 
150   /**
151    * Creates an application frame for this demo and displays it.
152    * The name of this class will be the title of the displayed frame.
153    */
154   public void start() {
155     start(getClass().getName());
156   }
157 
158   /**
159    * Creates an application frame for this demo and displays it.
160    * @param title the title of the display frame.
161    */
162   public void start(final String title) {
163     JFrame frame = new JFrame(title);
164     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
165     addContentTo(frame.getRootPane());
166     frame.pack();
167     frame.setLocationRelativeTo(null);
168     frame.setVisible(true);
169   }
170 
171   public final void addContentTo(final JRootPane rootPane) {
172     rootPane.setJMenuBar(createMenuBar());
173     rootPane.setContentPane(this);
174   }
175 
176   /**
177    * Initializes to a "nice" look and feel.
178    */
179   public static void initLnF() {
180     try {
181       if (!"com.sun.java.swing.plaf.motif.MotifLookAndFeel".equals(UIManager.getSystemLookAndFeelClassName())
182           && !"com.sun.java.swing.plaf.gtk.GTKLookAndFeel".equals(UIManager.getSystemLookAndFeelClassName())
183           && !UIManager.getSystemLookAndFeelClassName().equals(UIManager.getLookAndFeel().getClass().getName())
184           && !(System.getProperty("java.version").startsWith("1.4") && System.getProperty("os.name").startsWith(
185           "Windows") && "6.1".equals(System.getProperty("os.version")))) {
186         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
187       }
188     }
189     catch (Exception e) {
190       e.printStackTrace();
191     }
192   }
193 
194   /**
195    * Launches this demo.
196    * @param args ignored.
197    */
198   public static void main(final String[] args) {
199     EventQueue.invokeLater(new Runnable() {
200       public void run() {
201         initLnF();
202         (new ViewActionDemo()).start();
203       }
204     });
205   }
206 
207   protected GraphMLIOHandler createGraphMLIOHandler() {
208     return new GraphMLIOHandler();
209   }
210 
211 
212   /**
213    * Action that prints the contents of the view
214    */
215   protected class PrintAction extends AbstractAction {
216     PageFormat pageFormat;
217     OptionHandler printOptions;
218 
219     public PrintAction() {
220       super("Print");
221       putValue(Action.SHORT_DESCRIPTION, "Print");
222 
223       //setup option handler
224       printOptions = new OptionHandler("Print Options");
225       printOptions.addInt("Poster Rows", 1);
226       printOptions.addInt("Poster Columns", 1);
227       printOptions.addBool("Add Poster Coords", false);
228       final String[] area = {"View", "Graph"};
229       printOptions.addEnum("Clip Area", area, 1);
230     }
231 
232     public void actionPerformed(ActionEvent e) {
233       Graph2DPrinter gprinter = new Graph2DPrinter(view);
234 
235       //show custom print dialog and adopt values
236       if (!printOptions.showEditor()) {
237         return;
238       }
239       gprinter.setPosterRows(printOptions.getInt("Poster Rows"));
240       gprinter.setPosterColumns(printOptions.getInt("Poster Columns"));
241       gprinter.setPrintPosterCoords(
242           printOptions.getBool("Add Poster Coords"));
243       if ("Graph".equals(printOptions.get("Clip Area"))) {
244         gprinter.setClipType(Graph2DPrinter.CLIP_GRAPH);
245       } else {
246         gprinter.setClipType(Graph2DPrinter.CLIP_VIEW);
247       }
248 
249       //show default print dialogs
250       PrinterJob printJob = PrinterJob.getPrinterJob();
251       if (pageFormat == null) {
252         pageFormat = printJob.defaultPage();
253       }
254       PageFormat pf = printJob.pageDialog(pageFormat);
255       if (pf == pageFormat) {
256         return;
257       } else {
258         pageFormat = pf;
259       }
260 
261       //setup printjob.
262       //Graph2DPrinter is of type Printable
263       printJob.setPrintable(gprinter, pageFormat);
264 
265       if (printJob.printDialog()) {
266         try {
267           printJob.print();
268         } catch (PrinterException ex) {
269           ex.printStackTrace();
270         }
271       }
272     }
273   }
274 
275   /**
276    * Action that terminates the application
277    */
278   protected static class ExitAction extends AbstractAction {
279     ExitAction() {
280       super("Exit");
281       putValue(Action.SHORT_DESCRIPTION, "Exit");
282     }
283 
284     public void actionPerformed(ActionEvent e) {
285 
286       System.exit(0);
287     }
288   }
289 
290   JFileChooser createGraphMLFileChooser() {
291     JFileChooser chooser = new JFileChooser();
292     chooser.setAcceptAllFileFilterUsed(false);
293     chooser.addChoosableFileFilter(new FileFilter() {
294       public boolean accept(File f) {
295         return f.isDirectory() || f.getName().endsWith(".graphml");
296       }
297 
298       public String getDescription() {
299         return "GraphML Format (.graphml)";
300       }
301     });
302 
303     return chooser;
304   }
305 
306   /**
307    * Action that saves the current graph to a file in GraphML format.
308    */
309   protected class SaveAction extends AbstractAction {
310     JFileChooser chooser;
311 
312     public SaveAction() {
313       super("Save...");
314       putValue(Action.SHORT_DESCRIPTION, "Save...");
315       chooser = null;
316     }
317 
318     public void actionPerformed(ActionEvent e) {
319       if (chooser == null) {
320         chooser = createGraphMLFileChooser();
321       }
322       if (chooser.showSaveDialog(ViewActionDemo.this) == JFileChooser.APPROVE_OPTION) {
323         String name = chooser.getSelectedFile().toString();
324         GraphMLIOHandler ioh = new GraphMLIOHandler();
325         try {
326           ioh.write(view.getGraph2D(), name);
327         } catch (IOException ioe) {
328           D.show(ioe);
329         }
330       }
331     }
332   }
333 
334   /**
335    * Action that loads the current graph from a file in GraphML format.
336    */
337   protected class LoadAction extends AbstractAction {
338     JFileChooser chooser;
339 
340     public LoadAction() {
341       super("Load...");
342       putValue(Action.SHORT_DESCRIPTION, "Load...");
343       chooser = null;
344     }
345 
346     public void actionPerformed(ActionEvent e) {
347       if (chooser == null) {
348         chooser = createGraphMLFileChooser();
349       }
350       if (chooser.showOpenDialog(ViewActionDemo.this) == JFileChooser.APPROVE_OPTION) {
351         String name = chooser.getSelectedFile().toString();
352         GraphMLIOHandler ioh = createGraphMLIOHandler();
353         try {
354           view.getGraph2D().clear();
355           ioh.read(view.getGraph2D(), name);
356         } catch (IOException ioe) {
357           D.show(ioe);
358         }
359 
360         //force redisplay of view contents
361         view.fitContent();
362         view.getGraph2D().updateViews();
363       }
364     }
365   }
366 
367   /**
368    * Action that deletes the selected parts of the graph.
369    */
370   protected class DeleteSelection extends AbstractAction {
371     public DeleteSelection() {
372       super("Delete Selection");
373       putValue(Action.SHORT_DESCRIPTION, "Delete Selection");
374       URL imageURL = getClass().getResource("resource/delete.png");
375       if (imageURL != null) {
376         this.putValue(Action.SMALL_ICON, new ImageIcon(imageURL));
377       }
378     }
379 
380     public void actionPerformed(ActionEvent e) {
381       view.getGraph2D().removeSelection();
382       view.getGraph2D().updateViews();
383     }
384   }
385 
386   /**
387    * Action that applies a specified zoom level to the view.
388    */
389   protected class Zoom extends AbstractAction {
390     double factor;
391 
392     public Zoom(double factor) {
393       final String name = "Zoom " + (factor > 1.0 ? "In" : "Out");
394       putValue(Action.NAME, name);
395       putValue(Action.SHORT_DESCRIPTION, name);
396       URL imageURL;
397       if (factor > 1.0d) {
398         imageURL = getClass().getResource("resource/zoomIn.png");
399       } else {
400         imageURL = getClass().getResource("resource/zoomOut.png");
401       }
402       if (imageURL != null) {
403         this.putValue(Action.SMALL_ICON, new ImageIcon(imageURL));
404       }
405       this.factor = factor;
406     }
407 
408     public void actionPerformed(ActionEvent e) {
409       view.setZoom(view.getZoom() * factor);
410       //optional code that adjusts the size of the
411       //view's world rectangle. The world rectangle
412       //defines the region of the canvas that is
413       //accessible by using the scrollbars of the view.
414       Rectangle box = view.getGraph2D().getBoundingBox();
415       view.setWorldRect(box.x - 20, box.y - 20, box.width + 40, box.height + 40);
416 
417       view.updateView();
418     }
419   }
420 
421   /**
422    * Action that resets the view's zoom level to <code>1.0</code>.
423    */
424   protected class ResetZoom extends AbstractAction {
425     public ResetZoom() {
426       super("Reset Zoom");
427       this.putValue(Action.SHORT_DESCRIPTION, "Reset Zoom");
428       final URL imageURL = getClass().getResource("resource/zoomOriginal.png");
429       if (imageURL != null) {
430         this.putValue(Action.SMALL_ICON, new ImageIcon(imageURL));
431       }
432     }
433 
434     public void actionPerformed( final ActionEvent e ) {
435       view.setZoom(1);
436       // optional code that adjusts the size of the
437       // view's world rectangle. The world rectangle
438       // defines the region of the canvas that is
439       // accessible by using the scroll bars of the view.
440       Rectangle box = view.getGraph2D().getBoundingBox();
441       view.setWorldRect(box.x - 20, box.y - 20, box.width + 40, box.height + 40);
442 
443       view.updateView();
444     }
445   }
446 
447   /**
448    * Action that fits the content nicely inside the view.
449    */
450   protected class FitContent extends AbstractAction {
451     public FitContent() {
452       super("Fit Content");
453       putValue(Action.SHORT_DESCRIPTION, "Fit Content");
454       final URL imageURL = getClass().getResource("resource/zoomFit.png");
455       if (imageURL != null) {
456         this.putValue(Action.SMALL_ICON, new ImageIcon(imageURL));
457       }
458     }
459 
460     public void actionPerformed(ActionEvent e) {
461       view.fitContent();
462       view.updateView();
463     }
464   }
465 }
466