1
28 package demo.layout.module;
29
30 import y.module.LayoutModule;
31 import y.module.YModule;
32
33 import y.base.DataProvider;
34 import y.base.Edge;
35 import y.base.Node;
36 import y.base.NodeCursor;
37 import y.base.NodeMap;
38 import y.layout.ComponentLayouter;
39 import y.layout.PortConstraintKeys;
40 import y.layout.organic.OutputRestriction;
41 import y.layout.organic.SmartOrganicLayouter;
42 import y.option.ConstraintManager;
43 import y.option.ConstraintManager.Condition;
44 import y.option.DefaultEditorFactory;
45 import y.option.DoubleOptionItem;
46 import y.option.EnumOptionItem;
47 import y.option.IntOptionItem;
48 import y.option.OptionHandler;
49 import y.option.OptionGroup;
50 import y.option.OptionItem;
51 import y.util.DataProviderAdapter;
52 import y.util.DataProviders;
53 import y.util.Maps;
54 import y.view.Arrow;
55 import y.view.EdgeRealizer;
56 import y.view.Graph2D;
57 import y.view.Graph2DLayoutExecutor;
58 import y.view.Selections;
59 import y.view.hierarchy.HierarchyManager;
60
61 import java.awt.Rectangle;
62
63
71 public class SmartOrganicLayoutModule extends LayoutModule {
72 protected static final String MODULE_SMARTORGANIC = "SMARTORGANIC";
74
75 protected static final String SECTION_VISUAL = "VISUAL";
77 protected static final String ITEM_SCOPE = "SCOPE";
79 protected static final String VALUE_SCOPE_ALL = "ALL";
80 protected static final String VALUE_SCOPE_MAINLY_SUBSET = "MAINLY_SUBSET";
81 protected static final String VALUE_SCOPE_SUBSET = "SUBSET";
82 protected static final String ITEM_PREFERRED_EDGE_LENGTH = "PREFERRED_EDGE_LENGTH";
83 protected static final String ITEM_CONSIDER_NODE_LABELS = "CONSIDER_NODE_LABELS";
84 protected static final String ITEM_ALLOW_NODE_OVERLAPS = "ALLOW_NODE_OVERLAPS";
85 protected static final String ITEM_MINIMAL_NODE_DISTANCE = "MINIMAL_NODE_DISTANCE";
86 protected static final String ITEM_AVOID_NODE_EDGE_OVERLAPS = "AVOID_NODE_EDGE_OVERLAPS";
87 protected static final String ITEM_COMPACTNESS = "COMPACTNESS";
88 protected static final String ITEM_USE_AUTO_CLUSTERING = "USE_AUTO_CLUSTERING";
89 protected static final String ITEM_AUTO_CLUSTERING_QUALITY = "AUTO_CLUSTERING_QUALITY";
90
91 protected static final String SECTION_RESTRICTIONS = "RESTRICTIONS";
93 protected static final String ITEM_RESTRICT_OUTPUT = "RESTRICT_OUTPUT";
95 protected static final String VALUE_NONE = "NONE";
96 protected static final String VALUE_OUTPUT_CAGE = "OUTPUT_CAGE";
97 protected static final String VALUE_OUTPUT_CIRCULAR_CAGE = "OUTPUT_CIRCULAR_CAGE";
98 protected static final String VALUE_OUTPUT_AR = "OUTPUT_AR";
99 protected static final String VALUE_OUTPUT_ELLIPTICAL_CAGE = "OUTPUT_ELLIPTICAL_CAGE";
100 protected static final String TITLE_OUTPUT_CAGE = "OUTPUT_CAGE";
101 protected static final String ITEM_RECT_CAGE_USE_VIEW = "RECT_CAGE_USE_VIEW";
102 protected static final String ITEM_CAGE_X = "CAGE_X";
103 protected static final String ITEM_CAGE_Y = "CAGE_Y";
104 protected static final String ITEM_CAGE_WIDTH = "CAGE_WIDTH";
105 protected static final String ITEM_CAGE_HEIGHT = "CAGE_HEIGHT";
106 protected static final String TITLE_OUTPUT_CIRCULAR_CAGE = "OUTPUT_CIRCULAR_CAGE";
107 protected static final String ITEM_CIRC_CAGE_USE_VIEW = "CIRC_CAGE_USE_VIEW";
108 protected static final String ITEM_CAGE_CENTER_X = "CAGE_CENTER_X";
109 protected static final String ITEM_CAGE_CENTER_Y = "CAGE_CENTER_Y";
110 protected static final String ITEM_CAGE_RADIUS = "CAGE_RADIUS";
111 protected static final String TITLE_OUTPUT_AR = "OUTPUT_AR";
112 protected static final String ITEM_AR_CAGE_USE_VIEW = "AR_CAGE_USE_VIEW";
113 protected static final String ITEM_CAGE_RATIO = "CAGE_RATIO";
114 protected static final String TITLE_OUTPUT_ELLIPTICAL_CAGE = "OUTPUT_ELLIPTICAL_CAGE";
115 protected static final String ITEM_ELL_CAGE_USE_VIEW = "ELL_CAGE_USE_VIEW";
116 protected static final String ITEM_ELLIPTICAL_CAGE_X = "ELLIPTICAL_CAGE_X";
117 protected static final String ITEM_ELLIPTICAL_CAGE_Y = "ELLIPTICAL_CAGE_Y";
118 protected static final String ITEM_ELLIPTICAL_CAGE_WIDTH = "ELLIPTICAL_CAGE_WIDTH";
119 protected static final String ITEM_ELLIPTICAL_CAGE_HEIGHT = "ELLIPTICAL_CAGE_HEIGHT";
120
121 protected static final String SECTION_GROUPING = "GROUPING";
123 protected static final String ITEM_GROUP_LAYOUT_POLICY = "GROUP_LAYOUT_POLICY";
125 protected static final String VALUE_LAYOUT_GROUPS = "LAYOUT_GROUPS";
126 protected static final String VALUE_FIX_GROUP_CONTENTS = "FIX_GROUP_CONTENTS";
127 protected static final String VALUE_FIX_GROUP_BOUNDS = "FIX_GROUP_BOUNDS";
128 protected static final String VALUE_IGNORE_GROUPS = "IGNORE_GROUPS";
129 protected static final String ITEM_USE_AUTOMATIC_GROUP_NODE_COMPACTION = "USE_AUTOMATIC_GROUP_NODE_COMPACTION";
130 protected static final String ITEM_GROUP_COMPACTNESS = "GROUP_COMPACTNESS";
131
132 protected static final String SECTION_ALGORITHM = "ALGORITHM";
134 protected static final String ITEM_QUALITY_TIME_RATIO = "QUALITY_TIME_RATIO";
136 protected static final String ITEM_MAXIMAL_DURATION = "MAXIMAL_DURATION";
137 protected static final String ITEM_ACTIVATE_DETERMINISTIC_MODE = "ACTIVATE_DETERMINISTIC_MODE";
138 protected static final String ITEM_ALLOW_MULTI_THREADING = "ALLOW_MULTI_THREADING";
139
140 protected static final String SECTION_SUBSTRUCTURE_LAYOUT = "SUBSTRUCTURE_LAYOUT";
142 protected static final String ITEM_CONSIDER_EDGE_DIRECTION = "CONSIDER_EDGE_DIRECTION";
143 protected static final String ITEM_USE_EDGE_GROUPING = "USE_EDGE_GROUPING";
144 protected static final String ITEM_CYCLE = "CYCLE";
145 protected static final String VALUE_CYCLE_NONE = "NONE";
146 protected static final String VALUE_CYCLE_CIRCULAR = "CIRCULAR";
147 protected static final String ITEM_CHAIN = "CHAIN";
148 protected static final String VALUE_CHAIN_NONE = "NONE";
149 protected static final String VALUE_CHAIN_RECTANGULAR = "RECTANGULAR";
150 protected static final String VALUE_CHAIN_STRAIGHT_LINE = "STRAIGHT_LINE";
151 protected static final String ITEM_STAR = "STAR";
152 protected static final String VALUE_STAR_NONE = "NONE";
153 protected static final String VALUE_STAR_SEPARATED_RADIAL = "SEPARATED_RADIAL";
154 protected static final String VALUE_STAR_RADIAL = "RADIAL";
155 protected static final String VALUE_STAR_CIRCULAR = "CIRCULAR";
156 protected static final String ITEM_PARALLEL = "PARALLEL";
157 protected static final String VALUE_PARALLEL_NONE = "NONE";
158 protected static final String VALUE_PARALLEL_STRAIGHT_LINE = "STRAIGHT_LINE";
159 protected static final String VALUE_PARALLEL_RECTANGULAR = "RECTANGULAR";
160 protected static final String VALUE_PARALLEL_RADIAL = "RADIAL";
161
162 private boolean isNodeDPAddedByModule;
163
164
167 public SmartOrganicLayoutModule() {
168 super(MODULE_SMARTORGANIC);
169 setPortIntersectionCalculatorEnabled(true);
170 }
171
172
176 protected OptionHandler createOptionHandler() {
177 final OptionHandler options = new OptionHandler(getModuleName());
178 final ConstraintManager optionConstraints = new ConstraintManager(options);
179 final SmartOrganicLayouter defaults = new SmartOrganicLayouter();
181
182 options.useSection(SECTION_VISUAL);
184
185 options.addEnum(ITEM_SCOPE, new String[]{
187 VALUE_SCOPE_ALL,
188 VALUE_SCOPE_MAINLY_SUBSET,
189 VALUE_SCOPE_SUBSET
190 }, defaults.getScope());
191 options.addInt(ITEM_PREFERRED_EDGE_LENGTH, (int)defaults.getPreferredEdgeLength(), 5, 500);
192 final OptionItem itemConsiderNodeLabels =
193 options.addBool(ITEM_CONSIDER_NODE_LABELS,defaults.isConsiderNodeLabelsEnabled());
194 final OptionItem itemAllowNodeOverlaps = options.addBool(ITEM_ALLOW_NODE_OVERLAPS, defaults.isNodeOverlapsAllowed());
195 final OptionItem itemMinimalNodeDistance =
196 options.addDouble(ITEM_MINIMAL_NODE_DISTANCE, defaults.getMinimalNodeDistance(), 0, 100, 0);
197 options.addBool(ITEM_AVOID_NODE_EDGE_OVERLAPS, false);
198 options.addDouble(ITEM_COMPACTNESS, defaults.getCompactness(),0,1);
199 final OptionItem itemUseAutoClustering =
200 options.addBool(ITEM_USE_AUTO_CLUSTERING, defaults.isAutoClusteringEnabled());
201 final OptionItem itemAutoClusteringQuality =
202 options.addDouble(ITEM_AUTO_CLUSTERING_QUALITY, defaults.getAutoClusteringQuality(), 0, 1);
203 Condition condition =
205 optionConstraints.createConditionValueEquals(itemAllowNodeOverlaps, Boolean.FALSE).or(
206 optionConstraints.createConditionValueEquals(itemConsiderNodeLabels, Boolean.TRUE));
207 optionConstraints.setEnabledOnCondition(condition, itemMinimalNodeDistance);
208 optionConstraints.setEnabledOnValueEquals(itemConsiderNodeLabels, Boolean.FALSE, itemAllowNodeOverlaps);
209 optionConstraints.setEnabledOnValueEquals(itemUseAutoClustering, Boolean.TRUE, itemAutoClusteringQuality);
210
211 options.useSection(SECTION_RESTRICTIONS);
213 final Object ctrId = new Object();
215 final EnumOptionItem itemRestrictOutput = options.addEnum(ITEM_RESTRICT_OUTPUT, new String[]{
216 VALUE_NONE,
217 VALUE_OUTPUT_CAGE,
218 VALUE_OUTPUT_CIRCULAR_CAGE,
219 VALUE_OUTPUT_AR,
220 VALUE_OUTPUT_ELLIPTICAL_CAGE
221 }, 0);
222 itemRestrictOutput.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId);
223
224 final OptionGroup cageGroup = new OptionGroup();
226 cageGroup.setAttribute(OptionGroup.ATTRIBUTE_TITLE, TITLE_OUTPUT_CAGE);
227 cageGroup.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId);
229 cageGroup.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, VALUE_OUTPUT_CAGE);
230 final OptionItem itemRectCageUseView = cageGroup.addItem(options.addBool(ITEM_RECT_CAGE_USE_VIEW, true));
231 final OptionItem itemCageX = cageGroup.addItem(options.addDouble(ITEM_CAGE_X, 0.0d));
232 final OptionItem itemCageY = cageGroup.addItem(options.addDouble(ITEM_CAGE_Y, 0.0d));
233 final OptionItem itemCageWidth = cageGroup.addItem(options.addDouble(ITEM_CAGE_WIDTH, 1000.0d));
234 itemCageWidth.setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
235 final OptionItem itemCageHeight = cageGroup.addItem(options.addDouble(ITEM_CAGE_HEIGHT, 1000.0d));
236 itemCageHeight.setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
237 optionConstraints.setEnabledOnValueEquals(itemRestrictOutput, VALUE_OUTPUT_CAGE, cageGroup);
239 condition = optionConstraints.createConditionValueEquals(itemRestrictOutput, VALUE_OUTPUT_CAGE).and(
240 optionConstraints.createConditionValueEquals(itemRectCageUseView, Boolean.FALSE));
241 optionConstraints.setEnabledOnCondition(condition, itemCageX);
242 optionConstraints.setEnabledOnCondition(condition, itemCageY);
243 optionConstraints.setEnabledOnCondition(condition, itemCageWidth);
244 optionConstraints.setEnabledOnCondition(condition, itemCageHeight);
245
246 final OptionGroup circularCageGroup = new OptionGroup();
248 circularCageGroup.setAttribute(OptionGroup.ATTRIBUTE_TITLE, TITLE_OUTPUT_CIRCULAR_CAGE);
249 circularCageGroup.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId);
251 circularCageGroup.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, VALUE_OUTPUT_CIRCULAR_CAGE);
252 final OptionItem itemCircCageUseView = circularCageGroup.addItem(options.addBool(ITEM_CIRC_CAGE_USE_VIEW, true));
253 final OptionItem itemCageCenterX = circularCageGroup.addItem(options.addDouble(ITEM_CAGE_CENTER_X, 0.0d));
254 final OptionItem itemCageCenterY = circularCageGroup.addItem(options.addDouble(ITEM_CAGE_CENTER_Y, 0.0d));
255 final OptionItem itemCageRadius = circularCageGroup.addItem(options.addDouble(ITEM_CAGE_RADIUS, 1000.0d));
256 itemCageRadius.setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
257 optionConstraints.setEnabledOnValueEquals(itemRestrictOutput, VALUE_OUTPUT_CIRCULAR_CAGE, circularCageGroup);
259 condition = optionConstraints.createConditionValueEquals(itemRestrictOutput, VALUE_OUTPUT_CIRCULAR_CAGE).and(
260 optionConstraints.createConditionValueEquals(itemCircCageUseView, Boolean.FALSE));
261 optionConstraints.setEnabledOnCondition(condition, itemCageCenterX);
262 optionConstraints.setEnabledOnCondition(condition, itemCageCenterY);
263 optionConstraints.setEnabledOnCondition(condition, itemCageRadius);
264
265 final OptionGroup arGroup = new OptionGroup();
267 arGroup.setAttribute(OptionGroup.ATTRIBUTE_TITLE, TITLE_OUTPUT_AR);
268 arGroup.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId);
270 arGroup.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, VALUE_OUTPUT_AR);
271 final OptionItem itemArCageUseView = arGroup.addItem(options.addBool(ITEM_AR_CAGE_USE_VIEW, true));
272 optionConstraints.setEnabledOnValueEquals(itemRestrictOutput, VALUE_OUTPUT_AR, arGroup);
273 condition = optionConstraints.createConditionValueEquals(itemRestrictOutput, VALUE_OUTPUT_AR).and(
274 optionConstraints.createConditionValueEquals(itemArCageUseView, Boolean.FALSE));
275 optionConstraints.setEnabledOnCondition(condition, arGroup.addItem(options.addDouble(ITEM_CAGE_RATIO, 1.0d)));
276
277 final OptionGroup ellipticalCageGroup = new OptionGroup();
279 ellipticalCageGroup.setAttribute(OptionGroup.ATTRIBUTE_TITLE, TITLE_OUTPUT_ELLIPTICAL_CAGE);
280 ellipticalCageGroup.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID, ctrId);
282 ellipticalCageGroup.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, VALUE_OUTPUT_ELLIPTICAL_CAGE);
283 final OptionItem itemEllCageUseView = ellipticalCageGroup.addItem(options.addBool(ITEM_ELL_CAGE_USE_VIEW, true));
284 final OptionItem itemEllipticalCageX = ellipticalCageGroup.addItem(options.addDouble(ITEM_ELLIPTICAL_CAGE_X, 0.0d));
285 final OptionItem itemEllipticalCageY = ellipticalCageGroup.addItem(options.addDouble(ITEM_ELLIPTICAL_CAGE_Y, 0.0d));
286 final OptionItem itemEllipticalCageWidth = ellipticalCageGroup.addItem(
287 options.addDouble(ITEM_ELLIPTICAL_CAGE_WIDTH, 1000.0d));
288 itemEllipticalCageWidth.setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
289 final OptionItem itemEllipticalCageHeight = ellipticalCageGroup.addItem(
290 options.addDouble(ITEM_ELLIPTICAL_CAGE_HEIGHT, 1000.0d));
291 itemEllipticalCageHeight.setAttribute(DoubleOptionItem.ATTRIBUTE_MIN_VALUE, new Double(Double.MIN_VALUE));
292 optionConstraints.setEnabledOnValueEquals(itemRestrictOutput, VALUE_OUTPUT_ELLIPTICAL_CAGE, ellipticalCageGroup);
294 condition = optionConstraints.createConditionValueEquals(itemRestrictOutput, VALUE_OUTPUT_ELLIPTICAL_CAGE).and(
295 optionConstraints.createConditionValueEquals(itemEllCageUseView, Boolean.FALSE));
296 optionConstraints.setEnabledOnCondition(condition, itemEllipticalCageX);
297 optionConstraints.setEnabledOnCondition(condition, itemEllipticalCageY);
298 optionConstraints.setEnabledOnCondition(condition, itemEllipticalCageWidth);
299 optionConstraints.setEnabledOnCondition(condition, itemEllipticalCageHeight);
300
301 options.useSection(SECTION_GROUPING);
303 options.addEnum(ITEM_GROUP_LAYOUT_POLICY, new String[]{
305 VALUE_LAYOUT_GROUPS,
306 VALUE_FIX_GROUP_CONTENTS,
307 VALUE_FIX_GROUP_BOUNDS,
308 VALUE_IGNORE_GROUPS
309 }, 0);
310 final OptionItem itemUseAutomaticGroupNodeCompaction =
311 options.addBool(ITEM_USE_AUTOMATIC_GROUP_NODE_COMPACTION, defaults.isAutomaticGroupNodeCompactionEnabled());
312 final OptionItem itemGroupCompactness =
313 options.addDouble(ITEM_GROUP_COMPACTNESS, defaults.getGroupNodeCompactness(), 0, 1);
314 optionConstraints.setEnabledOnValueEquals(itemUseAutomaticGroupNodeCompaction, Boolean.FALSE, itemGroupCompactness);
316
317 options.useSection(SECTION_ALGORITHM);
319 final OptionItem itemQualityTimeRatio =
321 options.addDouble(ITEM_QUALITY_TIME_RATIO, defaults.getQualityTimeRatio(), 0, 1);
322 itemQualityTimeRatio.setAttribute(DefaultEditorFactory.ATTRIBUTE_MIN_VALUE_LABEL_TEXT, "SPEED");
323 itemQualityTimeRatio.setAttribute(DefaultEditorFactory.ATTRIBUTE_MAX_VALUE_LABEL_TEXT, "QUALITY");
324 options.addInt(ITEM_MAXIMAL_DURATION, (int)(defaults.getMaximumDuration()/1000))
325 .setAttribute(IntOptionItem.ATTRIBUTE_MIN_VALUE, new Integer(0));
326 options.addBool(ITEM_ACTIVATE_DETERMINISTIC_MODE, defaults.isDeterministic());
327 options.addBool(ITEM_ALLOW_MULTI_THREADING, true);
328
329 options.useSection(SECTION_SUBSTRUCTURE_LAYOUT);
331 options.addEnum(ITEM_CYCLE, new String[]{
332 VALUE_CYCLE_NONE,
333 VALUE_CYCLE_CIRCULAR
334 }, 1);
335 options.addEnum(ITEM_CHAIN, new String[]{
336 VALUE_CHAIN_NONE,
337 VALUE_CHAIN_RECTANGULAR,
338 VALUE_CHAIN_STRAIGHT_LINE
339 }, 0);
340 options.addEnum(ITEM_STAR, new String[]{
341 VALUE_STAR_NONE,
342 VALUE_STAR_SEPARATED_RADIAL,
343 VALUE_STAR_RADIAL,
344 VALUE_CYCLE_CIRCULAR
345 }, 2);
346 options.addEnum(ITEM_PARALLEL, new String[]{
347 VALUE_PARALLEL_NONE,
348 VALUE_PARALLEL_STRAIGHT_LINE,
349 VALUE_PARALLEL_RECTANGULAR,
350 VALUE_PARALLEL_RADIAL
351 }, 3);
352 options.addBool(ITEM_CONSIDER_EDGE_DIRECTION, false);
353 options.addBool(ITEM_USE_EDGE_GROUPING, true);
354
355 return options;
356 }
357
358
362 protected void mainrun() {
363 final SmartOrganicLayouter organic = new SmartOrganicLayouter();
364
365 final OptionHandler options = getOptionHandler();
366 configure(organic, options);
367
368 final Graph2D graph = getGraph2D();
369
370 final Graph2DLayoutExecutor layoutExecutor = getLayoutExecutor();
371 final boolean wasConfiguringGrouping = layoutExecutor.isConfiguringGrouping();
372 layoutExecutor.setConfiguringGrouping(isGroupingNodes(graph, options.getString(ITEM_GROUP_LAYOUT_POLICY)));
373
374 prepareGraph(graph, options);
375 try {
376 launchLayouter(organic);
377 } finally {
378 restoreGraph(graph, options);
379 layoutExecutor.setConfiguringGrouping(wasConfiguringGrouping);
380 }
381 }
382
383
393 protected void prepareGraph(final Graph2D graph, final OptionHandler options) {
394 isNodeDPAddedByModule = false;
395 final String policy = options.getString(ITEM_GROUP_LAYOUT_POLICY);
396 final boolean grouping = isGroupingNodes(graph, policy);
397 if (VALUE_FIX_GROUP_BOUNDS.equals(policy) && grouping) {
398 final NodeMap nodeMap = Maps.createHashedNodeMap();
399 for (NodeCursor nodeCursor = graph.nodes(); nodeCursor.ok(); nodeCursor.next()) {
400 final Node node = nodeCursor.node();
401 if (HierarchyManager.getInstance(graph).isGroupNode(node)) {
402 nodeMap.set(node, SmartOrganicLayouter.GROUP_NODE_MODE_FIX_BOUNDS);
403 }
404 }
405 backupDataProvider(graph, SmartOrganicLayouter.GROUP_NODE_MODE_DATA);
407 graph.addDataProvider(SmartOrganicLayouter.GROUP_NODE_MODE_DATA, nodeMap);
408 isNodeDPAddedByModule = true;
409 } else if (VALUE_FIX_GROUP_CONTENTS.equals(policy) && grouping) {
410 final NodeMap nodeMap = Maps.createHashedNodeMap();
411 for (NodeCursor nodeCursor = graph.nodes(); nodeCursor.ok(); nodeCursor.next()) {
412 final Node node = nodeCursor.node();
413 if (HierarchyManager.getInstance(graph).isGroupNode(node)) {
414 nodeMap.set(node, SmartOrganicLayouter.GROUP_NODE_MODE_FIX_CONTENTS);
415 }
416 }
417 backupDataProvider(graph, SmartOrganicLayouter.GROUP_NODE_MODE_DATA);
419 graph.addDataProvider(SmartOrganicLayouter.GROUP_NODE_MODE_DATA, nodeMap);
420 isNodeDPAddedByModule = true;
421 }
422 backupDataProvider(graph, SmartOrganicLayouter.NODE_SUBSET_DATA);
424 graph.addDataProvider(SmartOrganicLayouter.NODE_SUBSET_DATA, Selections.createSelectionNodeMap(graph));
425
426 if (options.getBool(ITEM_CONSIDER_EDGE_DIRECTION)) {
427 backupDataProvider(graph, SmartOrganicLayouter.EDGE_DIRECTEDNESS_DPKEY);
429 graph.addDataProvider(
430 SmartOrganicLayouter.EDGE_DIRECTEDNESS_DPKEY, new EdgeDirectednessProvider(graph));
431 }
432 if (options.getBool(ITEM_USE_EDGE_GROUPING)) {
433 backupDataProvider(graph, PortConstraintKeys.SOURCE_GROUPID_KEY);
435 backupDataProvider(graph, PortConstraintKeys.TARGET_GROUPID_KEY);
436 final DataProvider edgeGroupIdDP = DataProviders.createConstantDataProvider("Group");
437 graph.addDataProvider(PortConstraintKeys.SOURCE_GROUPID_KEY, edgeGroupIdDP);
438 graph.addDataProvider(PortConstraintKeys.TARGET_GROUPID_KEY, edgeGroupIdDP);
439 }
440 }
441
442
448 protected void restoreGraph(final Graph2D graph, final OptionHandler options) {
449 restoreDataProvider(graph, SmartOrganicLayouter.NODE_SUBSET_DATA);
451
452 if (isNodeDPAddedByModule) {
453 isNodeDPAddedByModule = false;
454 restoreDataProvider(graph, SmartOrganicLayouter.GROUP_NODE_MODE_DATA);
455 }
456 if (options.getBool(ITEM_CONSIDER_EDGE_DIRECTION)) {
457 restoreDataProvider(graph, SmartOrganicLayouter.EDGE_DIRECTEDNESS_DPKEY);
459 }
460 if (options.getBool(ITEM_USE_EDGE_GROUPING)) {
461 restoreDataProvider(graph, PortConstraintKeys.SOURCE_GROUPID_KEY);
463 restoreDataProvider(graph, PortConstraintKeys.TARGET_GROUPID_KEY);
464 }
465 }
466
467
472 protected void configure(final SmartOrganicLayouter organic, final OptionHandler options) {
473 organic.setPreferredEdgeLength(options.getInt(SECTION_VISUAL, ITEM_PREFERRED_EDGE_LENGTH));
474
475 boolean considerNodeLabels = options.getBool(SECTION_VISUAL, ITEM_CONSIDER_NODE_LABELS);
476 organic.setConsiderNodeLabelsEnabled(considerNodeLabels);
477 organic.setNodeOverlapsAllowed(options.getBool(SECTION_VISUAL, ITEM_ALLOW_NODE_OVERLAPS) && !considerNodeLabels);
478
479 organic.setMinimalNodeDistance(options.getDouble(SECTION_VISUAL, ITEM_MINIMAL_NODE_DISTANCE));
480
481 final String is = options.getString(SECTION_VISUAL, ITEM_SCOPE);
482 if (VALUE_SCOPE_SUBSET.equals(is)) {
483 organic.setScope(SmartOrganicLayouter.SCOPE_SUBSET);
484 } else if (VALUE_SCOPE_MAINLY_SUBSET.equals(is)) {
485 organic.setScope(SmartOrganicLayouter.SCOPE_MAINLY_SUBSET);
486 } else {
487 organic.setScope(SmartOrganicLayouter.SCOPE_ALL);
489 }
490
491 organic.setCompactness(options.getDouble(SECTION_VISUAL, ITEM_COMPACTNESS));
492 organic.setAutomaticGroupNodeCompactionEnabled(options.getBool(ITEM_USE_AUTOMATIC_GROUP_NODE_COMPACTION));
493 organic.setGroupNodeCompactness(options.getDouble(ITEM_GROUP_COMPACTNESS));
494 organic.setNodeSizeAware(true);
497 organic.setAutoClusteringEnabled(options.getBool(ITEM_USE_AUTO_CLUSTERING));
498 organic.setAutoClusteringQuality(options.getDouble(ITEM_AUTO_CLUSTERING_QUALITY));
499 organic.setNodeEdgeOverlapAvoided(options.getBool(ITEM_AVOID_NODE_EDGE_OVERLAPS));
500 organic.setDeterministic(options.getBool(SECTION_ALGORITHM, ITEM_ACTIVATE_DETERMINISTIC_MODE));
501 organic.setMultiThreadingAllowed(options.getBool(SECTION_ALGORITHM, ITEM_ALLOW_MULTI_THREADING));
502 organic.setMaximumDuration(1000L * options.getInt(SECTION_ALGORITHM, ITEM_MAXIMAL_DURATION));
503 organic.setQualityTimeRatio(options.getDouble(SECTION_ALGORITHM, ITEM_QUALITY_TIME_RATIO));
504
505 final String itemCycle = options.getString(SECTION_SUBSTRUCTURE_LAYOUT, ITEM_CYCLE);
506 if (VALUE_CYCLE_CIRCULAR.equals(itemCycle)) {
507 organic.setCycleSubstructureStyle(SmartOrganicLayouter.CYCLE_SUBSTRUCTURE_STYLE_CIRCULAR);
508 } else {
509 organic.setCycleSubstructureStyle(SmartOrganicLayouter.CYCLE_SUBSTRUCTURE_STYLE_NONE);
510 }
511 final String itemChain = options.getString(SECTION_SUBSTRUCTURE_LAYOUT, ITEM_CHAIN);
512 if (VALUE_CHAIN_STRAIGHT_LINE.equals(itemChain)) {
513 organic.setChainSubstructureStyle(SmartOrganicLayouter.CHAIN_SUBSTRUCTURE_STYLE_STRAIGHT_LINE);
514 } else if (VALUE_CHAIN_RECTANGULAR.equals(itemChain)) {
515 organic.setChainSubstructureStyle(SmartOrganicLayouter.CHAIN_SUBSTRUCTURE_STYLE_RECTANGULAR);
516 } else {
517 organic.setChainSubstructureStyle(SmartOrganicLayouter.CHAIN_SUBSTRUCTURE_STYLE_NONE);
518 }
519 final String itemParallel = options.getString(SECTION_SUBSTRUCTURE_LAYOUT, ITEM_PARALLEL);
520 if (VALUE_PARALLEL_STRAIGHT_LINE.equals(itemParallel)) {
521 organic.setParallelSubstructureStyle(SmartOrganicLayouter.PARALLEL_SUBSTRUCTURE_STYLE_STRAIGHT_LINE);
522 } else if (VALUE_PARALLEL_RECTANGULAR.equals(itemParallel)) {
523 organic.setParallelSubstructureStyle(SmartOrganicLayouter.PARALLEL_SUBSTRUCTURE_STYLE_RECTANGULAR);
524 } else if (VALUE_PARALLEL_RADIAL.equals(itemParallel)) {
525 organic.setParallelSubstructureStyle(SmartOrganicLayouter.PARALLEL_SUBSTRUCTURE_STYLE_RADIAL);
526 } else {
527 organic.setParallelSubstructureStyle(SmartOrganicLayouter.PARALLEL_SUBSTRUCTURE_STYLE_NONE);
528 }
529 final String itemStar = options.getString(SECTION_SUBSTRUCTURE_LAYOUT, ITEM_STAR);
530 if (VALUE_STAR_SEPARATED_RADIAL.equals(itemStar)) {
531 organic.setStarSubstructureStyle(SmartOrganicLayouter.STAR_SUBSTRUCTURE_STYLE_SEPARATED_RADIAL);
532 } else if (VALUE_STAR_RADIAL.equals(itemStar)) {
533 organic.setStarSubstructureStyle(SmartOrganicLayouter.STAR_SUBSTRUCTURE_STYLE_RADIAL);
534 } else if (VALUE_STAR_CIRCULAR.equals(itemStar)) {
535 organic.setStarSubstructureStyle(SmartOrganicLayouter.STAR_SUBSTRUCTURE_STYLE_CIRCULAR);
536 } else {
537 organic.setStarSubstructureStyle(SmartOrganicLayouter.STAR_SUBSTRUCTURE_STYLE_NONE);
538 }
539
540 ((ComponentLayouter) organic.getComponentLayouter()).setStyle(ComponentLayouter.STYLE_MULTI_ROWS);
541
542 final String restrictOutput = options.getString(ITEM_RESTRICT_OUTPUT);
543 if (VALUE_NONE.equals(restrictOutput)) {
544 organic.setComponentLayouterEnabled(true);
545 organic.setOutputRestriction(OutputRestriction.NONE);
546 } else if (VALUE_OUTPUT_CAGE.equals(restrictOutput)) {
547 final double x;
548 final double y;
549 final double w;
550 final double h;
551 if (options.getBool(ITEM_RECT_CAGE_USE_VIEW) && getGraph2DView() != null) {
552 Rectangle visibleRect = getGraph2DView().getVisibleRect();
553 x = visibleRect.x;
554 y = visibleRect.y;
555 w = visibleRect.width;
556 h = visibleRect.height;
557 } else {
558 x = options.getDouble(ITEM_CAGE_X);
559 y = options.getDouble(ITEM_CAGE_Y);
560 w = options.getDouble(ITEM_CAGE_WIDTH);
561 h = options.getDouble(ITEM_CAGE_HEIGHT);
562 }
563
564 organic.setOutputRestriction(
565 OutputRestriction.createRectangularCageRestriction(x, y, w, h));
566 organic.setComponentLayouterEnabled(false);
567 } else if (VALUE_OUTPUT_CIRCULAR_CAGE.equals(restrictOutput)) {
568 final double x;
569 final double y;
570 final double radius;
571 if (options.getBool(ITEM_CIRC_CAGE_USE_VIEW) && getGraph2DView() != null) {
572 Rectangle visibleRect = getGraph2DView().getVisibleRect();
573 x = visibleRect.getCenterX();
574 y = visibleRect.getCenterY();
575 radius = Math.min(visibleRect.width, visibleRect.height) * 0.5d;
576 } else {
577 x = options.getDouble(ITEM_CAGE_CENTER_X);
578 y = options.getDouble(ITEM_CAGE_CENTER_Y);
579 radius = options.getDouble(ITEM_CAGE_RADIUS);
580 }
581
582 organic.setOutputRestriction(OutputRestriction.createCircularCageRestriction(x, y, radius));
583 organic.setComponentLayouterEnabled(false);
584 } else if (VALUE_OUTPUT_AR.equals(restrictOutput)) {
585 final double ratio;
586 if (options.getBool(ITEM_AR_CAGE_USE_VIEW) && getGraph2DView() != null) {
587 Rectangle visibleRect = getGraph2DView().getVisibleRect();
588 ratio = visibleRect.getWidth()/visibleRect.getHeight();
589 } else {
590 ratio = options.getDouble(ITEM_CAGE_RATIO);
591 }
592
593 organic.setOutputRestriction(OutputRestriction.createAspectRatioRestriction(ratio));
594 organic.setComponentLayouterEnabled(true);
595 ((ComponentLayouter) organic.getComponentLayouter()).setPreferredLayoutSize(ratio * 100, 100);
596 } else if (VALUE_OUTPUT_ELLIPTICAL_CAGE.equals(restrictOutput)) {
597 final double x;
598 final double y;
599 final double w;
600 final double h;
601 if (options.getBool(ITEM_ELL_CAGE_USE_VIEW) && getGraph2DView() != null) {
602 Rectangle visibleRect = getGraph2DView().getVisibleRect();
603 x = visibleRect.x;
604 y = visibleRect.y;
605 w = visibleRect.width;
606 h = visibleRect.height;
607 } else {
608 x = options.getDouble(ITEM_ELLIPTICAL_CAGE_X);
609 y = options.getDouble(ITEM_ELLIPTICAL_CAGE_Y);
610 w = options.getDouble(ITEM_ELLIPTICAL_CAGE_WIDTH);
611 h = options.getDouble(ITEM_ELLIPTICAL_CAGE_HEIGHT);
612 }
613
614 organic.setOutputRestriction(OutputRestriction.createEllipticalCageRestriction(x, y, w, h));
615 organic.setComponentLayouterEnabled(false);
616 }
617 }
618
619 private boolean isGroupingNodes(Graph2D graph, String policy) {
620 return !VALUE_IGNORE_GROUPS.equals(policy) && HierarchyManager.containsGroupNodes(graph);
621 }
622
623 private static final class EdgeDirectednessProvider extends DataProviderAdapter {
624 final Graph2D graph;
625
626 EdgeDirectednessProvider(final Graph2D graph) {
627 this.graph = graph;
628 }
629
630 public double getDouble(final Object dataHolder) {
631 try {
632 final EdgeRealizer realizer = graph.getRealizer((Edge) dataHolder);
633 if (realizer.getSourceArrow() == Arrow.NONE && realizer.getTargetArrow() != Arrow.NONE) {
634 return 1;
636 } else if (realizer.getTargetArrow() == Arrow.NONE && realizer.getSourceArrow() != Arrow.NONE) {
637 return -1;
639 } else {
640 return 0;
642 }
643 } catch (Exception e) {
644 return 1;
646 }
647 }
648 }
649 }
650