1
28 package demo.layout.module;
29
30 import y.module.LayoutModule;
31 import y.module.YModule;
32
33 import y.layout.ComponentLayouter;
34 import y.layout.circular.CircularLayouter;
35 import y.layout.EdgeBundling;
36 import y.layout.EdgeBundleDescriptor;
37 import y.layout.circular.SingleCycleLayouter;
38 import y.layout.tree.BalloonLayouter;
39 import y.option.OptionHandler;
40 import y.option.ConstraintManager;
41 import y.option.EnumOptionItem;
42 import y.option.OptionItem;
43 import y.view.Graph2D;
44
45
52 public class CircularLayoutModule extends LayoutModule {
53 protected static final String MODULE_CIRCULAR = "CIRCULAR";
55
56 protected static final String SECTION_GENERAL = "GENERAL";
58 protected static final String ITEM_LAYOUT_STYLE = "LAYOUT_STYLE";
60 protected static final String VALUE_BCC_COMPACT = "BCC_COMPACT";
61 protected static final String VALUE_BCC_ISOLATED = "BCC_ISOLATED";
62 protected static final String VALUE_CIRCULAR_CUSTOM_GROUPS = "CIRCULAR_CUSTOM_GROUPS";
63 protected static final String VALUE_SINGLE_CYCLE = "SINGLE_CYCLE";
64 protected static final String ITEM_ACT_ON_SELECTION_ONLY = "ACT_ON_SELECTION_ONLY";
65 protected static final String ITEM_FROM_SKETCH = "FROM_SKETCH";
66 protected static final String ITEM_HANDLE_NODE_LABELS = "HANDLE_NODE_LABELS";
67
68 protected static final String SECTION_CYCLE = "CYCLE";
70 private static final String ITEM_PARTITION_LAYOUT_STYLE = "PARTITION_LAYOUT_STYLE";
72 private static final String VALUE_PARTITION_LAYOUTSTYLE_CYCLIC = "PARTITION_LAYOUTSTYLE_CYCLIC";
73 private static final String VALUE_PARTITION_LAYOUTSTYLE_DISK = "PARTITION_LAYOUTSTYLE_DISK";
74 private static final String VALUE_PARTITION_LAYOUTSTYLE_ORGANIC = "PARTITION_LAYOUTSTYLE_ORGANIC";
75 protected static final String ITEM_MINIMAL_NODE_DISTANCE = "MINIMAL_NODE_DISTANCE";
76 protected static final String ITEM_CHOOSE_RADIUS_AUTOMATICALLY = "CHOOSE_RADIUS_AUTOMATICALLY";
77 protected static final String ITEM_FIXED_RADIUS = "FIXED_RADIUS";
78
79 protected static final String SECTION_BUNDLING = "EDGE_BUNDLING";
81 protected static final String EDGE_BUNDLING_ENABLED = "EDGE_BUNDLING_ENABLED";
82 protected static final String EDGE_BUNDLING_STRENGTH = "EDGE_BUNDLING_STRENGTH";
83
84 protected static final String SECTION_TREE = "TREE";
86 protected static final String ITEM_PREFERRED_CHILD_WEDGE = "PREFERRED_CHILD_WEDGE";
88 protected static final String ITEM_MINIMAL_EDGE_LENGTH = "MINIMAL_EDGE_LENGTH";
89 protected static final String ITEM_MAXIMAL_DEVIATION_ANGLE = "MAXIMAL_DEVIATION_ANGLE";
90 protected static final String ITEM_COMPACTNESS_FACTOR = "COMPACTNESS_FACTOR";
91 protected static final String ITEM_MINIMAL_TREE_NODE_DISTANCE = "MINIMAL_TREE_NODE_DISTANCE";
92 protected static final String ITEM_ALLOW_OVERLAPS = "ALLOW_OVERLAPS";
93 protected static final String ITEM_PLACE_CHILDREN_ON_COMMON_RADIUS = "PLACE_CHILDREN_ON_COMMON_RADIUS";
94
95
98 public CircularLayoutModule() {
99 super(MODULE_CIRCULAR);
100 }
101
102
106 protected OptionHandler createOptionHandler() {
107 final OptionHandler options = new OptionHandler(getModuleName());
108 final ConstraintManager optionConstraints = new ConstraintManager(options);
109 final CircularLayouter defaults = new CircularLayouter();
111 final SingleCycleLayouter defaultsSC = defaults.getSingleCycleLayouter();
112 final BalloonLayouter defaultsB = defaults.getBalloonLayouter();
113
114 options.useSection(SECTION_GENERAL);
116 final EnumOptionItem itemGlobalLayoutStyle = options.addEnum(ITEM_LAYOUT_STYLE, new String[]{
118 VALUE_BCC_COMPACT,
119 VALUE_BCC_ISOLATED,
120 VALUE_CIRCULAR_CUSTOM_GROUPS,
121 VALUE_SINGLE_CYCLE
122 }, defaults.getLayoutStyle());
123 options.addBool(ITEM_ACT_ON_SELECTION_ONLY, false);
124 options.addBool(ITEM_FROM_SKETCH, false);
125 options.addBool(ITEM_HANDLE_NODE_LABELS, false);
126
127 options.useSection(SECTION_CYCLE);
129 final EnumOptionItem itemLayoutStyle = options.addEnum(ITEM_PARTITION_LAYOUT_STYLE, new String[]{
131 VALUE_PARTITION_LAYOUTSTYLE_CYCLIC,
132 VALUE_PARTITION_LAYOUTSTYLE_DISK,
133 VALUE_PARTITION_LAYOUTSTYLE_ORGANIC
134 }, defaults.getPartitionLayoutStyle());
135 final OptionItem itemChooseRadiusAutomatically =
136 options.addBool(ITEM_CHOOSE_RADIUS_AUTOMATICALLY, defaultsSC.getAutomaticRadius());
137 final OptionItem itemFixedRadius = options.addInt(ITEM_FIXED_RADIUS, (int) defaultsSC.getFixedRadius(), 50, 800);
138 final OptionItem itemMinimalNodeDistance =
139 options.addInt(ITEM_MINIMAL_NODE_DISTANCE, (int) defaultsSC.getMinimalNodeDistance(), 0, 999);
140 optionConstraints.setEnabledOnValueEquals(itemChooseRadiusAutomatically, Boolean.FALSE, itemFixedRadius);
142 optionConstraints.setEnabledOnValueEquals(itemChooseRadiusAutomatically, Boolean.TRUE, itemMinimalNodeDistance);
143
144 options.useSection(SECTION_BUNDLING);
146 final OptionItem bundlingEnabled = options.addBool(EDGE_BUNDLING_ENABLED, false);
147 final OptionItem itemBundlingStrength = options.addDouble(EDGE_BUNDLING_STRENGTH, 0.95, 0.0, 1.0);
148
149 final ConstraintManager.Condition bundlingCondition =
151 optionConstraints.createConditionValueEquals(itemLayoutStyle, VALUE_PARTITION_LAYOUTSTYLE_CYCLIC).and((
152 optionConstraints.createConditionValueEquals(itemGlobalLayoutStyle, VALUE_BCC_ISOLATED)).inverse());
153 optionConstraints.setEnabledOnCondition(bundlingCondition, bundlingEnabled);
154 final ConstraintManager.Condition bundlingSettingsCondition =
155 optionConstraints.createConditionValueEquals(bundlingEnabled, Boolean.TRUE).and(bundlingCondition);
156 optionConstraints.setEnabledOnCondition(bundlingSettingsCondition, itemBundlingStrength);
157
158 options.useSection(SECTION_TREE);
160 final OptionItem itemPreferredChildWedge =
162 options.addInt(ITEM_PREFERRED_CHILD_WEDGE, defaultsB.getPreferredChildWedge(), 1, 359);
163 final OptionItem itemMinimalEdgeLength =
164 options.addInt(ITEM_MINIMAL_EDGE_LENGTH, defaultsB.getMinimalEdgeLength(), 5, 400);
165 final OptionItem itemMaximalDeviationAngle =
166 options.addInt(ITEM_MAXIMAL_DEVIATION_ANGLE, defaults.getMaximalDeviationAngle(), 10, 360);
167 final OptionItem itemCompactnessFactor =
168 options.addDouble(ITEM_COMPACTNESS_FACTOR, defaultsB.getCompactnessFactor(), 0.1, 0.9);
169 final OptionItem itemMinimalTreeNodeDistance =
170 options.addInt(ITEM_MINIMAL_TREE_NODE_DISTANCE, defaultsB.getMinimalNodeDistance(), 0, 100);
171 final OptionItem itemAllowOverlaps = options.addBool(ITEM_ALLOW_OVERLAPS, defaultsB.getAllowOverlaps());
172 final OptionItem itemPlaceChildrenCommonRadius = options.addBool(ITEM_PLACE_CHILDREN_ON_COMMON_RADIUS, true);
173 optionConstraints.setEnabledOnValueEquals(itemLayoutStyle, VALUE_SINGLE_CYCLE, itemMinimalTreeNodeDistance, true);
175 optionConstraints.setEnabledOnValueEquals(itemLayoutStyle, VALUE_SINGLE_CYCLE, itemPlaceChildrenCommonRadius, true);
176 optionConstraints.setEnabledOnValueEquals(itemLayoutStyle, VALUE_SINGLE_CYCLE, itemPreferredChildWedge, true);
177 optionConstraints.setEnabledOnValueEquals(itemLayoutStyle, VALUE_SINGLE_CYCLE, itemMinimalEdgeLength, true);
178 optionConstraints.setEnabledOnValueEquals(itemLayoutStyle, VALUE_SINGLE_CYCLE, itemMaximalDeviationAngle, true);
179 optionConstraints.setEnabledOnValueEquals(itemLayoutStyle, VALUE_SINGLE_CYCLE, itemCompactnessFactor, true);
180 optionConstraints.setEnabledOnValueEquals(itemLayoutStyle, VALUE_SINGLE_CYCLE, itemAllowOverlaps, true);
181
182 return options;
183 }
184
185
186
190 protected void mainrun() {
191 final CircularLayouter circular = new CircularLayouter();
192
193 final OptionHandler options = getOptionHandler();
194 configure(circular, options);
195
196 final Graph2D graph = getGraph2D();
197 prepareGraph(graph, options);
198 try {
199 launchLayouter(circular);
200 } finally {
201 restoreGraph(graph, options);
202 }
203 }
204
205
215 protected void prepareGraph(final Graph2D graph, final OptionHandler options) {
216 if (options.getString(ITEM_LAYOUT_STYLE).equals(VALUE_CIRCULAR_CUSTOM_GROUPS)) {
217 if (graph.getHierarchyManager() != null) {
220 backupDataProvider(graph, CircularLayouter.CIRCULAR_CUSTOM_GROUPS_DPKEY);
222 graph.addDataProvider(CircularLayouter.CIRCULAR_CUSTOM_GROUPS_DPKEY,
223 graph.getHierarchyManager().getParentNodeIdDataProvider());
224 }
225 }
226 }
227
228
234 protected void restoreGraph(final Graph2D graph, final OptionHandler options) {
235 if (options.getString(ITEM_LAYOUT_STYLE).equals(VALUE_CIRCULAR_CUSTOM_GROUPS) &&
237 graph.getHierarchyManager() != null) {
238 restoreDataProvider(graph, CircularLayouter.CIRCULAR_CUSTOM_GROUPS_DPKEY);
239 }
240 }
241
242
247 protected void configure(final CircularLayouter circular, final OptionHandler options) {
248 ((ComponentLayouter) circular.getComponentLayouter()).setStyle(ComponentLayouter.STYLE_MULTI_ROWS);
249
250 if (options.getString(ITEM_LAYOUT_STYLE).equals(VALUE_BCC_COMPACT)) {
251 circular.setLayoutStyle(CircularLayouter.BCC_COMPACT);
252 } else if (options.getString(ITEM_LAYOUT_STYLE).equals(VALUE_BCC_ISOLATED)) {
253 circular.setLayoutStyle(CircularLayouter.BCC_ISOLATED);
254 } else if (options.getString(ITEM_LAYOUT_STYLE).equals(VALUE_CIRCULAR_CUSTOM_GROUPS)) {
255 circular.setLayoutStyle(CircularLayouter.CIRCULAR_CUSTOM_GROUPS);
256 } else {
257 circular.setLayoutStyle(CircularLayouter.SINGLE_CYCLE);
258 }
259
260 circular.setSubgraphLayouterEnabled(options.getBool(ITEM_ACT_ON_SELECTION_ONLY));
261 circular.setMaximalDeviationAngle(options.getInt(ITEM_MAXIMAL_DEVIATION_ANGLE));
262 circular.setFromSketchModeEnabled(options.getBool(ITEM_FROM_SKETCH));
263 circular.setPlaceChildrenOnCommonRadiusEnabled(options.getBool(ITEM_PLACE_CHILDREN_ON_COMMON_RADIUS));
264 circular.setConsiderNodeLabelsEnabled(options.getBool(ITEM_HANDLE_NODE_LABELS));
265
266 if (options.getString(ITEM_PARTITION_LAYOUT_STYLE).equals(VALUE_PARTITION_LAYOUTSTYLE_CYCLIC)) {
267 circular.setPartitionLayoutStyle(CircularLayouter.PARTITION_LAYOUTSTYLE_CYCLIC);
268 } else if (options.getString(ITEM_PARTITION_LAYOUT_STYLE).equals(VALUE_PARTITION_LAYOUTSTYLE_DISK)) {
269 circular.setPartitionLayoutStyle(CircularLayouter.PARTITION_LAYOUTSTYLE_DISK);
270 } else if (options.getString(ITEM_PARTITION_LAYOUT_STYLE).equals(VALUE_PARTITION_LAYOUTSTYLE_ORGANIC)) {
271 circular.setPartitionLayoutStyle(CircularLayouter.PARTITION_LAYOUTSTYLE_ORGANIC);
272 }
273
274 final SingleCycleLayouter cl = circular.getSingleCycleLayouter();
275 cl.setMinimalNodeDistance(options.getInt(ITEM_MINIMAL_NODE_DISTANCE));
276 cl.setAutomaticRadius(options.getBool(ITEM_CHOOSE_RADIUS_AUTOMATICALLY));
277 cl.setFixedRadius(options.getInt(ITEM_FIXED_RADIUS));
278
279 final BalloonLayouter bl = circular.getBalloonLayouter();
280 bl.setPreferredChildWedge(options.getInt(ITEM_PREFERRED_CHILD_WEDGE));
281 bl.setMinimalEdgeLength(options.getInt(ITEM_MINIMAL_EDGE_LENGTH));
282 bl.setCompactnessFactor(options.getDouble(ITEM_COMPACTNESS_FACTOR));
283 bl.setAllowOverlaps(options.getBool(ITEM_ALLOW_OVERLAPS));
284 bl.setMinimalNodeDistance(options.getInt(ITEM_MINIMAL_TREE_NODE_DISTANCE));
285
286 final EdgeBundling ebc = circular.getEdgeBundling();
288 final EdgeBundleDescriptor descriptor = new EdgeBundleDescriptor();
289 descriptor.setBundled(options.getBool(EDGE_BUNDLING_ENABLED));
290 ebc.setDefaultBundleDescriptor(descriptor);
291 ebc.setBundlingStrength(options.getDouble(EDGE_BUNDLING_STRENGTH));
292 }
293 }
294