1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.6. 
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-2008 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.module;
15  
16  
17  import y.base.DataMap;
18  import y.base.DataProvider;
19  import y.base.Edge;
20  import y.base.EdgeCursor;
21  import y.base.NodeCursor;
22  import y.layout.CanonicMultiStageLayouter;
23  import y.layout.LabelLayoutConstants;
24  import y.layout.LabelRanking;
25  import y.layout.LayoutOrientation;
26  import y.layout.OrientationLayouter;
27  import y.layout.PortConstraint;
28  import y.layout.PortConstraintKeys;
29  import y.layout.hierarchic.AsIsLayerer;
30  import y.layout.hierarchic.BFSLayerer;
31  import y.layout.hierarchic.IncrementalHierarchicLayouter;
32  import y.layout.hierarchic.incremental.EdgeLayoutDescriptor;
33  import y.layout.hierarchic.incremental.IncrementalHintsFactory;
34  import y.layout.hierarchic.incremental.NodeLayoutDescriptor;
35  import y.layout.hierarchic.incremental.OldLayererWrapper;
36  import y.layout.hierarchic.incremental.SimplexNodePlacer;
37  import y.layout.hierarchic.incremental.TopLevelGroupToSwimlaneStage;
38  import y.layout.labeling.GreedyMISLabeling;
39  import y.option.ConstraintManager;
40  import y.option.ConstraintManager.Condition;
41  import y.option.DefaultEditorFactory;
42  import y.option.EnumOptionItem;
43  import y.option.OptionGroup;
44  import y.option.OptionHandler;
45  import y.option.OptionItem;
46  import y.util.DataProviderAdapter;
47  import y.util.Maps;
48  import y.view.EdgeLabel;
49  import y.view.EdgeRealizer;
50  import y.view.Graph2D;
51  import y.view.Selections;
52  import y.view.hierarchy.GroupLayoutConfigurator;
53  import y.module.LayoutModule;
54  
55  /**
56   * This module represents an interactive configurator and launcher for
57   * {@link y.layout.hierarchic.IncrementalHierarchicLayouter}.
58   * It is similar to IncrementalHierarchicLayoutModule found in the yFiles
59   * package y.module.
60   *
61   */
62  public class IncrementalHierarchicLayoutModule extends LayoutModule {
63    private static final String INCREMENTAL_HIERARCHIC = "INCREMENTAL_HIERARCHIC";
64  
65    private static final String GENERAL = "GENERAL";
66    private static final String INTERACTION = "INTERACTION";
67    private static final String SELECTED_ELEMENTS_INCREMENTALLY = "SELECTED_ELEMENTS_INCREMENTALLY";
68    private static final String USE_DRAWING_AS_SKETCH = "USE_DRAWING_AS_SKETCH";
69    private static final String ORIENTATION = "ORIENTATION";
70    private static final String RIGHT_TO_LEFT = "RIGHT_TO_LEFT";
71    private static final String BOTTOM_TO_TOP = "BOTTOM_TO_TOP";
72    private static final String LEFT_TO_RIGHT = "LEFT_TO_RIGHT";
73    private static final String TOP_TO_BOTTOM = "TOP_TO_BOTTOM";
74    private static final String LAYOUT_COMPONENTS_SEPARATELY = "LAYOUT_COMPONENTS_SEPARATELY";
75    private static final String SYMMETRIC_PLACEMENT = "SYMMETRIC_PLACEMENT";
76    private static final String MINIMUM_DISTANCES = "MINIMUM_DISTANCES";
77    private static final String NODE_TO_NODE_DISTANCE = "NODE_TO_NODE_DISTANCE";
78    private static final String NODE_TO_EDGE_DISTANCE = "NODE_TO_EDGE_DISTANCE";
79    private static final String EDGE_TO_EDGE_DISTANCE = "EDGE_TO_EDGE_DISTANCE";
80    private static final String MINIMUM_LAYER_DISTANCE = "MINIMUM_LAYER_DISTANCE";
81  
82    private static final String EDGE_SETTINGS = "EDGE_SETTINGS";
83    private static final String EDGE_ROUTING = "EDGE_ROUTING";
84    private static final String EDGE_ROUTING_ORTHOGONAL = "EDGE_ROUTING_ORTHOGONAL";
85    private static final String EDGE_ROUTING_POLYLINE = "EDGE_ROUTING_POLYLINE";
86    private static final String BACKLOOP_ROUTING = "BACKLOOP_ROUTING";
87    private static final String MINIMUM_FIRST_SEGMENT_LENGTH = "MINIMUM_FIRST_SEGMENT_LENGTH";
88    private static final String MINIMUM_LAST_SEGMENT_LENGTH = "MINIMUM_LAST_SEGMENT_LENGTH";
89    private static final String MINIMUM_EDGE_LENGTH = "MINIMUM_EDGE_LENGTH";
90    private static final String MINIMUM_EDGE_DISTANCE = "MINIMUM_EDGE_DISTANCE";
91    private static final String MINIMUM_SLOPE = "MINIMUM_SLOPE";
92    private static final String PC_OPTIMIZATION_ENABLED = "PC_OPTIMIZATION_ENABLED";
93  
94    private static final String RANKS = "RANKS";
95    private static final String RANKING_POLICY = "RANKING_POLICY";
96    private static final String HIERARCHICAL_OPTIMAL = "HIERARCHICAL_OPTIMAL";
97    private static final String HIERARCHICAL_TIGHT_TREE_HEURISTIC = "HIERARCHICAL_TIGHT_TREE_HEURISTIC";
98    private static final String HIERARCHICAL_TOPMOST = "HIERARCHICAL_TOPMOST";
99    private static final String BFS_LAYERS = "BFS_LAYERS";
100   private static final String FROM_SKETCH = "FROM_SKETCH";
101   private static final String LAYER_ALIGNMENT = "LAYER_ALIGNMENT";
102   private static final String TOP = "TOP";
103   private static final String CENTER = "CENTER";
104   private static final String BOTTOM = "BOTTOM";
105   private static final String FROM_SKETCH_PROPERTIES = "FROM_SKETCH_PROPERTIES";
106   private static final String SCALE = "SCALE";
107   private static final String HALO = "HALO";
108   private static final String MINIMUM_SIZE = "MINIMUM_SIZE";
109   private static final String MAXIMUM_SIZE = "MAXIMUM_SIZE";
110 
111 
112   private static final String LABELING = "LABELING";
113   private static final String NODE_PROPERTIES = "NODE_PROPERTIES";
114   private static final String CONSIDER_NODE_LABELS = "CONSIDER_NODE_LABELS";
115   private static final String EDGE_PROPERTIES = "EDGE_PROPERTIES";
116   private static final String EDGE_LABELING = "EDGE_LABELING";
117   private static final String EDGE_LABELING_NONE = "EDGE_LABELING_NONE";
118   private static final String EDGE_LABELING_HIERARCHIC = "EDGE_LABELING_HIERARCHIC";
119   private static final String EDGE_LABELING_GENERIC = "EDGE_LABELING_GENERIC";
120   private static final String EDGE_LABEL_MODEL = "EDGE_LABEL_MODEL";
121   private static final String EDGE_LABEL_MODEL_FREE = "EDGE_LABEL_MODEL_FREE";
122   private static final String EDGE_LABEL_MODEL_BEST = "EDGE_LABEL_MODEL_BEST";
123   private static final String EDGE_LABEL_MODEL_AS_IS = "EDGE_LABEL_MODEL_AS_IS";
124   private static final String EDGE_LABEL_MODEL_SIDE_SLIDER = "EDGE_LABEL_MODEL_SIDE_SLIDER";
125   private static final String EDGE_LABEL_MODEL_CENTER_SLIDER = "EDGE_LABEL_MODEL_CENTER_SLIDER";
126 
127   private static final String GROUPING = "GROUPING";
128   private static final String SWIMLANES = "SWIMLANES";
129   private static final String TREAT_ROOT_GROUPS_AS_SWIMLANES = "TREAT_ROOT_GROUPS_AS_SWIMLANES";
130   private static final String USE_ORDER_FROM_SKETCH = "USE_ORDER_FROM_SKETCH";
131   private static final String SWIMLANE_SPACING = "SWIMLANE_SPACING";
132   private static final String GROUP_LAYERING_STRATEGY = "GROUP_LAYERING_STRATEGY";
133   private static final String GLOBAL_LAYERING = "GLOBAL_LAYERING";
134   private static final String RECURSIVE_LAYERING = "RECURSIVE_LAYERING";
135   private static final String GROUP_ALIGNMENT = "GROUP_ALIGNMENT";
136   private static final String GROUP_ALIGN_TOP = "GROUP_ALIGN_TOP";
137   private static final String GROUP_ALIGN_CENTER = "GROUP_ALIGN_CENTER";
138   private static final String GROUP_ALIGN_BOTTOM = "GROUP_ALIGN_BOTTOM";
139 
140   private static final String GROUP_ENABLE_COMPACTION = "GROUP_ENABLE_COMPACTION";
141   private static final String GROUP_HORIZONTAL_COMPACTION = "GROUP_HORIZONTAL_COMPACTION";
142   private static final String GROUP_HORIZONTAL_COMPACTION_NONE = "GROUP_HORIZONTAL_COMPACTION_NONE";
143   private static final String GROUP_HORIZONTAL_COMPACTION_MAX = "GROUP_HORIZONTAL_COMPACTION_MAX";
144 
145   private static final Object[] edgeRoutingEnum = new Object[]{EDGE_ROUTING_ORTHOGONAL, EDGE_ROUTING_POLYLINE};
146 
147   private static final Object[] orientEnum = {TOP_TO_BOTTOM, LEFT_TO_RIGHT, BOTTOM_TO_TOP, RIGHT_TO_LEFT};
148 
149   private static final Object[] alignmentEnum = {TOP, CENTER, BOTTOM};
150   private static final String[] rankingPolicies = {HIERARCHICAL_OPTIMAL, HIERARCHICAL_TIGHT_TREE_HEURISTIC, BFS_LAYERS,
151       FROM_SKETCH, HIERARCHICAL_TOPMOST};
152 
153   private static final String[] edgeLabeling = {EDGE_LABELING_NONE, EDGE_LABELING_GENERIC, EDGE_LABELING_HIERARCHIC};
154 
155   private static final String[] edgeLabelModel = {
156       EDGE_LABEL_MODEL_BEST,
157       EDGE_LABEL_MODEL_AS_IS,
158       EDGE_LABEL_MODEL_CENTER_SLIDER,
159       EDGE_LABEL_MODEL_SIDE_SLIDER,
160       EDGE_LABEL_MODEL_FREE,
161   };
162 
163   private static final Object[] groupStrategyEnum = {GLOBAL_LAYERING, RECURSIVE_LAYERING};
164   private static final Object[] groupAlignmentEnum = {GROUP_ALIGN_TOP, GROUP_ALIGN_CENTER, GROUP_ALIGN_BOTTOM};
165   private static final Object[] groupHorizCompactionEnum = {GROUP_HORIZONTAL_COMPACTION_NONE, GROUP_HORIZONTAL_COMPACTION_MAX};
166 
167   public IncrementalHierarchicLayoutModule() {
168     super(INCREMENTAL_HIERARCHIC, "yFiles Layout Team", "A sophisticated hierarchic layout algorithm");
169     setPortIntersectionCalculatorEnabled(true);
170   }
171 
172   public OptionHandler createOptionHandler() {
173     OptionHandler op = new OptionHandler(getModuleName());
174 
175     OptionGroup og;
176 
177     op.useSection(GENERAL);
178 
179     og = new OptionGroup();
180     og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, INTERACTION);
181 
182     og.addItem(op.addBool(SELECTED_ELEMENTS_INCREMENTALLY, false));
183     OptionItem useDrawingItem = og.addItem(op.addBool(USE_DRAWING_AS_SKETCH, false));
184 
185     op.addEnum(ORIENTATION, orientEnum, 0);
186 
187     op.addBool(LAYOUT_COMPONENTS_SEPARATELY, false);
188     op.addBool(SYMMETRIC_PLACEMENT, true);
189 
190 
191     og = new OptionGroup();
192     og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, MINIMUM_DISTANCES);
193     og.addItem(op.addDouble(NODE_TO_NODE_DISTANCE, 30.0d));
194     og.addItem(op.addDouble(NODE_TO_EDGE_DISTANCE, 15.0d));
195     og.addItem(op.addDouble(EDGE_TO_EDGE_DISTANCE, 15.0d));
196     og.addItem(op.addDouble(MINIMUM_LAYER_DISTANCE, 10.0d));
197 
198     op.useSection(EDGE_SETTINGS);
199 
200     EnumOptionItem eoi = op.addEnum(EDGE_ROUTING, edgeRoutingEnum, 0);
201     eoi.setAttribute(DefaultEditorFactory.ATTRIBUTE_ENUM_STYLE,
202         DefaultEditorFactory.STYLE_RADIO_BUTTONS);
203     eoi.setAttribute(DefaultEditorFactory.ATTRIBUTE_ENUM_ALIGNMENT,
204         DefaultEditorFactory.ALIGNMENT_VERTICAL);
205 
206     op.addBool(BACKLOOP_ROUTING, false);
207     op.addDouble(MINIMUM_FIRST_SEGMENT_LENGTH, 10.0d);
208     op.addDouble(MINIMUM_LAST_SEGMENT_LENGTH, 15.0d);
209     op.addDouble(MINIMUM_EDGE_LENGTH, 20.0d);
210     op.addDouble(MINIMUM_EDGE_DISTANCE, 15.0d);
211 
212     ConstraintManager cm = new ConstraintManager(op);
213     cm.setEnabledOnValueEquals(eoi, EDGE_ROUTING_POLYLINE,
214         op.addDouble(MINIMUM_SLOPE, 0.25d, 0.0d, 5.0d, 2));
215 
216     op.addBool(PC_OPTIMIZATION_ENABLED, false);
217 
218     op.useSection(RANKS);
219     op.addEnum(RANKING_POLICY, rankingPolicies, 0);
220     op.addEnum(LAYER_ALIGNMENT, alignmentEnum, 1);
221 
222     og = new OptionGroup();
223     og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, FROM_SKETCH_PROPERTIES);
224     og.addItem(op.addDouble(SCALE, 1.0d, 0.0d, 5.0d, 1));
225     og.addItem(op.addDouble(HALO, 0.0d));
226     og.addItem(op.addDouble(MINIMUM_SIZE, 0.0d));
227     og.addItem(op.addDouble(MAXIMUM_SIZE, 1000.0d));
228 
229     Condition c =
230         cm.createConditionValueEquals(USE_DRAWING_AS_SKETCH, Boolean.FALSE).and(
231             cm.createConditionValueEquals(SELECTED_ELEMENTS_INCREMENTALLY, Boolean.FALSE));
232     cm.setEnabledOnCondition(c, op.getItem(RANKING_POLICY));
233 
234     c = c.inverse().or(cm.createConditionValueEquals(RANKING_POLICY, FROM_SKETCH));
235     cm.setEnabledOnCondition(c, og);
236 
237     op.useSection(LABELING);
238     og = new OptionGroup();
239     og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, NODE_PROPERTIES);
240     og.addItem(op.addBool(CONSIDER_NODE_LABELS, true));
241     og = new OptionGroup();
242     og.setAttribute(OptionGroup.ATTRIBUTE_TITLE, EDGE_PROPERTIES);
243     og.addItem(op.addEnum(EDGE_LABELING, edgeLabeling, 0));
244     cm.setEnabledOnValueEquals(op.getItem(EDGE_LABELING), EDGE_LABELING_NONE,
245         og.addItem(op.addEnum(EDGE_LABEL_MODEL, edgeLabelModel, 0)), true);
246 
247     op.useSection(GROUPING);
248     OptionItem groupLayeringItem = op.addEnum(GROUP_LAYERING_STRATEGY, groupStrategyEnum, 0);
249     OptionItem layerCompactionItem = op.addBool(GROUP_ENABLE_COMPACTION, true);
250     OptionItem groupAlignementItem = op.addEnum(GROUP_ALIGNMENT, groupAlignmentEnum, 0);
251     cm.setEnabledOnValueEquals(useDrawingItem, Boolean.FALSE, groupLayeringItem);
252     cm.setEnabledOnValueEquals(groupLayeringItem, RECURSIVE_LAYERING, layerCompactionItem);
253     cm.setEnabledOnValueEquals(groupLayeringItem, RECURSIVE_LAYERING, groupAlignementItem);
254     cm.setEnabledOnCondition(cm.createConditionValueEquals(groupLayeringItem, RECURSIVE_LAYERING).and(
255         cm.createConditionValueEquals(layerCompactionItem, Boolean.TRUE).inverse()), groupAlignementItem);
256 
257     cm.setEnabledOnCondition(cm.createConditionValueEquals(groupLayeringItem, RECURSIVE_LAYERING).and(
258         cm.createConditionValueEquals(useDrawingItem, Boolean.FALSE)), layerCompactionItem);
259     op.addEnum(GROUP_HORIZONTAL_COMPACTION, groupHorizCompactionEnum, 1);
260 
261     op.useSection(SWIMLANES);
262     final OptionItem swimlaneOption = op.addBool(TREAT_ROOT_GROUPS_AS_SWIMLANES, false);
263     final OptionItem fromSketchOption = op.addBool(USE_ORDER_FROM_SKETCH, false);
264     final OptionItem spacingOption = op.addDouble(SWIMLANE_SPACING, 0.0d);
265     cm.setEnabledOnValueEquals(swimlaneOption, Boolean.TRUE, fromSketchOption);
266     cm.setEnabledOnValueEquals(swimlaneOption, Boolean.TRUE, spacingOption);
267     return op;
268   }
269 
270   public void mainrun() {
271     CanonicMultiStageLayouter layouter = null;
272     Graph2D graph = getGraph2D();
273 
274     OptionHandler op = getOptionHandler();
275 
276     final IncrementalHierarchicLayouter ihl = new IncrementalHierarchicLayouter();
277     layouter = ihl;
278 
279     //  mark incremental elements if required
280     DataMap incrementalElements = null;
281     boolean fromSketch = op.getBool(USE_DRAWING_AS_SKETCH);
282     boolean incrementalLayout = op.getBool(SELECTED_ELEMENTS_INCREMENTALLY);
283     boolean selectedElements = !Selections.isEdgeSelectionEmpty(graph) || !Selections.isNodeSelectionEmpty(graph);
284 
285     if (incrementalLayout && selectedElements) {
286       // create storage for both nodes and edges
287       incrementalElements = Maps.createHashedDataMap();
288       // configure the mode
289       ihl.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_INCREMENTAL);
290       final IncrementalHintsFactory ihf = ihl.createIncrementalHintsFactory();
291 
292       for (NodeCursor nc = graph.selectedNodes(); nc.ok(); nc.next()) {
293         incrementalElements.set(nc.node(), ihf.createLayerIncrementallyHint(nc.node()));
294       }
295 
296       for (EdgeCursor ec = graph.selectedEdges(); ec.ok(); ec.next()) {
297         incrementalElements.set(ec.edge(), ihf.createSequenceIncrementallyHint(ec.edge()));
298       }
299       graph.addDataProvider(IncrementalHierarchicLayouter.INCREMENTAL_HINTS_DPKEY, incrementalElements);
300     } else if (fromSketch) {
301       ihl.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_INCREMENTAL);
302     } else {
303       ihl.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_FROM_SCRATCH);
304     }
305 
306     // cast to implementation simplex
307     ((SimplexNodePlacer) ihl.getNodePlacer()).setBaryCenterModeEnabled(op.getBool(SYMMETRIC_PLACEMENT));
308 
309     if (GROUP_HORIZONTAL_COMPACTION_NONE.equals(op.getString(GROUP_HORIZONTAL_COMPACTION))) {
310       ((SimplexNodePlacer) ihl.getNodePlacer()).setGroupCompactionStrategy(SimplexNodePlacer.GROUP_COMPACTION_NONE);
311     } else if (GROUP_HORIZONTAL_COMPACTION_MAX.equals(op.getString(GROUP_HORIZONTAL_COMPACTION))) {
312       ((SimplexNodePlacer) ihl.getNodePlacer()).setGroupCompactionStrategy(SimplexNodePlacer.GROUP_COMPACTION_MAX);
313     }
314 
315 
316     ihl.setComponentLayouterEnabled(op.getBool(LAYOUT_COMPONENTS_SEPARATELY));
317 
318     ihl.setMinimumLayerDistance(op.getDouble(MINIMUM_LAYER_DISTANCE));
319     ihl.setNodeToEdgeDistance(op.getDouble(NODE_TO_EDGE_DISTANCE));
320     ihl.setNodeToNodeDistance(op.getDouble(NODE_TO_NODE_DISTANCE));
321     ihl.setEdgeToEdgeDistance(op.getDouble(EDGE_TO_EDGE_DISTANCE));
322 
323     final NodeLayoutDescriptor nld = ihl.getNodeLayoutDescriptor();
324     final EdgeLayoutDescriptor eld = ihl.getEdgeLayoutDescriptor();
325 
326     eld.setOrthogonallyRouted(op.getEnum(EDGE_ROUTING) == 0);
327     eld.setMinimumFirstSegmentLength(op.getDouble(MINIMUM_FIRST_SEGMENT_LENGTH));
328     eld.setMinimumLastSegmentLength(op.getDouble(MINIMUM_LAST_SEGMENT_LENGTH));
329 
330     eld.setMinimumDistance(op.getDouble(MINIMUM_EDGE_DISTANCE));
331     eld.setMinimumLength(op.getDouble(MINIMUM_EDGE_LENGTH));
332 
333     eld.setMinimumSlope(op.getDouble(MINIMUM_SLOPE));
334 
335     eld.setSourcePortOptimizationEnabled(op.getBool(PC_OPTIMIZATION_ENABLED));
336     eld.setTargetPortOptimizationEnabled(op.getBool(PC_OPTIMIZATION_ENABLED));
337 
338     nld.setMinimumDistance(Math.min(ihl.getNodeToNodeDistance(), ihl.getNodeToEdgeDistance()));
339     nld.setMinimumLayerHeight(0);
340 
341     if (op.get(LAYER_ALIGNMENT).equals(TOP)) {
342       nld.setLayerAlignment(0.0);
343     } else if (op.get(LAYER_ALIGNMENT).equals(CENTER)) {
344       nld.setLayerAlignment(0.5);
345     } else if (op.get(LAYER_ALIGNMENT).equals(BOTTOM)) {
346       nld.setLayerAlignment(1.0);
347     }
348 
349     final OrientationLayouter ol = (OrientationLayouter) ihl.getOrientationLayouter();
350     if (op.get(ORIENTATION).equals(TOP_TO_BOTTOM)) {
351       ol.setOrientation(OrientationLayouter.TOP_TO_BOTTOM);
352     } else if (op.get(ORIENTATION).equals(LEFT_TO_RIGHT)) {
353       ol.setOrientation(OrientationLayouter.LEFT_TO_RIGHT);
354     } else if (op.get(ORIENTATION).equals(BOTTOM_TO_TOP)) {
355       ol.setOrientation(OrientationLayouter.BOTTOM_TO_TOP);
356     } else if (op.get(ORIENTATION).equals(RIGHT_TO_LEFT)) {
357       ol.setOrientation(OrientationLayouter.RIGHT_TO_LEFT);
358     }
359 
360     final String el = op.getString(EDGE_LABELING);
361     if (!el.equals(EDGE_LABELING_NONE)) {
362       setupEdgeLabelModel(el, op.getString(EDGE_LABEL_MODEL));
363       if (el.equals(EDGE_LABELING_GENERIC)) {
364         GreedyMISLabeling la = new GreedyMISLabeling();
365         la.setPlaceNodeLabels(false);
366         la.setPlaceEdgeLabels(true);
367         la.setProfitModel(new LabelRanking());
368         ihl.setLabelLayouter(la);
369         ihl.setLabelLayouterEnabled(true);
370       } else if (el.equals(EDGE_LABELING_HIERARCHIC)) {
371         ihl.setIntegratedEdgeLabelingEnabled(true);
372       }
373     } else {
374       ihl.setIntegratedEdgeLabelingEnabled(false);
375     }
376 
377     if (op.getBool(CONSIDER_NODE_LABELS)) {
378       ihl.setConsiderNodeLabelsEnabled(true);
379       ihl.getNodeLayoutDescriptor().setNodeLabelMode(NodeLayoutDescriptor.NODE_LABEL_MODE_CONSIDER_FOR_DRAWING);
380     } else {
381       ihl.setConsiderNodeLabelsEnabled(false);
382     }
383 
384     DataProvider oldSdp = null;
385     DataProvider oldTdp = null;
386 
387     if (op.getBool(BACKLOOP_ROUTING)) {
388       PortConstraint spc = null, tpc = null;
389       switch (ol.getOrientation()) {
390         case LayoutOrientation.TOP_TO_BOTTOM:
391           spc = PortConstraint.create(PortConstraint.SOUTH);
392           tpc = PortConstraint.create(PortConstraint.NORTH);
393           break;
394         case LayoutOrientation.LEFT_TO_RIGHT:
395           spc = PortConstraint.create(PortConstraint.EAST);
396           tpc = PortConstraint.create(PortConstraint.WEST);
397           break;
398         case LayoutOrientation.RIGHT_TO_LEFT:
399           spc = PortConstraint.create(PortConstraint.WEST);
400           tpc = PortConstraint.create(PortConstraint.EAST);
401           break;
402         case LayoutOrientation.BOTTOM_TO_TOP:
403           spc = PortConstraint.create(PortConstraint.NORTH);
404           tpc = PortConstraint.create(PortConstraint.SOUTH);
405           break;
406       }
407 
408       oldSdp = graph.getDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY);
409       oldTdp = graph.getDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY);
410 
411       DataProvider sdp = new BackloopConstraintDP(spc, oldSdp);
412       DataProvider tdp = new BackloopConstraintDP(tpc, oldTdp);
413 
414       if (oldSdp != null) {
415         graph.removeDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY);
416       }
417       if (oldTdp != null) {
418         graph.removeDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY);
419       }
420 
421       graph.addDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY, sdp);
422       graph.addDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY, tdp);
423     }
424 
425 
426     final String rp = op.getString(RANKING_POLICY);
427 
428     if (rp.equals(FROM_SKETCH)) {
429       ihl.setFromScratchLayeringStrategy(IncrementalHierarchicLayouter.LAYERING_STRATEGY_FROM_SKETCH);
430     } else if (rp.equals(HIERARCHICAL_OPTIMAL)) {
431       ihl.setFromScratchLayeringStrategy(IncrementalHierarchicLayouter.LAYERING_STRATEGY_HIERARCHICAL_OPTIMAL);
432     } else if (rp.equals(HIERARCHICAL_TIGHT_TREE_HEURISTIC)) {
433       ihl.setFromScratchLayeringStrategy(IncrementalHierarchicLayouter.LAYERING_STRATEGY_HIERARCHICAL_TIGHT_TREE);
434     } else if (rp.equals(HIERARCHICAL_TOPMOST)) {
435       ihl.setFromScratchLayeringStrategy(IncrementalHierarchicLayouter.LAYERING_STRATEGY_HIERARCHICAL_TOPMOST);
436     } else if (rp.equals(BFS_LAYERS)) {
437       ihl.setFromScratchLayeringStrategy(IncrementalHierarchicLayouter.LAYERING_STRATEGY_BFS);
438       getGraph2D().addDataProvider(BFSLayerer.CORE_NODES, Selections.createSelectionNodeMap(getGraph2D()));
439     }
440 
441     //configure AsIsLayerer
442     Object layerer = (ihl.getLayoutMode() == IncrementalHierarchicLayouter.LAYOUT_MODE_FROM_SCRATCH) ?
443         ihl.getFromScratchLayerer() : ihl.getFixedElementsLayerer();
444 
445     if (layerer instanceof OldLayererWrapper) {
446       y.layout.hierarchic.Layerer coreLayerer = ((OldLayererWrapper) layerer).getOldLayerer();
447       if (coreLayerer instanceof AsIsLayerer) {
448         AsIsLayerer ail = (AsIsLayerer) coreLayerer;
449         ail.setNodeHalo(op.getDouble(HALO));
450         ail.setNodeScalingFactor(op.getDouble(SCALE));
451         ail.setMinimumNodeSize(op.getDouble(MINIMUM_SIZE));
452         ail.setMaximumNodeSize(op.getDouble(MAXIMUM_SIZE));
453       }
454     }
455 
456     if (!fromSketch && op.getString(GROUP_LAYERING_STRATEGY).equals(RECURSIVE_LAYERING)) {
457       byte alignmentPolicy = IncrementalHierarchicLayouter.POLICY_ALIGN_GROUPS_TOP;
458       if (op.getString(GROUP_ALIGNMENT).equals(GROUP_ALIGN_CENTER)) {
459         alignmentPolicy = IncrementalHierarchicLayouter.POLICY_ALIGN_GROUPS_CENTER;
460       } else if (op.getString(GROUP_ALIGNMENT).equals(GROUP_ALIGN_BOTTOM)) {
461         alignmentPolicy = IncrementalHierarchicLayouter.POLICY_ALIGN_GROUPS_BOTTOM;
462       }
463       ihl.setGroupCompactionEnabled(op.getBool(GROUP_ENABLE_COMPACTION));
464       ihl.setGroupAlignmentPolicy(alignmentPolicy);
465       ihl.setRecursiveGroupLayeringEnabled(true);
466     } else {
467       ihl.setRecursiveGroupLayeringEnabled(false);
468     }
469 
470     if (op.getBool(SWIMLANES, TREAT_ROOT_GROUPS_AS_SWIMLANES)){
471       final TopLevelGroupToSwimlaneStage stage = new TopLevelGroupToSwimlaneStage();
472       stage.setFromSketchSwimlaneOrderingEnabled(op.getBool(SWIMLANES, USE_ORDER_FROM_SKETCH));
473       stage.setSpacing(op.getDouble(SWIMLANES, SWIMLANE_SPACING));
474       ihl.appendStage(stage);
475     }
476 
477     // initialize potential grouping information
478     GroupLayoutConfigurator glc = new GroupLayoutConfigurator(graph);
479     try {
480       // register grouping relevant DataProviders
481       glc.prepareAll();
482       // launch layouter in buffered mode
483       launchLayouter(layouter);
484     } finally {
485       // make sure the DataProviders will always be unregistered
486       glc.restoreAll();
487 
488       // remove the registered DataProvider instances
489       if (incrementalElements != null) {
490         graph.removeDataProvider(IncrementalHierarchicLayouter.INCREMENTAL_HINTS_DPKEY);
491         incrementalElements = null;
492       }
493 
494       if (op.getBool(BACKLOOP_ROUTING)) {
495         graph.removeDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY);
496         if (oldSdp != null) {
497           graph.addDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY, oldSdp);
498         }
499         graph.removeDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY);
500         if (oldTdp != null) {
501           graph.addDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY, oldTdp);
502         }
503       }
504     }
505   }
506 
507   void setupEdgeLabelModel(String edgeLabeling, String edgeLabelModel) {
508     if (edgeLabeling.equals(EDGE_LABELING_NONE) || edgeLabelModel.equals(EDGE_LABEL_MODEL_AS_IS)) {
509       return; //nothing to do
510     }
511 
512     if (edgeLabelModel.equals(EDGE_LABEL_MODEL_BEST)) {
513       if (edgeLabeling.equals(EDGE_LABELING_GENERIC)) {
514         edgeLabelModel = EDGE_LABEL_MODEL_SIDE_SLIDER;
515       } else if (edgeLabeling.equals(EDGE_LABELING_HIERARCHIC)) {
516         edgeLabelModel = EDGE_LABEL_MODEL_FREE;
517       }
518     }
519 
520     byte model = EdgeLabel.SIDE_SLIDER;
521     int preferredSide = LabelLayoutConstants.PLACE_RIGHT_OF_EDGE;
522     if (edgeLabelModel.equals(EDGE_LABEL_MODEL_CENTER_SLIDER)) {
523       model = EdgeLabel.CENTER_SLIDER;
524       preferredSide = LabelLayoutConstants.PLACE_ON_EDGE;
525     } else if (edgeLabelModel.equals(EDGE_LABEL_MODEL_FREE)) {
526       model = EdgeLabel.FREE;
527       preferredSide = LabelLayoutConstants.PLACE_ON_EDGE;
528     }
529 
530     Graph2D graph = getGraph2D();
531     for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
532       Edge e = ec.edge();
533       EdgeRealizer er = graph.getRealizer(e);
534       for (int i = 0; i < er.labelCount(); i++) {
535         EdgeLabel el = er.getLabel(i);
536         el.setModel(model);
537         int prefAlongEdge = el.getPreferredPlacement() & LabelLayoutConstants.PLACEMENT_ALONG_EDGE_MASK;
538         el.setPreferredPlacement((byte) (preferredSide | prefAlongEdge));
539       }
540     }
541   }
542 
543 
544   static final class BackloopConstraintDP extends DataProviderAdapter {
545     private PortConstraint pc;
546     private DataProvider delegate;
547     private static final PortConstraint anySide = PortConstraint.create(PortConstraint.ANY_SIDE);
548 
549     BackloopConstraintDP(PortConstraint pc, DataProvider delegate) {
550       this.pc = pc;
551       this.delegate = delegate;
552     }
553 
554     public Object get(Object o) {
555       if (delegate != null) {
556         Object delegateResult = delegate.get(o);
557         if (delegateResult != null) {
558           return delegateResult;
559         }
560       }
561       Edge e = (Edge) o;
562       if (e.isSelfLoop()) {
563         return anySide;
564       } else {
565         return pc;
566       }
567     }
568   }
569 }