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