1
28 package demo.layout.module;
29
30 import y.module.LayoutModule;
31 import y.module.YModule;
32
33 import y.base.DataMap;
34 import y.base.DataProvider;
35 import y.base.Edge;
36 import y.base.EdgeCursor;
37 import y.base.EdgeMap;
38 import y.base.Node;
39 import y.layout.AbstractLayoutStage;
40 import y.layout.CanonicMultiStageLayouter;
41 import y.layout.ComponentLayouter;
42 import y.layout.EdgeBundleDescriptor;
43 import y.layout.EdgeBundling;
44 import y.layout.EdgeLabelLayout;
45 import y.layout.LayoutGraph;
46 import y.layout.LayoutOrientation;
47 import y.layout.Layouter;
48 import y.layout.grouping.Grouping;
49 import y.layout.labeling.GreedyMISLabeling;
50 import y.layout.labeling.MISLabelingAlgorithm;
51 import y.layout.labeling.SALabeling;
52 import y.layout.router.OrganicEdgeRouter;
53 import y.layout.router.StraightLineEdgeRouter;
54 import y.layout.router.polyline.EdgeRouter;
55 import y.layout.tree.ARTreeLayouter;
56 import y.layout.tree.HVTreeLayouter;
57 import y.layout.tree.TreeLayouter;
58 import y.layout.tree.TreeReductionStage;
59 import y.option.ConstraintManager;
60 import y.option.EnumOptionItem;
61 import y.option.OptionHandler;
62 import y.option.OptionItem;
63 import y.util.DataProviderAdapter;
64 import y.util.GraphHider;
65 import y.util.Maps;
66 import y.view.Graph2D;
67 import y.view.Graph2DView;
68
69 import java.awt.Dimension;
70
71
78 public class TreeLayoutModule extends LayoutModule {
79
80 protected static final String MODULE_TREE = "TREE";
82
83 protected static final String SECTION_GENERAL = "GENERAL";
85 protected static final String ITEM_LAYOUT_STYLE = "LAYOUT_STYLE";
87 protected static final String VALUE_DIRECTED = "DIRECTED";
88 protected static final String VALUE_HV = "HV";
89 protected static final String VALUE_AR = "AR";
90 protected static final String ITEM_ROUTING_STYLE_FOR_NON_TREE_EDGES = "ROUTING_STYLE_FOR_NON_TREE_EDGES";
91 protected static final String VALUE_ROUTE_ORGANIC = "ROUTE_ORGANIC";
92 protected static final String VALUE_ROUTE_ORTHOGONAL = "ROUTE_ORTHOGONAL";
93 protected static final String VALUE_ROUTE_STRAIGHTLINE = "ROUTE_STRAIGHTLINE";
94 protected static final String VALUE_ROUTE_BUNDLED = "ROUTE_BUNDLED";
95 protected static final String EDGE_BUNDLING_STRENGTH = "EDGE_BUNDLING_STRENGTH";
96
97 protected static final String ITEM_ACT_ON_SELECTION_ONLY = "ACT_ON_SELECTION_ONLY";
98 protected static final String SECTION_DIRECTED = "DIRECTED";
100 protected static final String ITEM_MINIMAL_NODE_DISTANCE = "MINIMAL_NODE_DISTANCE";
102 protected static final String ITEM_MINIMAL_LAYER_DISTANCE = "MINIMAL_LAYER_DISTANCE";
103 protected static final String ITEM_ORIENTATION = "ORIENTATION";
104 protected static final String VALUE_TOP_TO_BOTTOM = "TOP_TO_BOTTOM";
105 protected static final String VALUE_LEFT_TO_RIGHT = "LEFT_TO_RIGHT";
106 protected static final String VALUE_BOTTOM_TO_TOP = "BOTTOM_TO_TOP";
107 protected static final String VALUE_RIGHT_TO_LEFT = "RIGHT_TO_LEFT";
108 protected static final String ITEM_PORT_STYLE = "PORT_STYLE";
109 protected static final String VALUE_NODE_CENTER_PORTS = "NODE_CENTER";
110 protected static final String VALUE_BORDER_CENTER_PORTS = "BORDER_CENTER";
111 protected static final String VALUE_BORDER_DISTRIBUTED_PORTS = "BORDER_DISTRIBUTED";
112 protected static final String VALUE_PORT_CONSTRAINTS_AWARE = "PORT_CONSTRAINTS_AWARE";
113 protected static final String ITEM_INTEGRATED_NODE_LABELING = "INTEGRATED_NODE_LABELING";
114 protected static final String ITEM_INTEGRATED_EDGE_LABELING = "INTEGRATED_EDGE_LABELING";
115 protected static final String ITEM_ORTHOGONAL_EDGE_ROUTING = "ORTHOGONAL_EDGE_ROUTING";
116 protected static final String ITEM_BUS_ALIGNMENT = "BUS_ALIGNMENT";
117 protected static final String ITEM_VERTICAL_ALIGNMENT = "VERTICAL_ALIGNMENT";
118 protected static final String VALUE_ALIGNMENT_TOP = "ALIGNMENT_TOP";
119 protected static final String VALUE_ALIGNMENT_CENTER = "ALIGNMENT_CENTER";
120 protected static final String VALUE_ALIGNMENT_BOTTOM = "ALIGNMENT_BOTTOM";
121 protected static final String ITEM_CHILD_PLACEMENT_POLICY = "CHILD_PLACEMENT_POLICY";
122 protected static final String VALUE_SIBLINGS_ON_SAME_LAYER = "SIBLINGS_ON_SAME_LAYER";
123 protected static final String VALUE_ALL_LEAVES_ON_SAME_LAYER = "ALL_LEAVES_ON_SAME_LAYER";
124 protected static final String VALUE_LEAVES_STACKED = "LEAVES_STACKED";
125 protected static final String VALUE_LEAVES_STACKED_LEFT = "LEAVES_STACKED_LEFT";
126 protected static final String VALUE_LEAVES_STACKED_RIGHT = "LEAVES_STACKED_RIGHT";
127 protected static final String ITEM_ENFORCE_GLOBAL_LAYERING = "ENFORCE_GLOBAL_LAYERING";
128 protected static final String SECTION_HV = "HV";
130 protected static final String ITEM_HORIZONTAL_SPACE_HV = "HORIZONTAL_SPACE";
132 protected static final String ITEM_VERTICAL_SPACE_HV = "VERTICAL_SPACE";
133 protected static final String SECTION_AR = "AR";
135 protected static final String ITEM_HORIZONTAL_SPACE_AR = "HORIZONTAL_SPACE";
137 protected static final String ITEM_VERTICAL_SPACE_AR = "VERTICAL_SPACE";
138 protected static final String ITEM_BEND_DISTANCE = "BEND_DISTANCE";
139 protected static final String ITEM_USE_VIEW_ASPECT_RATIO = "USE_VIEW_ASPECT_RATIO";
140 protected static final String ITEM_ASPECT_RATIO = "ASPECT_RATIO";
141
142
145 public TreeLayoutModule() {
146 super(MODULE_TREE);
147 setPortIntersectionCalculatorEnabled(true);
148 }
149
150
154 protected OptionHandler createOptionHandler() {
155 final OptionHandler options = new OptionHandler(getModuleName());
156 final ConstraintManager optionConstraints = new ConstraintManager(options);
157 final TreeLayouter defaultsTree = new TreeLayouter();
159 final HVTreeLayouter defaultsHv = new HVTreeLayouter();
160 final ARTreeLayouter defaultsAr = new ARTreeLayouter();
161 ((ComponentLayouter) defaultsHv.getComponentLayouter()).setStyle(ComponentLayouter.STYLE_MULTI_ROWS);
162 ((ComponentLayouter) defaultsAr.getComponentLayouter()).setStyle(ComponentLayouter.STYLE_MULTI_ROWS);
163
164 options.useSection(SECTION_GENERAL);
166 options.addEnum(ITEM_LAYOUT_STYLE, new String[]{
168 VALUE_DIRECTED,
169 VALUE_HV,
170 VALUE_AR
171 }, 0);
172 final EnumOptionItem itemNonTreeEdgeRouting = options.addEnum(ITEM_ROUTING_STYLE_FOR_NON_TREE_EDGES, new String[]{
173 VALUE_ROUTE_ORGANIC,
174 VALUE_ROUTE_ORTHOGONAL,
175 VALUE_ROUTE_STRAIGHTLINE,
176 VALUE_ROUTE_BUNDLED
177 }, 0);
178 options.addBool(ITEM_ACT_ON_SELECTION_ONLY, false);
179
180 final OptionItem itemBundlingStrength = options.addDouble(EDGE_BUNDLING_STRENGTH, 0.99, 0.0, 1.0);
181
182 final ConstraintManager.Condition bundlingCondition =
183 optionConstraints.createConditionValueEquals(itemNonTreeEdgeRouting, VALUE_ROUTE_BUNDLED);
184 optionConstraints.setEnabledOnCondition(bundlingCondition, itemBundlingStrength);
185
186 options.useSection(SECTION_DIRECTED);
188 options.addInt(ITEM_MINIMAL_NODE_DISTANCE, (int) defaultsTree.getMinimalNodeDistance(), 1, 100);
190 options.addInt(ITEM_MINIMAL_LAYER_DISTANCE, (int) defaultsTree.getMinimalLayerDistance(), 10, 300);
191 options.addEnum(ITEM_ORIENTATION, new String[]{
192 VALUE_TOP_TO_BOTTOM,
193 VALUE_LEFT_TO_RIGHT,
194 VALUE_BOTTOM_TO_TOP,
195 VALUE_RIGHT_TO_LEFT
196 }, 0);
197 options.addEnum(ITEM_PORT_STYLE, new String[]{
198 VALUE_NODE_CENTER_PORTS,
199 VALUE_BORDER_CENTER_PORTS,
200 VALUE_BORDER_DISTRIBUTED_PORTS,
201 VALUE_PORT_CONSTRAINTS_AWARE,
202 }, 0);
203 options.addBool(ITEM_INTEGRATED_NODE_LABELING, false);
204 options.addBool(ITEM_INTEGRATED_EDGE_LABELING, false);
205 final OptionItem itemEdgeRouting = options.addBool(ITEM_ORTHOGONAL_EDGE_ROUTING, false);
206 final OptionItem itemBusAlignment = options.addEnum(ITEM_BUS_ALIGNMENT, new String[]{
207 VALUE_ALIGNMENT_TOP,
208 VALUE_ALIGNMENT_CENTER,
209 VALUE_ALIGNMENT_BOTTOM,
210 }, 1);
211 options.addEnum(ITEM_VERTICAL_ALIGNMENT, new String[]{
212 VALUE_ALIGNMENT_TOP,
213 VALUE_ALIGNMENT_CENTER,
214 VALUE_ALIGNMENT_BOTTOM,
215 }, 1);
216 final OptionItem itemChildPlacement = options.addEnum(ITEM_CHILD_PLACEMENT_POLICY, new String[]{
217 VALUE_SIBLINGS_ON_SAME_LAYER,
218 VALUE_ALL_LEAVES_ON_SAME_LAYER,
219 VALUE_LEAVES_STACKED,
220 VALUE_LEAVES_STACKED_LEFT,
221 VALUE_LEAVES_STACKED_RIGHT
222 }, 0);
223 final OptionItem itemGlobalLayering = options.addBool(ITEM_ENFORCE_GLOBAL_LAYERING, false);
224 final ConstraintManager.Condition conditionBusAlignment =
226 optionConstraints.createConditionValueEquals(itemEdgeRouting, Boolean.TRUE)
227 .and(optionConstraints.createConditionValueEquals(itemGlobalLayering, Boolean.TRUE)
228 .or(optionConstraints.createConditionValueEquals(itemChildPlacement, VALUE_ALL_LEAVES_ON_SAME_LAYER)));
229 optionConstraints.setEnabledOnCondition(conditionBusAlignment, itemBusAlignment);
230
231 options.useSection(SECTION_HV);
233 options.addInt(ITEM_HORIZONTAL_SPACE_HV, (int) defaultsHv.getHorizontalSpace());
235 options.addInt(ITEM_VERTICAL_SPACE_HV, (int) defaultsHv.getVerticalSpace());
236
237 options.useSection(SECTION_AR);
239 options.addInt(ITEM_HORIZONTAL_SPACE_AR, (int) defaultsAr.getHorizontalSpace());
241 options.addInt(ITEM_VERTICAL_SPACE_AR, (int) defaultsAr.getVerticalSpace());
242 options.addInt(ITEM_BEND_DISTANCE, (int) defaultsAr.getBendDistance());
243 final OptionItem itemUseViewAspectRatio = options.addBool(ITEM_USE_VIEW_ASPECT_RATIO, true);
244 final OptionItem itemAspectRatio = options.addDouble(ITEM_ASPECT_RATIO, defaultsAr.getAspectRatio());
245 optionConstraints.setEnabledOnValueEquals(itemUseViewAspectRatio, Boolean.FALSE, itemAspectRatio);
247
248 return options;
249 }
250
251
255 protected void mainrun() {
256 final CanonicMultiStageLayouter layouter;
257
258 final OptionHandler options = getOptionHandler();
259 final Graph2D graph = getGraph2D();
260
261 String style = options.getString(ITEM_LAYOUT_STYLE);
262 if (VALUE_HV.equals(style)) {
263 final HVTreeLayouter hv = new HVTreeLayouter();
264 configure(hv, options);
265 layouter = hv;
266 } else if (VALUE_AR.equals(style)) {
267 final ARTreeLayouter ar = new ARTreeLayouter();
268 configure(ar, options);
269 layouter = ar;
270 } else {
271 final TreeLayouter tree = new TreeLayouter();
273 configure(tree, options);
274 layouter = tree;
275 }
276
277 final TreeReductionStage trs = new TreeReductionStage();
278 configure(trs, options);
279
280 layouter.prependStage(trs);
283 layouter.prependStage(new HandleEdgesBetweenGroupsStage());
285 prepareGraph(graph, options);
286 try {
287 launchLayouter(layouter);
288 } finally {
289 restoreGraph(graph, options);
290 }
291 }
292
293
303 protected void prepareGraph(final Graph2D graph, final OptionHandler options) {
304 String style = options.getString(ITEM_LAYOUT_STYLE);
305 if (VALUE_HV.equals(style)) {
306 backupDataProvider(graph, HVTreeLayouter.SUBTREE_ORIENTATION);
308 graph.addDataProvider(HVTreeLayouter.SUBTREE_ORIENTATION, new DataProviderAdapter() {
309 public Object get(Object node) {
310 if (graph.isSelected((Node) node)) {
311 return HVTreeLayouter.VERTICAL_SUBTREE;
312 } else {
313 return HVTreeLayouter.HORIZONTAL_SUBTREE;
314 }
315 }
316 });
317
318 } else if (VALUE_AR.equals(style)) {
319 backupDataProvider(graph, ARTreeLayouter.ROUTING_POLICY);
321 graph.addDataProvider(ARTreeLayouter.ROUTING_POLICY, new DataProviderAdapter() {
322 public Object get( Object node ) {
323 if (graph.isSelected((Node) node)) {
324 return ARTreeLayouter.ROUTING_HORIZONTAL;
325 } else {
326 return ARTreeLayouter.ROUTING_VERTICAL;
327 }
328 }
329 });
330 }
331 }
332
333
339 protected void restoreGraph(final Graph2D graph, final OptionHandler options) {
340 String style = options.getString(ITEM_LAYOUT_STYLE);
342 if (VALUE_HV.equals(style)) {
343 restoreDataProvider(graph, HVTreeLayouter.SUBTREE_ORIENTATION);
344 } else if (VALUE_AR.equals(style)) {
345 restoreDataProvider(graph, ARTreeLayouter.ROUTING_POLICY);
346 }
347 }
348
349
354 protected void configure(TreeLayouter tree, final OptionHandler options) {
355 ((ComponentLayouter) tree.getComponentLayouter()).setStyle(ComponentLayouter.STYLE_MULTI_ROWS);
356
357 tree.setMinimalNodeDistance(options.getInt(SECTION_DIRECTED, ITEM_MINIMAL_NODE_DISTANCE));
358 tree.setMinimalLayerDistance(options.getInt(SECTION_DIRECTED, ITEM_MINIMAL_LAYER_DISTANCE));
359
360 final String orientation = options.getString(ITEM_ORIENTATION);
361 if (VALUE_TOP_TO_BOTTOM.equals(orientation)) {
362 tree.setLayoutOrientation(LayoutOrientation.TOP_TO_BOTTOM);
363 } else if (VALUE_BOTTOM_TO_TOP.equals(orientation)) {
364 tree.setLayoutOrientation(LayoutOrientation.BOTTOM_TO_TOP);
365 } else if (VALUE_RIGHT_TO_LEFT.equals(orientation)) {
366 tree.setLayoutOrientation(LayoutOrientation.RIGHT_TO_LEFT);
367 } else {
368 tree.setLayoutOrientation(LayoutOrientation.LEFT_TO_RIGHT);
369 }
370
371 if (options.getBool(ITEM_ORTHOGONAL_EDGE_ROUTING)) {
372 tree.setLayoutStyle(TreeLayouter.ORTHOGONAL_STYLE);
373 } else {
374 tree.setLayoutStyle(TreeLayouter.PLAIN_STYLE);
375 }
376
377 final String leafLayoutPolicyStr = options.getString(ITEM_CHILD_PLACEMENT_POLICY);
378 if (VALUE_SIBLINGS_ON_SAME_LAYER.equals(leafLayoutPolicyStr)) {
379 tree.setChildPlacementPolicy(TreeLayouter.CHILD_PLACEMENT_POLICY_SIBLINGS_ON_SAME_LAYER);
380 } else if (VALUE_LEAVES_STACKED_LEFT.equals(leafLayoutPolicyStr)) {
381 tree.setChildPlacementPolicy(TreeLayouter.CHILD_PLACEMENT_POLICY_LEAVES_STACKED_LEFT);
382 } else if (VALUE_LEAVES_STACKED_RIGHT.equals(leafLayoutPolicyStr)) {
383 tree.setChildPlacementPolicy(TreeLayouter.CHILD_PLACEMENT_POLICY_LEAVES_STACKED_RIGHT);
384 } else if (VALUE_LEAVES_STACKED.equals(leafLayoutPolicyStr)) {
385 tree.setChildPlacementPolicy(TreeLayouter.CHILD_PLACEMENT_POLICY_LEAVES_STACKED);
386 } else if (VALUE_ALL_LEAVES_ON_SAME_LAYER.equals(leafLayoutPolicyStr)) {
387 tree.setChildPlacementPolicy(TreeLayouter.CHILD_PLACEMENT_POLICY_ALL_LEAVES_ON_SAME_LAYER);
388 }
389
390 if (options.getBool(ITEM_ENFORCE_GLOBAL_LAYERING)) {
391 tree.setEnforceGlobalLayering(true);
392 } else {
393 tree.setEnforceGlobalLayering(false);
394 }
395
396 final String portStyle = options.getString(ITEM_PORT_STYLE);
397 if (VALUE_NODE_CENTER_PORTS.equals(portStyle)) {
398 tree.setPortStyle(TreeLayouter.NODE_CENTER_PORTS);
399 } else if (VALUE_BORDER_CENTER_PORTS.equals(portStyle)) {
400 tree.setPortStyle(TreeLayouter.BORDER_CENTER_PORTS);
401 } else if (VALUE_BORDER_DISTRIBUTED_PORTS.equals(portStyle)) {
402 tree.setPortStyle(TreeLayouter.BORDER_DISTRIBUTED_PORTS);
403 } else {
404 tree.setPortStyle(TreeLayouter.PORT_CONSTRAINTS_AWARE);
405 }
406
407 tree.setIntegratedNodeLabelingEnabled(options.getBool(SECTION_DIRECTED, ITEM_INTEGRATED_NODE_LABELING));
408 tree.setIntegratedEdgeLabelingEnabled(options.getBool(SECTION_DIRECTED, ITEM_INTEGRATED_EDGE_LABELING));
409
410 final String verticalAlignment = options.getString(ITEM_VERTICAL_ALIGNMENT);
411 if (VALUE_ALIGNMENT_TOP.equals(verticalAlignment)) {
412 tree.setVerticalAlignment(0);
413 } else if (VALUE_ALIGNMENT_BOTTOM.equals(verticalAlignment)) {
414 tree.setVerticalAlignment(1);
415 } else {
416 tree.setVerticalAlignment(0.5); }
418
419 final String busAlignment = options.getString(ITEM_BUS_ALIGNMENT);
420 if (VALUE_ALIGNMENT_TOP.equals(busAlignment)) {
421 tree.setBusAlignment(0.1);
422 } else if (VALUE_ALIGNMENT_BOTTOM.equals(busAlignment)) {
423 tree.setBusAlignment(0.9);
424 } else {
425 tree.setBusAlignment(0.5); }
427
428 tree.setSubgraphLayouterEnabled(options.getBool(ITEM_ACT_ON_SELECTION_ONLY));
429 }
430
431
436 protected void configure(final ARTreeLayouter ar, final OptionHandler options) {
437 if (options.getBool(ITEM_USE_VIEW_ASPECT_RATIO)) {
438 Graph2DView view = getGraph2DView();
439 if (view != null) {
440 Dimension dim = view.getSize();
441 ar.setAspectRatio(dim.getWidth() / (double) dim.getHeight());
442 } else {
443 ar.setAspectRatio(1);
444 }
445 } else {
446 ar.setAspectRatio(options.getDouble(ITEM_ASPECT_RATIO));
447 }
448 ar.setHorizontalSpace(options.getInt(SECTION_AR, ITEM_HORIZONTAL_SPACE_AR));
449 ar.setVerticalSpace(options.getInt(SECTION_AR, ITEM_VERTICAL_SPACE_AR));
450 ar.setBendDistance(options.getInt(SECTION_AR, ITEM_BEND_DISTANCE));
451 ar.setSubgraphLayouterEnabled(options.getBool(ITEM_ACT_ON_SELECTION_ONLY));
452 }
453
454
460 protected void configure(HVTreeLayouter hv, OptionHandler options) {
461 hv.setHorizontalSpace(options.getInt(SECTION_HV, ITEM_HORIZONTAL_SPACE_HV));
462 hv.setVerticalSpace(options.getInt(SECTION_HV, ITEM_VERTICAL_SPACE_HV));
463 hv.setSubgraphLayouterEnabled(options.getBool(ITEM_ACT_ON_SELECTION_ONLY));
464 }
465
466
467
472 protected void configure(final TreeReductionStage reduction, final OptionHandler options) {
473 reduction.setMultiParentAllowed(
475 VALUE_DIRECTED.equals(options.getString(ITEM_LAYOUT_STYLE)) &&
476 !options.getBool(ITEM_ENFORCE_GLOBAL_LAYERING) &&
477 !VALUE_ALL_LEAVES_ON_SAME_LAYER.equals(options.getString(ITEM_CHILD_PLACEMENT_POLICY)));
478
479 final Object routingStyle = options.get(ITEM_ROUTING_STYLE_FOR_NON_TREE_EDGES);
480 if (VALUE_ROUTE_ORGANIC.equals(routingStyle)) {
481 OrganicEdgeRouter organic = new OrganicEdgeRouter();
482 reduction.setNonTreeEdgeRouter(organic);
483 reduction.setNonTreeEdgeSelectionKey(OrganicEdgeRouter.ROUTE_EDGE_DPKEY);
484 } else if (VALUE_ROUTE_ORTHOGONAL.equals(routingStyle)) {
485 EdgeRouter orthogonal = new EdgeRouter();
486 orthogonal.setReroutingEnabled(true);
487 orthogonal.setSphereOfAction(EdgeRouter.ROUTE_SELECTED_EDGES);
488
489 reduction.setNonTreeEdgeSelectionKey(orthogonal.getSelectedEdgesDpKey());
490 reduction.setNonTreeEdgeRouter(orthogonal);
491 } else if (VALUE_ROUTE_STRAIGHTLINE.equals(routingStyle)) {
492 reduction.setNonTreeEdgeRouter(reduction.createStraightlineRouter());
493 } else if (VALUE_ROUTE_BUNDLED.equals(routingStyle)){
494
495 final EdgeBundling ebc = reduction.getEdgeBundling();
497 final EdgeBundleDescriptor descriptor = new EdgeBundleDescriptor();
498 descriptor.setBundled(true);
499 ebc.setDefaultBundleDescriptor(descriptor);
500 ebc.setBundlingStrength(options.getDouble(EDGE_BUNDLING_STRENGTH));
501
502 OrganicEdgeRouter organic = new OrganicEdgeRouter();
504 reduction.setNonTreeEdgeRouter(organic);
505 reduction.setNonTreeEdgeSelectionKey(OrganicEdgeRouter.ROUTE_EDGE_DPKEY);
506 }
507
508 if (options.getBool(ITEM_INTEGRATED_EDGE_LABELING)) {
509 final GreedyMISLabeling labeling = new GreedyMISLabeling();
511 labeling.setOptimizationStrategy(MISLabelingAlgorithm.OPTIMIZATION_BALANCED);
512 labeling.setPlaceNodeLabels(false);
513 labeling.setPlaceEdgeLabels(true);
514 labeling.setSelection("NonTreeEdgeLabelsSelectionDp");
515 reduction.setNonTreeEdgeLabelingAlgorithm(labeling);
516 reduction.setNonTreeEdgeLabelSelectionKey(labeling.getSelectionKey());
517 }
518 }
519
520
551 private static class HandleEdgesBetweenGroupsStage extends AbstractLayoutStage {
552
553 private boolean considerEdgeLabels = true;
554
555 private Layouter markedEdgeRouter;
556 private Object edgeSelectionKey;
557
558
561 public HandleEdgesBetweenGroupsStage() {
562 markedEdgeRouter = new StraightLineEdgeRouter();
563 edgeSelectionKey = StraightLineEdgeRouter.SELECTED_EDGES;
564 }
565
566
576 public boolean isConsiderEdgeLabelsEnabled() {
577 return considerEdgeLabels;
578 }
579
580
591 public void setConsiderEdgeLabelsEnabled( final boolean considerEdgeLabels ) {
592 this.considerEdgeLabels = considerEdgeLabels;
593 }
594
595
604 public Object getEdgeSelectionKey() {
605 return edgeSelectionKey;
606 }
607
608
609
617 public void setEdgeSelectionKey( final Object edgeSelectionKey ) {
618 this.edgeSelectionKey = edgeSelectionKey;
619 }
620
621
632 public Layouter getMarkedEdgeRouter() {
633 return markedEdgeRouter;
634 }
635
636
646 public void setMarkedEdgeRouter( final Layouter markedEdgeRouter ) {
647 this.markedEdgeRouter = markedEdgeRouter;
648 }
649
650
657 public boolean canLayout(LayoutGraph graph) {
658 return true;
659 }
660
661
672 public void doLayout( final LayoutGraph graph ) {
673
674 final boolean existGroups = !Grouping.isFlat(graph);
675
676 if (!existGroups){
677 doLayoutCore(graph);
679 } else {
680 final Grouping grouping = new Grouping(graph);
681 final GraphHider edgeHider = new GraphHider(graph);
682
683 final EdgeMap hiddenEdgesMap = graph.createEdgeMap();
685
686 boolean existHiddenEdges = false;
687 for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
689 final Edge edge = ec.edge();
690
691 if (grouping.isGroupNode(edge.source()) || grouping.isGroupNode(edge.target())){
692 hiddenEdgesMap.setBool(edge, true);
693 edgeHider.hide(edge);
694 if (!existHiddenEdges){
695 existHiddenEdges = true;
696 }
697 }
698 }
699
700 doLayoutCore(graph);
702
703 if (existHiddenEdges) {
704 edgeHider.unhideAll();
706
707 routeSelectedEdges(graph, hiddenEdgesMap);
709
710 if (considerEdgeLabels) {
711 final Object selectionKey = "SELECTED_LABELS";
713 graph.addDataProvider(selectionKey, new DataProviderAdapter() {
714 public boolean getBool( Object dataHolder ) {
715 if (dataHolder instanceof EdgeLabelLayout) {
716 final EdgeLabelLayout labelLayout = (EdgeLabelLayout) dataHolder;
717 final Edge relatedEdge = graph.getFeature(labelLayout);
718 return hiddenEdgesMap.getBool(relatedEdge);
719 } else {
720 return false;
721 }
722 }
723 });
724
725 final GreedyMISLabeling labeling = new GreedyMISLabeling();
727 labeling.setOptimizationStrategy(MISLabelingAlgorithm.OPTIMIZATION_BALANCED);
728 labeling.setPlaceNodeLabels(false);
729 labeling.setPlaceEdgeLabels(true);
730 labeling.setSelection(selectionKey);
731 labeling.doLayout(graph);
732
733 graph.removeDataProvider(selectionKey);
735 }
736 }
737
738 graph.disposeEdgeMap(hiddenEdgesMap);
739 grouping.dispose();
740 }
741 }
742
743
758 protected void routeSelectedEdges(LayoutGraph graph, EdgeMap markedEdgeMap) {
759 if (markedEdgeRouter == null) return;
760
761 DataProvider backupDP = null;
762 if (edgeSelectionKey != null) {
763 backupDP = graph.getDataProvider(edgeSelectionKey);
764 graph.addDataProvider(edgeSelectionKey, markedEdgeMap);
765 }
766 if (markedEdgeRouter instanceof StraightLineEdgeRouter) {
767 final StraightLineEdgeRouter router = (StraightLineEdgeRouter) markedEdgeRouter;
768 router.setSphereOfAction(StraightLineEdgeRouter.ROUTE_SELECTED_EDGES);
769 router.setSelectedEdgesDpKey(edgeSelectionKey);
770 }
771
772 markedEdgeRouter.doLayout(graph);
773
774 graph.removeDataProvider(edgeSelectionKey);
775 if (backupDP != null) {
776 graph.addDataProvider(edgeSelectionKey, backupDP);
777 }
778 }
779 }
780 }
781