1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.9. 
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) 2000-2011 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.layout.organic;
15  
16  import demo.view.DemoBase;
17  import demo.view.DemoDefaults;
18  
19  import y.base.Edge;
20  import y.base.EdgeCursor;
21  import y.base.EdgeMap;
22  import y.layout.organic.OrganicLayouter;
23  import y.module.GRIPModule;
24  import y.module.OrganicEdgeRouterModule;
25  import y.module.OrganicLayoutModule;
26  import y.module.SmartOrganicLayoutModule;
27  import y.module.YModule;
28  import y.view.EdgeRealizer;
29  import y.view.EditMode;
30  import y.view.Graph2D;
31  import y.view.NodeRealizer;
32  import y.view.PopupMode;
33  import y.view.YLabel;
34  
35  import javax.swing.AbstractAction;
36  import javax.swing.Action;
37  import javax.swing.ButtonGroup;
38  import javax.swing.JMenu;
39  import javax.swing.JMenuBar;
40  import javax.swing.JPopupMenu;
41  import javax.swing.JRadioButtonMenuItem;
42  import javax.swing.JToolBar;
43  import java.awt.event.ActionEvent;
44  import java.awt.event.ActionListener;
45  import java.awt.EventQueue;
46  import java.util.Locale;
47  
48  /**
49   * Demonstrates different organic layout algorithms and 
50   * how to specify individual preferred edge lengths 
51   * for OrganicLayouter.  
52   * <br>
53   * In this demo the edge lengths can be specified by right clicking 
54   * on an edge or applying the current node distances using the button from the 
55   * toolbar.
56   * <br>
57   * Choose the item "Edit Preferred Edge Length" from the context menu to open up 
58   * a label editor that allows for entering a value for the edge length in pixels.
59   * Note that the entered value must be numeric. Otherwise 
60   * a default length will be chosen.
61   *
62   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/smart_organic_layouter.html">Section Organic Layout Style</a> in the yFiles for Java Developer's Guide
63   * @see <a href="http://docs.yworks.com/yfiles/doc/developers-guide/organic_edge_router.html">Section Organic Edge Routing</a> in the yFiles for Java Developer's Guide
64   */
65  public class OrganicLayouterDemo extends DemoBase {
66    EdgeMap preferredEdgeLengthMap;
67    YModule module;
68  
69    public OrganicLayouterDemo() {
70      preferredEdgeLengthMap = view.getGraph2D().createEdgeMap();
71      view.getGraph2D().addDataProvider(OrganicLayouter.PREFERRED_EDGE_LENGTH_DATA, preferredEdgeLengthMap);
72      module = new SmartOrganicLayoutModule();
73      loadGraph("resource/organic.graphml");
74      DemoDefaults.applyRealizerDefaults(view.getGraph2D(), true, true);
75    }
76  
77    protected void registerViewModes() {
78      EditMode editMode = new EditMode();
79      view.addViewMode(editMode);
80  
81      editMode.setPopupMode(new PopupMode() {
82        public JPopupMenu getEdgePopup(Edge e) {
83          JPopupMenu pm = new JPopupMenu();
84          pm.add(new EditLabel(e));
85          return pm;
86        }
87      });
88    }
89  
90    /**
91     * Returns ViewActionDemo toolbar plus actions to trigger some layout algorithms 
92     */
93    protected JToolBar createToolBar() {
94      JToolBar bar = super.createToolBar();
95  
96      bar.addSeparator();
97      bar.add(createActionControl(new LayoutAction()));
98      bar.add(createActionControl(new OptionAction()));
99      bar.addSeparator();
100     bar.add(new AssignLengthsAction());
101     return bar;
102   }
103 
104   protected JMenuBar createMenuBar() {
105     JMenuBar mb = super.createMenuBar();
106     JMenu layoutMenu = new JMenu("Style");
107     ButtonGroup bg = new ButtonGroup();
108     ActionListener listener = new ActionListener() {
109       public void actionPerformed(ActionEvent ae) {
110         module = new OrganicLayoutModule();
111       }
112     };
113     JRadioButtonMenuItem item = new JRadioButtonMenuItem("Classic");
114     item.addActionListener(listener);
115     bg.add(item);
116     layoutMenu.add(item);
117     listener = new ActionListener() {
118       public void actionPerformed(ActionEvent ae) {
119         module = new SmartOrganicLayoutModule();
120       }
121     };
122     item = new JRadioButtonMenuItem("Smart");
123     item.addActionListener(listener);
124     item.setSelected(true);
125     bg.add(item);
126     layoutMenu.add(item);
127 
128     listener = new ActionListener() {
129       public void actionPerformed(ActionEvent ae) {
130         module = new GRIPModule();
131       }
132     };
133     item = new JRadioButtonMenuItem("GRIP");
134     item.addActionListener(listener);
135     bg.add(item);
136     layoutMenu.add(item);
137     listener = new ActionListener() {
138       public void actionPerformed(ActionEvent ae) {
139         module = new OrganicEdgeRouterModule();
140       }
141     };
142     item = new JRadioButtonMenuItem("EdgeRouting");
143     item.addActionListener(listener);
144     bg.add(item);
145     layoutMenu.add(item);
146     mb.add(layoutMenu);
147     return mb;
148   }
149 
150   /**
151    * Displays the layout options for organic layouter
152    */
153   class OptionAction extends AbstractAction {
154     OptionAction() {
155       super("Settings...", getIconResource("resource/Properties.png"));
156     }
157 
158     public void actionPerformed(ActionEvent e) {
159       OptionSupport.showDialog(module, view.getGraph2D(), false, view.getFrame());
160     }
161   }
162 
163   /**
164    *  Launches the OrganicLayouter.
165    */
166   class LayoutAction extends AbstractAction {
167     LayoutAction() {
168       super("Layout", SHARED_LAYOUT_ICON);
169     }
170 
171     public void actionPerformed(ActionEvent e) {
172       //update preferredEdgeLengthData before launching the module
173       Graph2D graph = view.getGraph2D();
174       for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
175         Edge edge = ec.edge();
176         String eLabel = graph.getLabelText(edge);
177         preferredEdgeLengthMap.set(edge, null);
178         try {
179           preferredEdgeLengthMap.setInt(edge, (int) Double.parseDouble(eLabel));
180         }
181         catch (Exception ex) {
182         }
183       }
184 
185       //start the module
186       module.start(view.getGraph2D());
187     }
188   }
189 
190   /**
191    * Action that opens a text editor for the label of an edge
192    * <p>
193    * The inlined label editor allows to enter a single line of
194    * label text for an edge. To terminate the label editor 
195    * press "Enter".
196    */
197   class EditLabel extends AbstractAction {
198     Edge e;
199 
200     EditLabel(Edge e) {
201       super("Edit Preferred Length");
202       this.e = e;
203     }
204 
205     public void actionPerformed(ActionEvent ev) {
206 
207       final EdgeRealizer r = view.getGraph2D().getRealizer(e);
208       final YLabel label = r.getLabel();
209 
210       view.openLabelEditor(label,
211           label.getBox().getX(),
212           label.getBox().getY(),
213           null, true);
214     }
215   }
216 
217   class AssignLengthsAction extends AbstractAction {
218     AssignLengthsAction() {
219       super("Assign Preferred Length");
220       putValue(Action.SHORT_DESCRIPTION, "Set the preferred length of each edge to its current geometric length");
221     }
222 
223     public void actionPerformed(ActionEvent e) {
224       Graph2D g = view.getGraph2D();
225       for (EdgeCursor ec = g.edges(); ec.ok(); ec.next()) {
226         NodeRealizer snr = g.getRealizer(ec.edge().source());
227         NodeRealizer tnr = g.getRealizer(ec.edge().target());
228         double deltaX = snr.getCenterX() - tnr.getCenterX();
229         double deltaY = snr.getCenterY() - tnr.getCenterY();
230         double dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
231         EdgeRealizer er = g.getRealizer(ec.edge());
232         er.getLabel().setText(Integer.toString((int) dist));
233       }
234       g.updateViews();
235     }
236   }
237 
238   public static void main(String[] args) {
239     EventQueue.invokeLater(new Runnable() {
240       public void run() {
241         Locale.setDefault(Locale.ENGLISH);
242         initLnF();
243         new OrganicLayouterDemo().start("Organic Layouter Demo");
244       }
245     });
246   }
247 }
248 
249 
250       
251