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.layout.module;
29  
30  import demo.view.DemoBase;
31  import demo.layout.module.BalloonLayoutModule;
32  import demo.layout.module.ChannelEdgeRouterModule;
33  import demo.layout.module.CircularLayoutModule;
34  import demo.layout.module.IncrementalHierarchicLayoutModule;
35  import demo.layout.module.LabelingModule;
36  import y.module.LayoutModule;
37  import demo.layout.module.OrthogonalEdgeRouterModule;
38  import demo.layout.module.OrthogonalLayoutModule;
39  import demo.layout.module.PolylineEdgeRouterModule;
40  import demo.layout.module.RadialLayoutModule;
41  import y.module.RandomLayoutModule;
42  import demo.layout.module.SeriesParallelLayoutModule;
43  import demo.layout.module.SmartOrganicLayoutModule;
44  import demo.layout.module.TreeLayoutModule;
45  import y.module.YModule;
46  import y.option.OptionHandler;
47  import y.option.PropertiesIOHandler;
48  import y.view.Arrow;
49  import y.view.hierarchy.HierarchyManager;
50  
51  import javax.swing.AbstractAction;
52  import javax.swing.Action;
53  import javax.swing.DefaultListCellRenderer;
54  import javax.swing.JComboBox;
55  import javax.swing.JList;
56  import javax.swing.JToolBar;
57  import javax.swing.ListCellRenderer;
58  import java.awt.Component;
59  import java.awt.EventQueue;
60  import java.awt.event.ActionEvent;
61  import java.awt.event.ActionListener;
62  import java.io.IOException;
63  import java.io.InputStream;
64  import java.net.URL;
65  import java.util.Locale;
66  import java.util.Properties;
67  
68  /**
69   * Demonstrates how layout modules can be added to the GUI of an application.
70   * A layout module is a layout algorithm combined
71   * with an option dialog, that allows to change the
72   * options of a layout algorithm interactively
73   * (only available if layout is part of distribution).
74   *
75   */
76  public class LayoutModuleDemo extends DemoBase {
77    public LayoutModuleDemo() {
78      //use a delta arrow to make edge directions clear
79      view.getGraph2D().getDefaultEdgeRealizer().setArrow(Arrow.DELTA);
80  
81      //to enable loading of hierarchical grouped graphs
82      new HierarchyManager(view.getGraph2D());
83      loadGraph("resource/sample.graphml");
84    }
85  
86    /**
87     * Creates a toolbar for choosing, configuring, and running layout algorithms.
88     */
89    protected JToolBar createToolBar() {
90      final JComboBox layoutModules = createLayouterModulesComboBox();
91      final Action layoutPropertiesAction = createPropertiesAction(layoutModules);
92      final Action layoutAction = createAction("Layout", layoutModules);
93  
94      final JComboBox routerModules = createRouterModulesComboBox();
95      final Action routerPropertiesAction = createPropertiesAction(routerModules);
96      final Action routerAction = createAction("Route", routerModules);
97  
98      final YModule labelingModule = loadSettings(new LabelingModule());
99      final Action labelingPropertiesAction = new AbstractAction(
100             "Settings...", getIconResource("resource/properties.png")) {
101       public void actionPerformed(ActionEvent e) {
102         showOptionDialog(labelingModule);
103       }
104     };
105     final Action labelingAction = new AbstractAction(
106             "Place labels", SHARED_LAYOUT_ICON) {
107       public void actionPerformed(final ActionEvent e) {
108         startModule(labelingModule);
109       }
110     };
111 
112     final JToolBar toolBar = super.createToolBar();
113     toolBar.addSeparator();
114     toolBar.add(createActionControl(layoutAction));
115     toolBar.add(layoutModules);
116     toolBar.add(createActionControl(layoutPropertiesAction));
117     toolBar.addSeparator();
118     toolBar.add(createActionControl(routerAction));
119     toolBar.add(routerModules);
120     toolBar.add(createActionControl(routerPropertiesAction));
121     toolBar.addSeparator();
122     toolBar.add(createActionControl(labelingAction));
123     toolBar.add(createActionControl(labelingPropertiesAction));
124     return toolBar;
125   }
126 
127   private JComboBox createLayouterModulesComboBox() {
128     final JComboBox layoutModules = new JComboBox();
129     layoutModules.setRenderer(new LayoutModuleListCellRenderer());
130     layoutModules.addItem(loadSettings(new IncrementalHierarchicLayoutModule()));
131     layoutModules.addItem(loadSettings(new SmartOrganicLayoutModule()));
132     layoutModules.addItem(loadSettings(new OrthogonalLayoutModule()));
133     layoutModules.addItem(loadSettings(new CircularLayoutModule()));
134     layoutModules.addItem(loadSettings(new RadialLayoutModule()));
135     layoutModules.addItem(loadSettings(new TreeLayoutModule()));
136     layoutModules.addItem(loadSettings(new SeriesParallelLayoutModule()));
137     layoutModules.addItem(loadSettings(new DiagonalLayoutModule()));
138     layoutModules.addItem(loadSettings(new RandomLayoutModule()));
139     layoutModules.setSelectedIndex(0);
140     layoutModules.setMaximumSize(layoutModules.getPreferredSize());
141     layoutModules.addActionListener(
142         new ActionListener() {
143           public void actionPerformed(ActionEvent e) {
144             startModule((LayoutModule) layoutModules.getSelectedItem());
145           }
146         });
147     return layoutModules;
148   }
149 
150   private JComboBox createRouterModulesComboBox() {
151     final JComboBox routerModules = new JComboBox();
152     routerModules.setRenderer(new LayoutModuleListCellRenderer());
153     routerModules.addItem(loadSettings(new PolylineEdgeRouterModule()));
154     routerModules.addItem(loadSettings(new OrthogonalEdgeRouterModule()));
155     routerModules.addItem(loadSettings(new ChannelEdgeRouterModule()));
156     routerModules.setSelectedIndex(0);
157     routerModules.setMaximumSize(routerModules.getPreferredSize());
158     routerModules.addActionListener(
159       new ActionListener() {
160         public void actionPerformed(ActionEvent e) {
161           startModule((LayoutModule) routerModules.getSelectedItem());
162         }
163       });
164     return routerModules;
165   }
166 
167   private Action createPropertiesAction(final JComboBox modules) {
168     return new AbstractAction("Settings...", getIconResource("resource/properties.png")) {
169       public void actionPerformed(final ActionEvent e) {
170         showOptionDialog((LayoutModule) modules.getSelectedItem());
171       }
172     };
173   }
174 
175   private Action createAction(final String name, final JComboBox modules) {
176     return new AbstractAction(name, SHARED_LAYOUT_ICON) {
177       public void actionPerformed(final ActionEvent e) {
178         startModule((LayoutModule) modules.getSelectedItem());
179       }
180     };
181   }
182 
183   private void showOptionDialog(final YModule module) {
184     if (module != null) {
185       final OptionHandler options = module.getOptionHandler();
186       if (options != null) {
187         OptionSupport.showDialog(module, view.getGraph2D(), false, view.getFrame());
188       }
189     }
190   }
191 
192   private void startModule(final YModule module) {
193     if (module != null) {
194       module.start(view.getGraph2D());
195     }
196   }
197 
198   /**
199    * Restores module settings from a properties file in the
200    * <code>resource</code> directory.
201    */
202   private YModule loadSettings(final YModule module) {
203     final OptionHandler options = module.getOptionHandler();
204     if (options != null) {
205       final String filePath = "resource/" + getSimpleName(module) + ".properties";
206       final URL resource = getClass().getResource(filePath);
207       if (resource != null) {
208         final Properties data = new Properties();
209         try {
210           final InputStream in = resource.openStream();
211           try {
212             data.load(in);
213             options.read(new PropertiesIOHandler(data));
214           } finally {
215             in.close();
216           }
217         } catch (IOException e) {
218           e.printStackTrace();
219         }
220       }
221     }
222     return module;
223   }
224 
225   /**
226    * Returns the simple class name of the given module. The simple class name
227    * is the qualified class name without its package name prefix.
228    */
229   private static String getSimpleName(final YModule module) {
230     final String qn = module.getClass().getName();
231     final int idx = qn.lastIndexOf('.');
232     return idx > -1 ? qn.substring(idx + 1) : qn;
233   }
234 
235   public static void main(String[] args) {
236     EventQueue.invokeLater(new Runnable() {
237       public void run() {
238         Locale.setDefault(Locale.ENGLISH);
239         initLnF();
240         new LayoutModuleDemo().start();
241       }
242     });
243   }
244 
245   static class LayoutModuleListCellRenderer implements ListCellRenderer {
246     final DefaultListCellRenderer renderer = new DefaultListCellRenderer();
247 
248     public Component getListCellRendererComponent(
249             final JList list,
250             final Object value,
251             final int index,
252             final boolean isSelected,
253             final boolean cellHasFocus
254     ) {
255       if (value instanceof LayoutModule) {
256         final String name = getLayouterName(value);
257         return renderer.getListCellRendererComponent(list, name, index, isSelected, cellHasFocus);
258       } else {
259         return renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
260       }
261     }
262 
263     private String getLayouterName(final Object value) {
264       if (value instanceof CircularLayoutModule) {
265         return "Circular";
266       } else if (value instanceof DiagonalLayoutModule) {
267         return "Diagonal";
268       } else if (value instanceof IncrementalHierarchicLayoutModule) {
269         return "Hierarchic";
270       } else if (value instanceof SmartOrganicLayoutModule) {
271         return "Organic";
272       } else if (value instanceof OrthogonalLayoutModule) {
273         return "Orthogonal";
274       } else if (value instanceof RadialLayoutModule) {
275         return "Radial";
276       } else if (value instanceof RandomLayoutModule) {
277         return "Random";
278       } else if (value instanceof SeriesParallelLayoutModule) {
279         return "Series-Parallel";
280       } else if (value instanceof TreeLayoutModule) {
281         return "Tree";
282       } else if (value instanceof BalloonLayoutModule) {
283         return "Balloon";
284       } else if (value instanceof PolylineEdgeRouterModule) {
285         return "Polyline";
286       } else if (value instanceof OrthogonalEdgeRouterModule) {
287         return "Orthogonal";
288       } else if (value instanceof ChannelEdgeRouterModule) {
289         return "Channel";
290       } else {
291         return ((YModule) value).getModuleName().toLowerCase();
292       }
293     }
294   }
295 }
296