1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.5.0.1. 
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-2007 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.view.layout.hierarchic;
15  
16  import demo.view.hierarchy.HierarchyDemo;
17  import y.base.*;
18  import y.layout.BufferedLayouter;
19  import y.layout.GraphLayout;
20  import y.layout.hierarchic.IncrementalHierarchicLayouter;
21  import y.layout.hierarchic.incremental.IncrementalHintsFactory;
22  import y.option.ConstraintManager;
23  import y.option.OptionHandler;
24  import y.option.OptionItem;
25  import y.util.Maps;
26  import y.view.Graph2D;
27  import y.view.LayoutMorpher;
28  import y.view.hierarchy.DefaultHierarchyGraphFactory;
29  import y.view.hierarchy.GroupLayoutConfigurator;
30  import y.view.hierarchy.ProxyAutoBoundsNodeRealizer;
31  
32  import javax.swing.*;
33  import java.awt.*;
34  import java.awt.event.ActionEvent;
35  
36  
37  /**
38   * This demo showcases how IncrementalHierarchicLayouter can be used to fully or incrementally
39   * layout hierarchically nested graphs. The demo supports automatic relayout after expanding folder nodes,
40   * collapsing group nodes. Furthermore it provides toolbar buttons that
41   * trigger full layout and incremental relayout. A settings dialog for group layout options is provided as well.
42   * In incremental layout mode all selected elementa are added incrementally to the existing layout.
43   */
44  public class IncrementalHierarchicGroupDemo extends HierarchyDemo {
45  
46    IncrementalHierarchicLayouter layouter;
47    OptionHandler groupLayoutOptions;
48  
49    public IncrementalHierarchicGroupDemo() {
50  
51      view.setPreferredSize(new Dimension(1000,800));
52  
53      //configure layout algorithm
54      layouter = new IncrementalHierarchicLayouter();
55      layouter.getEdgeLayoutDescriptor().setOrthogonallyRouted(true);
56      layouter.setRecursiveGroupLayeringEnabled(false);
57  
58      //prepare option handler for group layout options
59      Object[] groupStrategyEnum = {"Global Layering", "Recursive Layering"};
60      Object[] groupAlignmentEnum = {"Top", "Center", "Bottom"};
61      groupLayoutOptions = new OptionHandler("Grouplayout Options");
62      ConstraintManager cm = new ConstraintManager(groupLayoutOptions);
63      OptionItem gsi = groupLayoutOptions.addEnum("Group Layering Strategy", groupStrategyEnum, 0);
64      OptionItem eci = groupLayoutOptions.addBool("Enable Compact Layering", true);
65      OptionItem gai = groupLayoutOptions.addEnum("Group Alignment", groupAlignmentEnum, 0);
66      cm.setEnabledOnValueEquals(gsi, "Recursive Layering", eci);
67      cm.setEnabledOnValueEquals(gsi, "Recursive Layering", gai);
68      cm.setEnabledOnCondition(cm.createConditionValueEquals(gsi, "Recursive Layering").and(cm.createConditionValueEquals(eci, Boolean.TRUE).inverse()), gai);
69  
70      //configure default graphics for default node realizers. defaults are adopted
71      //from nodes contained in initial graph.
72      Graph2D graph = view.getGraph2D();
73      for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
74        Node n = nc.node();
75        if (hierarchy.isNormalNode(n)) {
76          graph.setDefaultNodeRealizer(graph.getRealizer(n).createCopy());
77          break;
78        }
79      }
80      for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
81        Node n = nc.node();
82        if (!hierarchy.isNormalNode(n)) {
83          DefaultHierarchyGraphFactory hgf = (DefaultHierarchyGraphFactory) hierarchy.getGraphFactory();
84          if(graph.getRealizer(n) instanceof ProxyAutoBoundsNodeRealizer) {
85            hgf.setProxyNodeRealizerEnabled(true);
86            ProxyAutoBoundsNodeRealizer pnr = (ProxyAutoBoundsNodeRealizer) graph.getRealizer(n);
87            hgf.setDefaultGroupNodeRealizer(pnr.getRealizer(0).createCopy());
88            hgf.setDefaultFolderNodeRealizer(pnr.getRealizer(1).createCopy());
89            break;
90          }
91        }
92      }
93  
94      view.fitContent();
95    }
96  
97    /**
98     * Loads the initial graph
99     */
100   protected void loadInitialGraph() {
101     loadGraph("resource/grouping.ygf");
102   }
103 
104   /**
105    * Creates the toolbar for the demo.
106    */
107   protected JToolBar createToolBar() {
108     JToolBar toolBar = super.createToolBar();
109     toolBar.add(new AbstractAction("Incremental Layout") {
110       public void actionPerformed(ActionEvent e) {
111         layoutIncrementally();
112       }
113     });
114     toolBar.add(new AbstractAction("New Layout") {
115       public void actionPerformed(ActionEvent e) {
116         layout();
117       }
118     });
119     toolBar.add(new AbstractAction("Group Layout Options...") {
120       public void actionPerformed(ActionEvent e) {
121         groupLayoutOptions.showEditor((Frame)view.getTopLevelAncestor());
122         configureGroupLayout();
123       }
124     });
125     return toolBar;
126   }
127 
128   /**
129    * Configures the layouter options relevant for grouping.
130    */
131   private void configureGroupLayout() {
132     Object gsi = groupLayoutOptions.get("Group Layering Strategy");
133     if ("Recursive Layering".equals(gsi)) {
134       layouter.setRecursiveGroupLayeringEnabled(true);
135     } else if ("Global Layering".equals(gsi)) {
136       layouter.setRecursiveGroupLayeringEnabled(false);
137     }
138 
139     layouter.setGroupCompactionEnabled(groupLayoutOptions.getBool("Enable Compact Layering"));
140 
141     Object gai = groupLayoutOptions.get("Group Alignment");
142     if ("Top".equals(gai)) {
143       layouter.setGroupAlignmentPolicy(IncrementalHierarchicLayouter.POLICY_ALIGN_GROUPS_TOP);
144     } else if ("Center".equals(gai)) {
145       layouter.setGroupAlignmentPolicy(IncrementalHierarchicLayouter.POLICY_ALIGN_GROUPS_CENTER);
146     }
147     if ("Bottom".equals(gai)) {
148       layouter.setGroupAlignmentPolicy(IncrementalHierarchicLayouter.POLICY_ALIGN_GROUPS_BOTTOM);
149     }
150   }
151 
152   /**
153    * Performs incremental layout. All selected elements will be treated incrementally.
154    */
155   private void layoutIncrementally() {
156     Graph2D graph = view.getGraph2D();
157 
158     layouter.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_INCREMENTAL);
159 
160     // create storage for both nodes and edges
161     DataMap incrementalElements = Maps.createHashedDataMap();
162     // configure the mode
163     final IncrementalHintsFactory ihf = layouter.createIncrementalHintsFactory();
164 
165     for (NodeCursor nc = graph.selectedNodes(); nc.ok(); nc.next()) {
166       incrementalElements.set(nc.node(), ihf.createLayerIncrementallyHint(nc.node()));
167     }
168 
169     for (EdgeCursor ec = graph.selectedEdges(); ec.ok(); ec.next()) {
170       incrementalElements.set(ec.edge(), ihf.createSequenceIncrementallyHint(ec.edge()));
171     }
172     graph.addDataProvider(IncrementalHierarchicLayouter.INCREMENTAL_HINTS_DPKEY, incrementalElements);
173 
174 
175     GroupLayoutConfigurator glc = new GroupLayoutConfigurator(graph);
176     glc.prepareAll();
177     GraphLayout gl = new BufferedLayouter(layouter).calcLayout(graph);
178     new LayoutMorpher(view, gl).execute();
179     glc.restoreAll();
180     
181     graph.removeDataProvider(IncrementalHierarchicLayouter.INCREMENTAL_HINTS_DPKEY);
182   }
183 
184   /**
185    * Performs global layout. The new layout can strongly differ from the existing layout.
186    */
187   private void layout() {
188     Graph2D graph = view.getGraph2D();
189     layouter.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_FROM_SCRATCH);
190     GroupLayoutConfigurator glc = new GroupLayoutConfigurator(graph);
191     glc.prepareAll();
192     GraphLayout gl = new BufferedLayouter(layouter).calcLayout(graph);
193     new LayoutMorpher(view, gl).execute();
194     glc.restoreAll();
195   }
196 
197 
198   /**
199    * Expand a folder node. After expanding the folder node, an incremental layout is automatically triggered.
200    * For this, the expanded node and all of its decendants will be treated as incremental elements.
201    */
202   protected void openFolder(Node folderNode) {
203     NodeList children = new NodeList(hierarchy.getInnerGraph(folderNode).nodes());
204     super.openFolder(folderNode);
205 
206     Graph2D graph = view.getGraph2D();
207 
208     graph.unselectAll();
209     graph.setSelected(folderNode, true);
210     for(NodeCursor nc = children.nodes(); nc.ok(); nc.next()) {
211       graph.setSelected(nc.node(), true);
212     }
213 
214     layoutIncrementally();
215 
216     graph.unselectAll();
217     graph.setSelected(folderNode, true);
218 
219     graph.updateViews();
220   }
221 
222   /**
223    * Collape a group node. After collapsing the group node, an incremental layout is automatically triggered.
224    * For this, the collapsed node is treated as an incremental element.
225    */
226   protected void closeGroup(Node groupNode) {
227     super.closeGroup(groupNode);
228 
229 
230     Graph2D graph = view.getGraph2D();
231     graph.unselectAll();
232     graph.setSelected(groupNode, true);
233     for (EdgeCursor ec = groupNode.edges(); ec.ok(); ec.next()) {
234       graph.setSelected(ec.edge(), true);
235     }
236 
237     layoutIncrementally();
238     graph.unselectAll();
239 
240     graph.updateViews();
241   }
242 
243   /**
244    * Launches this demo.
245    */
246   public static void main(String args[]) {
247     initLnF();
248 
249     IncrementalHierarchicGroupDemo demo = new IncrementalHierarchicGroupDemo();
250 
251     demo.start();
252   }
253 
254 }
255