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