1
28 package demo.layout.module;
29
30 import y.module.LayoutModule;
31 import y.module.YModule;
32
33 import y.base.Edge;
34 import y.layout.Layouter;
35 import y.layout.circular.CircularLayouter;
36 import y.layout.hierarchic.IncrementalHierarchicLayouter;
37 import y.layout.organic.SmartOrganicLayouter;
38 import y.layout.orthogonal.OrthogonalLayouter;
39 import y.layout.partial.PartialLayouter;
40 import y.option.OptionHandler;
41 import y.util.DataProviderAdapter;
42 import y.view.Arrow;
43 import y.view.EdgeRealizer;
44 import y.view.Graph2D;
45 import y.view.Graph2DLayoutExecutor;
46 import y.view.Selections;
47 import y.view.tabular.TableLayoutConfigurator;
48
49
56 public class PartialLayoutModule extends LayoutModule {
57 protected static final String MODULE_PARTIAL = "PARTIAL";
59
60 protected static final String SECTION_GENERAL = "GENERAL";
62 protected static final String ITEM_ROUTING_TO_SUBGRAPH = "ROUTING_TO_SUBGRAPH";
64 protected static final String VALUE_ROUTING_TO_SUBGRAPH_AUTO = "ROUTING_TO_SUBGRAPH_AUTO";
65 protected static final String VALUE_ROUTING_TO_SUBGRAPH_STRAIGHT_LINE = "ROUTING_TO_SUBGRAPH_STRAIGHT_LINE";
66 protected static final String VALUE_ROUTING_TO_SUBGRAPH_POLYLINE = "ROUTING_TO_SUBGRAPH_POLYLINE";
67 protected static final String VALUE_ROUTING_TO_SUBGRAPH_ORTHOGONALLY = "ROUTING_TO_SUBGRAPH_ORTHOGONALLY";
68 protected static final String VALUE_ROUTING_TO_SUBGRAPH_ORGANIC = "ROUTING_TO_SUBGRAPH_ORGANIC";
69 protected static final String ITEM_MODE_COMPONENT_ASSIGNMENT = "MODE_COMPONENT_ASSIGNMENT";
70 protected static final String VALUE_MODE_COMPONENT_CONNECTED = "MODE_COMPONENT_CONNECTED";
71 protected static final String VALUE_MODE_COMPONENT_SINGLE = "MODE_COMPONENT_SINGLE";
72 protected static final String VALUE_MODE_COMPONENT_CLUSTERING = "MODE_COMPONENT_CLUSTERING";
73 protected static final String VALUE_MODE_COMPONENT_CUSTOMIZED = "MODE_COMPONENT_CUSTOMIZED";
74 protected static final String ITEM_SUBGRAPH_LAYOUTER = "SUBGRAPH_LAYOUTER";
75 protected static final String VALUE_SUBGRAPH_LAYOUTER_IHL = "SUBGRAPH_LAYOUTER_IHL";
76 protected static final String VALUE_SUBGRAPH_LAYOUTER_ORGANIC = "SUBGRAPH_LAYOUTER_ORGANIC";
77 protected static final String VALUE_SUBGRAPH_LAYOUTER_CIRCULAR = "SUBGRAPH_LAYOUTER_CIRCULAR";
78 protected static final String VALUE_SUBGRAPH_LAYOUTER_ORTHOGONAL = "SUBGRAPH_LAYOUTER_ORTHOGONAL";
79 protected static final String VALUE_SUBGRAPH_LAYOUTER_NO_LAYOUT = "SUBGRAPH_LAYOUTER_NO_LAYOUT";
80 protected static final String ITEM_SUBGRAPH_POSITION_STRATEGY = "SUBGRAPH_POSITION_STRATEGY";
81 protected static final String VALUE_SUBGRAPH_POSITIONING_STRATEGY_BARYCENTER = "SUBGRAPH_POSITION_STRATEGY_BARYCENTER";
82 protected static final String VALUE_SUBGRAPH_POSITIONING_STRATEGY_FROM_SKETCH = "SUBGRAPH_POSITION_STRATEGY_FROM_SKETCH";
83 protected static final String ITEM_MIN_NODE_DIST = "MIN_NODE_DIST";
84 protected static final String ITEM_ORIENTATION_MAIN_GRAPH = "ORIENTATION_MAIN_GRAPH";
85 protected static final String VALUE_ORIENTATION_MAIN_GRAPH_AUTO_DETECT = "ORIENTATION_MAIN_GRAPH_AUTO_DETECT";
86 protected static final String VALUE_ORIENTATION_MAIN_GRAPH_TOP_TO_DOWN = "ORIENTATION_MAIN_GRAPH_TOP_TO_DOWN";
87 protected static final String VALUE_ORIENTATION_MAIN_GRAPH_DOWN_TO_TOP = "ORIENTATION_MAIN_GRAPH_DOWN_TO_TOP";
88 protected static final String VALUE_ORIENTATION_MAIN_GRAPH_LEFT_TO_RIGHT = "ORIENTATION_MAIN_GRAPH_LEFT_TO_RIGHT";
89 protected static final String VALUE_ORIENTATION_MAIN_GRAPH_RIGHT_TO_LEFT = "ORIENTATION_MAIN_GRAPH_RIGHT_TO_LEFT";
90 protected static final String VALUE_ORIENTATION_MAIN_GRAPH_NONE = "ORIENTATION_MAIN_GRAPH_NONE";
91 protected static final String ITEM_CONSIDER_SNAPLINES = "CONSIDER_SNAPLINES";
92 protected static final String ITEM_CONSIDER_EDGE_DIRECTION = "CONSIDER_EDGE_DIRECTION";
93
94
97 public PartialLayoutModule() {
98 super(MODULE_PARTIAL);
99 }
100
101
105 protected OptionHandler createOptionHandler() {
106 final OptionHandler options = new OptionHandler(getModuleName());
107
108 options.useSection(SECTION_GENERAL);
110 options.addEnum(ITEM_ROUTING_TO_SUBGRAPH, new String[]{
112 VALUE_ROUTING_TO_SUBGRAPH_AUTO,
113 VALUE_ROUTING_TO_SUBGRAPH_STRAIGHT_LINE,
114 VALUE_ROUTING_TO_SUBGRAPH_POLYLINE,
115 VALUE_ROUTING_TO_SUBGRAPH_ORTHOGONALLY,
116 VALUE_ROUTING_TO_SUBGRAPH_ORGANIC
117 }, 0);
118 options.addEnum(ITEM_MODE_COMPONENT_ASSIGNMENT, new String[]{
119 VALUE_MODE_COMPONENT_CONNECTED,
120 VALUE_MODE_COMPONENT_SINGLE,
121 VALUE_MODE_COMPONENT_CLUSTERING,
122 VALUE_MODE_COMPONENT_CUSTOMIZED
123 }, 0);
124 options.addEnum(ITEM_SUBGRAPH_LAYOUTER, new String[]{
125 VALUE_SUBGRAPH_LAYOUTER_IHL,
126 VALUE_SUBGRAPH_LAYOUTER_ORGANIC,
127 VALUE_SUBGRAPH_LAYOUTER_CIRCULAR,
128 VALUE_SUBGRAPH_LAYOUTER_ORTHOGONAL,
129 VALUE_SUBGRAPH_LAYOUTER_NO_LAYOUT
130 }, 0);
131 options.addEnum(ITEM_SUBGRAPH_POSITION_STRATEGY, new String[]{
132 VALUE_SUBGRAPH_POSITIONING_STRATEGY_BARYCENTER,
133 VALUE_SUBGRAPH_POSITIONING_STRATEGY_FROM_SKETCH
134 }, 0);
135 options.addInt(ITEM_MIN_NODE_DIST, 30, 1, 100);
136 options.addEnum(ITEM_ORIENTATION_MAIN_GRAPH, new String[]{
137 VALUE_ORIENTATION_MAIN_GRAPH_AUTO_DETECT,
138 VALUE_ORIENTATION_MAIN_GRAPH_TOP_TO_DOWN,
139 VALUE_ORIENTATION_MAIN_GRAPH_DOWN_TO_TOP,
140 VALUE_ORIENTATION_MAIN_GRAPH_LEFT_TO_RIGHT,
141 VALUE_ORIENTATION_MAIN_GRAPH_RIGHT_TO_LEFT,
142 VALUE_ORIENTATION_MAIN_GRAPH_NONE
143 }, 0);
144 options.addBool(ITEM_CONSIDER_SNAPLINES, true);
145 options.addBool(ITEM_CONSIDER_EDGE_DIRECTION, false);
146
147 return options;
148 }
149
150
154 protected void mainrun() {
155 final Graph2D graph = getGraph2D();
156 if (graph.selectedNodes().size() + graph.selectedEdges().size() == 0) {
157 return; }
159
160 final PartialLayouter partial = new PartialLayouter();
161
162 final OptionHandler options = getOptionHandler();
163 configure(partial, options);
164
165 final Graph2DLayoutExecutor layoutExecutor = getLayoutExecutor();
166 final TableLayoutConfigurator tableLayoutConf = layoutExecutor.getTableLayoutConfigurator();
167 final boolean wasConfTableNodeRealizer = layoutExecutor.isConfiguringTableNodeRealizers();
168 final boolean wasHorizontalLayoutConf = tableLayoutConf.isHorizontalLayoutConfiguration();
169 layoutExecutor.setConfiguringTableNodeRealizers(true);
170 tableLayoutConf.setHorizontalLayoutConfiguration(isHorizontalLayoutConf(options));
171
172 prepareGraph(graph, options);
173 try {
174 launchLayouter(partial);
175 } finally {
176 restoreGraph(graph, options);
177
178 layoutExecutor.setConfiguringTableNodeRealizers(wasConfTableNodeRealizer);
179 tableLayoutConf.setHorizontalLayoutConfiguration(wasHorizontalLayoutConf);
180 }
181 }
182
183
193 protected void prepareGraph(final Graph2D graph, OptionHandler options) {
194 backupDataProvider(graph, PartialLayouter.PARTIAL_NODES_DPKEY);
196 backupDataProvider(graph, PartialLayouter.PARTIAL_EDGES_DPKEY);
197 graph.addDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY, Selections.createSelectionNodeMap(graph));
199 graph.addDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY, Selections.createSelectionEdgeMap(graph));
200
201 if (options.getBool(ITEM_CONSIDER_EDGE_DIRECTION)
202 && graph.getDataProvider(PartialLayouter.DIRECTED_EDGES_DPKEY) == null) {
203 graph.addDataProvider(PartialLayouter.DIRECTED_EDGES_DPKEY, new ModuleDataProvider() {
204 public boolean getBool(Object dataHolder) {
205 if (!(dataHolder instanceof Edge)) {
206 return false;
207 }
208
209 final EdgeRealizer realizer = graph.getRealizer((Edge) dataHolder);
210 return (realizer.getSourceArrow() == Arrow.NONE) == (realizer.getTargetArrow() != Arrow.NONE);
212 }
213 });
214 }
215 }
216
217
223 protected void restoreGraph(final Graph2D graph, final OptionHandler options) {
224 if (graph.getDataProvider(PartialLayouter.DIRECTED_EDGES_DPKEY) instanceof ModuleDataProvider) {
226 graph.removeDataProvider(PartialLayouter.DIRECTED_EDGES_DPKEY);
228 }
229
230 restoreDataProvider(graph, PartialLayouter.PARTIAL_NODES_DPKEY);
231 restoreDataProvider(graph, PartialLayouter.PARTIAL_EDGES_DPKEY);
232 }
233
234
239 protected void configure(final PartialLayouter partial, final OptionHandler options) {
240 partial.setMinimalNodeDistance(options.getInt(ITEM_MIN_NODE_DIST));
241 partial.setConsiderNodeAlignment(options.getBool(ITEM_CONSIDER_SNAPLINES));
242
243 final byte subgraphPositioningStrategy =
244 subgraphPositioningStrategyAsByte(options.getString(ITEM_SUBGRAPH_POSITION_STRATEGY));
245 partial.setPositioningStrategy(subgraphPositioningStrategy);
246
247 final byte componentAssignment = componentAssignmentAsByte(options.getString(ITEM_MODE_COMPONENT_ASSIGNMENT));
248 partial.setComponentAssignmentStrategy(componentAssignment);
249
250 final byte mainGraphOrientation = graphOrientationAsByte(options.getString(ITEM_ORIENTATION_MAIN_GRAPH));
251 partial.setLayoutOrientation(mainGraphOrientation);
252
253 final byte routingToSubGraph = routingToSubGraphAsByte(options.getString(ITEM_ROUTING_TO_SUBGRAPH));
254 partial.setEdgeRoutingStrategy(routingToSubGraph);
255
256 partial.setCoreLayouter(defineSubgraphLayouter(options, routingToSubGraph));
257 }
258
259 private boolean isHorizontalLayoutConf(OptionHandler options) {
260 final byte mainGraphOrientation = graphOrientationAsByte(options.getString(ITEM_ORIENTATION_MAIN_GRAPH));
261 return (mainGraphOrientation == PartialLayouter.ORIENTATION_LEFT_TO_RIGHT)
262 || (mainGraphOrientation == PartialLayouter.ORIENTATION_RIGHT_TO_LEFT);
263 }
264
265
266 private Layouter defineSubgraphLayouter(final OptionHandler options, final byte routingToSubGraph) {
267 final String subgraphLayouterString = options.getString(ITEM_SUBGRAPH_LAYOUTER);
268 if (VALUE_SUBGRAPH_LAYOUTER_IHL.equals(subgraphLayouterString)) {
269 final IncrementalHierarchicLayouter ihl = new IncrementalHierarchicLayouter();
270 ihl.setIntegratedEdgeLabelingEnabled(true);
271 if (PartialLayouter.EDGE_ROUTING_STRATEGY_ORTHOGONAL == routingToSubGraph) {
272 ihl.setOrthogonallyRouted(true);
273 } else {
274 ihl.setOrthogonallyRouted(false);
275 }
276 return ihl;
277 } else if (VALUE_SUBGRAPH_LAYOUTER_ORGANIC.equals(subgraphLayouterString)) {
278 final SmartOrganicLayouter sol = new SmartOrganicLayouter();
279 sol.setDeterministic(true);
280 return sol;
281 } else if (VALUE_SUBGRAPH_LAYOUTER_CIRCULAR.equals(subgraphLayouterString)) {
282 return new CircularLayouter();
283 } else if (VALUE_SUBGRAPH_LAYOUTER_ORTHOGONAL.equals(subgraphLayouterString)) {
284 return new OrthogonalLayouter();
285 } else {
286
290 return null;
292 }
293 }
294
295
296 private static byte routingToSubGraphAsByte(final String routingToSubGraphString) {
297 if (VALUE_ROUTING_TO_SUBGRAPH_ORTHOGONALLY.equals(routingToSubGraphString)) {
298 return PartialLayouter.EDGE_ROUTING_STRATEGY_ORTHOGONAL;
299 } else if (VALUE_ROUTING_TO_SUBGRAPH_AUTO.equals(routingToSubGraphString)) {
300 return PartialLayouter.EDGE_ROUTING_STRATEGY_AUTOMATIC;
301 } else if (VALUE_ROUTING_TO_SUBGRAPH_ORGANIC.equals(routingToSubGraphString)) {
302 return PartialLayouter.EDGE_ROUTING_STRATEGY_ORGANIC;
303 } else if (VALUE_ROUTING_TO_SUBGRAPH_POLYLINE.equals(routingToSubGraphString)) {
304 return PartialLayouter.EDGE_ROUTING_STRATEGY_OCTILINEAR;
305 } else {
306 return PartialLayouter.EDGE_ROUTING_STRATEGY_STRAIGHTLINE;
308 }
309 }
310
311
312 private static byte subgraphPositioningStrategyAsByte(final String subgraphPositioningStrategyString) {
313 if (VALUE_SUBGRAPH_POSITIONING_STRATEGY_FROM_SKETCH.equals(subgraphPositioningStrategyString)) {
314 return PartialLayouter.SUBGRAPH_POSITIONING_STRATEGY_FROM_SKETCH;
315 } else {
316 return PartialLayouter.SUBGRAPH_POSITIONING_STRATEGY_BARYCENTER;
317 }
318 }
319
320
321 private static byte componentAssignmentAsByte(final String componentAssignmentString) {
322 if (VALUE_MODE_COMPONENT_SINGLE.equals(componentAssignmentString)) {
323 return PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_SINGLE;
324 } else if (VALUE_MODE_COMPONENT_CONNECTED.equals(componentAssignmentString)) {
325 return PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_CONNECTED;
326 } else if (VALUE_MODE_COMPONENT_CLUSTERING.equals(componentAssignmentString)) {
327 return PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_CLUSTERING;
328 } else {
329 return PartialLayouter.COMPONENT_ASSIGNMENT_STRATEGY_CUSTOMIZED;
330 }
331 }
332
333
334 private static byte graphOrientationAsByte(final String graphOrientationString) {
335 if (VALUE_ORIENTATION_MAIN_GRAPH_AUTO_DETECT.equals(graphOrientationString)) {
336 return PartialLayouter.ORIENTATION_AUTO_DETECTION;
337 } else if (VALUE_ORIENTATION_MAIN_GRAPH_TOP_TO_DOWN.equals(graphOrientationString)) {
338 return PartialLayouter.ORIENTATION_TOP_TO_BOTTOM;
339 } else if (VALUE_ORIENTATION_MAIN_GRAPH_DOWN_TO_TOP.equals(graphOrientationString)) {
340 return PartialLayouter.ORIENTATION_BOTTOM_TO_TOP;
341 } else if (VALUE_ORIENTATION_MAIN_GRAPH_LEFT_TO_RIGHT.equals(graphOrientationString)) {
342 return PartialLayouter.ORIENTATION_LEFT_TO_RIGHT;
343 } else if (VALUE_ORIENTATION_MAIN_GRAPH_RIGHT_TO_LEFT.equals(graphOrientationString)) {
344 return PartialLayouter.ORIENTATION_RIGHT_TO_LEFT;
345 } else if (VALUE_ORIENTATION_MAIN_GRAPH_NONE.equals(graphOrientationString)) {
346 return PartialLayouter.ORIENTATION_NONE;
347 } else {
348 return PartialLayouter.ORIENTATION_AUTO_DETECTION;
349 }
350 }
351
352 private class ModuleDataProvider extends DataProviderAdapter {
353 }
354 }
355