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.hierarchic;
29  
30  import demo.view.DemoBase;
31  import y.base.DataMap;
32  import y.base.NodeCursor;
33  import y.base.NodeList;
34  import y.layout.Layouter;
35  import y.layout.hierarchic.IncrementalHierarchicLayouter;
36  import y.layout.hierarchic.incremental.IncrementalHintsFactory;
37  import y.layout.hierarchic.incremental.NodeLayoutDescriptor;
38  import y.layout.hierarchic.incremental.RoutingStyle;
39  import y.layout.hierarchic.incremental.SimplexNodePlacer;
40  import y.util.Maps;
41  import y.view.Arrow;
42  import y.view.EdgeRealizer;
43  import y.view.Graph2D;
44  import y.view.hierarchy.HierarchyManager;
45  
46  import javax.swing.AbstractAction;
47  import javax.swing.JToolBar;
48  import java.awt.Cursor;
49  import java.awt.EventQueue;
50  import java.awt.event.ActionEvent;
51  import java.util.Locale;
52  
53  /**
54   * This simple demo shows how to use the {@link IncrementalHierarchicLayouter}
55   * to either calculate a new layout or calculate a new layout given the current
56   * sketch or incrementally layout selected nodes to an already existing graph whose
57   * layout is read from the current sketch. The layout algorithm uses an octilinear edge routing style,
58   * i.e., the slope of each edge segment is a multiple of 45 degrees.
59   * <br>
60   * <br>
61   * Things to try:
62   * <br>
63   * Create a graph and use the <b>Layout</b> button to lay it out from scratch.
64   * Modify the graph (move nodes and or bends), deselect all elements and
65   * choose <b>Layout From Sketch</b> to recalculate the layout using the given sketch
66   * Add some nodes and connect them to the graph, select the newly added nodes
67   * and choose <b>Layout Incrementally</b> to incrementally "add" the selected
68   * elements optimally into the existing graph.
69   *
70   * @see <a href="http://docs.yworks.com/yfiles/doc/api/index.html#/dguide/incremental_hierarchical_layouter#incremental_hierarchical_layouter" target="_blank">Section Hierarchical Layout Style</a> in the yFiles for Java Developer's Guide
71   */
72  public class SimpleIncrementalHierarchicLayouterDemo extends DemoBase
73  {
74    private DataMap hintMap;
75  
76    private IncrementalHierarchicLayouter hierarchicLayouter;
77    private IncrementalHintsFactory hintsFactory;
78  
79    public SimpleIncrementalHierarchicLayouterDemo()
80    {
81      final Graph2D graph = view.getGraph2D();
82      EdgeRealizer defaultER = graph.getDefaultEdgeRealizer();
83      defaultER.setArrow(Arrow.STANDARD);
84  
85      // create a map to store the hints for the incremental layout mechanism
86      hintMap = Maps.createHashedDataMap();
87      graph.addDataProvider(IncrementalHierarchicLayouter.INCREMENTAL_HINTS_DPKEY, hintMap);
88  
89      // create the layouter
90      hierarchicLayouter = new IncrementalHierarchicLayouter();
91  
92      // set some defaults
93      hierarchicLayouter.getEdgeLayoutDescriptor().setMinimumFirstSegmentLength(15);
94      hierarchicLayouter.getEdgeLayoutDescriptor().setMinimumLastSegmentLength(20);
95      hierarchicLayouter.getEdgeLayoutDescriptor().setRoutingStyle(new RoutingStyle(RoutingStyle.EDGE_STYLE_OCTILINEAR));
96      hierarchicLayouter.getEdgeLayoutDescriptor().setMinimumDistance(10.0d);
97  
98      hierarchicLayouter.getNodeLayoutDescriptor().setLayerAlignment(0.5d);
99      hierarchicLayouter.setMinimumLayerDistance(30.0d);
100     hierarchicLayouter.getNodeLayoutDescriptor().setNodeLabelMode(NodeLayoutDescriptor.NODE_LABEL_MODE_CONSIDER_FOR_DRAWING);
101 
102     hierarchicLayouter.setConsiderNodeLabelsEnabled(true);
103 
104     ((SimplexNodePlacer) hierarchicLayouter.getNodePlacer()).setBaryCenterModeEnabled(true);
105 
106     // get a reference to a hints factory
107     hintsFactory = hierarchicLayouter.createIncrementalHintsFactory();
108 
109     // disable the component layouter (optional)
110     hierarchicLayouter.setComponentLayouterEnabled(false);
111 
112     loadGraph("resource/simple.graphml");
113   }
114 
115   protected void initialize() {
116     // create hierarchy manager before undo manager (for view actions)
117     // to ensure undo/redo works for grouped graphs
118     new HierarchyManager(view.getGraph2D());
119   }
120 
121   class LayoutFromSketchAction extends AbstractAction
122   {
123     LayoutFromSketchAction()
124     {
125       super("Layout From Sketch", SHARED_LAYOUT_ICON);
126     }
127 
128     public void actionPerformed(ActionEvent ev)
129     {
130       calcIncrementalLayout(new NodeList().nodes());
131     }
132   }
133 
134   class LayoutIncrementallyAction extends AbstractAction
135   {
136     LayoutIncrementallyAction()
137     {
138       super("Layout Incrementally", SHARED_LAYOUT_ICON);
139     }
140 
141     public void actionPerformed(ActionEvent ev)
142     {
143       calcIncrementalLayout(view.getGraph2D().selectedNodes());
144     }
145   }
146 
147   class LayoutAction extends AbstractAction
148   {
149     LayoutAction()
150     {
151       super("Layout", SHARED_LAYOUT_ICON);
152     }
153 
154     public void actionPerformed(ActionEvent ev)
155     {
156       calcFreshLayout();
157     }
158   }
159 
160   protected JToolBar createToolBar()
161   {
162     JToolBar tb = super.createToolBar();
163     tb.addSeparator();
164     tb.add(createActionControl(new LayoutAction()));
165     tb.add(createActionControl(new LayoutFromSketchAction()));
166     tb.add(createActionControl(new LayoutIncrementallyAction()));
167     return tb;
168   }
169 
170   public void calcFreshLayout()
171   {
172     hierarchicLayouter.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_FROM_SCRATCH);
173     calcLayout(hierarchicLayouter);
174   }
175 
176   public void calcIncrementalLayout(NodeCursor incrementalNodes)
177   {
178     try
179     {
180       // mark nodes as "new"
181       for (incrementalNodes.toFirst(); incrementalNodes.ok(); incrementalNodes.next())
182       {
183         hintMap.set(incrementalNodes.node(), hintsFactory.createLayerIncrementallyHint(incrementalNodes.node()));
184       }
185       // read the old nodes from the sketch
186       hierarchicLayouter.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_INCREMENTAL);
187       // calculate the layout incrementally
188       calcLayout(hierarchicLayouter);
189     }
190     finally
191     {
192       // reset the marks
193       for (incrementalNodes.toFirst(); incrementalNodes.ok(); incrementalNodes.next())
194       {
195         hintMap.set(incrementalNodes.node(), null);
196       }
197     }
198   }
199 
200   protected void calcLayout(Layouter layouter)
201   {
202     Graph2D graph = view.getGraph2D();
203     if (!graph.isEmpty())
204     {
205       Cursor oldCursor = view.getViewCursor();
206       try
207       {
208         view.applyLayoutAnimated(layouter);
209       }
210       finally
211       {
212         view.setViewCursor(oldCursor);
213       }
214     }
215     view.fitContent();
216     view.updateView();
217   }
218 
219   /**
220    * Launches this demo.
221    */
222   public static void main(String[] args) {
223     EventQueue.invokeLater(new Runnable() {
224       public void run() {
225         Locale.setDefault(Locale.ENGLISH);
226         initLnF();
227         (new SimpleIncrementalHierarchicLayouterDemo()).start("Simple IncrementalHierarchicLayouter Demo");
228       }
229     });
230   }
231 }
232