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