1
28 package demo.view.flowchart.painters;
29
30 import demo.view.flowchart.layout.FlowchartElements;
31 import demo.view.flowchart.layout.FlowchartLayouter;
32 import y.base.DataMap;
33 import y.base.Edge;
34 import y.base.EdgeCursor;
35 import y.base.EdgeMap;
36 import y.base.Graph;
37 import y.base.Node;
38 import y.base.NodeCursor;
39 import y.base.NodeMap;
40 import y.layout.IntersectionCalculator;
41 import y.util.DataProviderAdapter;
42 import y.util.Maps;
43 import y.view.EdgeRealizer;
44 import y.view.GenericNodeRealizer;
45 import y.view.Graph2D;
46 import y.view.NodeLabel;
47 import y.view.NodeRealizer;
48 import y.view.NodeRealizerIntersectionCalculator;
49 import y.view.YLabel;
50 import y.view.hierarchy.GroupNodeRealizer;
51 import y.view.hierarchy.HierarchyManager;
52 import y.view.tabular.TableGroupNodeRealizer;
53
54 import java.util.Collection;
55 import java.util.HashSet;
56
57
62 public class FlowchartLayoutConfigurator {
63 private static final Object LABEL_LAYOUT_DPKEY = FlowchartLayouter.LABEL_LAYOUT_DPKEY;
64
65
66 private final Collection nodeActivityElements;
67 private final Collection nodeAnnotationElements;
68 private final Collection nodeDataElements;
69 private final Collection nodeEndElements;
70 private final Collection nodeEventElements;
71 private final Collection nodeGatewayElements;
72 private final Collection nodeReferenceElements;
73 private final Collection nodeStartElements;
74
75 private boolean portIntersectionDataProviderCreationEnabled;
76 private int preferredPositiveBranchDirection;
77 private int preferredNegativeBranchDirection;
78 private int adjustedPositiveBranchDirection;
79 private int adjustedNegativeBranchDirection;
80 private String negativeBranchLabel;
81 private String positiveBranchLabel;
82
83
86 public FlowchartLayoutConfigurator() {
87 portIntersectionDataProviderCreationEnabled = false;
88 setPositiveBranchLabel("Yes");
89 setNegativeBranchLabel("No");
90 setPreferredPositiveBranchDirection(FlowchartLayouter.DIRECTION_WITH_THE_FLOW);
91 setPreferredNegativeBranchDirection(FlowchartLayouter.DIRECTION_FLATWISE);
92
93 nodeActivityElements = new HashSet();
94 nodeActivityElements.add(FlowchartRealizerConstants.FLOWCHART_PROCESS_CONFIG_NAME);
95 nodeActivityElements.add(FlowchartRealizerConstants.FLOWCHART_PREDEFINED_PROCESS_CONFIG_NAME);
96 nodeActivityElements.add(FlowchartRealizerConstants.FLOWCHART_LOOP_LIMIT_CONFIG_NAME);
97 nodeActivityElements.add(FlowchartRealizerConstants.FLOWCHART_LOOP_LIMIT_END_CONFIG_NAME);
98
99 nodeAnnotationElements = new HashSet();
100 nodeAnnotationElements.add(FlowchartRealizerConstants.FLOWCHART_ANNOTATION_CONFIG_NAME);
101
102 nodeDataElements = new HashSet();
103 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_CARD_CONFIG_NAME);
104 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_CLOUD_TYPE_CONFIG_NAME);
105 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_DATA_CONFIG_NAME);
106 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_DATABASE_CONFIG_NAME);
107 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_DIRECT_DATA_CONFIG_NAME);
108 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_DOCUMENT_CONFIG_NAME);
109 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_INTERNAL_STORAGE_CONFIG_NAME);
110 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_MANUAL_INPUT_CONFIG_NAME);
111 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_PAPER_TYPE_CONFIG_NAME);
112 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_STORED_DATA_CONFIG_NAME);
113 nodeDataElements.add(FlowchartRealizerConstants.FLOWCHART_SEQUENTIAL_DATA_CONFIG_NAME);
114
115 nodeGatewayElements = new HashSet();
116 nodeGatewayElements.add(FlowchartRealizerConstants.FLOWCHART_DECISION_CONFIG_NAME);
117
118 nodeEndElements = new HashSet();
119 nodeEndElements.add(FlowchartRealizerConstants.FLOWCHART_TERMINATOR_CONFIG_NAME);
120
121 nodeEventElements = new HashSet();
122 nodeEventElements.add(FlowchartRealizerConstants.FLOWCHART_DELAY_CONFIG_NAME);
123 nodeEventElements.add(FlowchartRealizerConstants.FLOWCHART_DISPLAY_CONFIG_NAME);
124 nodeEventElements.add(FlowchartRealizerConstants.FLOWCHART_MANUAL_OPERATION_CONFIG_NAME);
125 nodeEventElements.add(FlowchartRealizerConstants.FLOWCHART_PREPARATION_CONFIG_NAME);
126
127 nodeReferenceElements = new HashSet();
128 nodeReferenceElements.add(FlowchartRealizerConstants.FLOWCHART_ON_PAGE_REFERENCE_CONFIG_NAME);
129 nodeReferenceElements.add(FlowchartRealizerConstants.FLOWCHART_OFF_PAGE_REFERENCE_CONFIG_NAME);
130
131 nodeStartElements = new HashSet();
132 nodeStartElements.add(FlowchartRealizerConstants.FLOWCHART_START1_CONFIG_NAME);
133 nodeStartElements.add(FlowchartRealizerConstants.FLOWCHART_START2_CONFIG_NAME);
134 }
135
136
141 public String getNegativeBranchLabel() {
142 return negativeBranchLabel;
143 }
144
145
150 public void setNegativeBranchLabel(String label) {
151 this.negativeBranchLabel = label;
152 }
153
154
159
160 public String getPositiveBranchLabel() {
161 return positiveBranchLabel;
162 }
163
164
169 public void setPositiveBranchLabel(String label) {
170 this.positiveBranchLabel = label;
171 }
172
173
178 public int getPreferredNegativeBranchDirection() {
179 return preferredNegativeBranchDirection;
180 }
181
182
187 public void setPreferredNegativeBranchDirection(int direction) {
188 preferredNegativeBranchDirection = direction;
189 adjustedPositiveBranchDirection = calculateAdjustedPositiveBranchDirection();
190 adjustedNegativeBranchDirection = calculateAdjustedNegativeBranchDirection();
191 }
192
193
198 public int getPreferredPositiveBranchDirection() {
199 return preferredPositiveBranchDirection;
200 }
201
202
207 public void setPreferredPositiveBranchDirection(int direction) {
208 preferredPositiveBranchDirection = direction;
209 adjustedPositiveBranchDirection = calculateAdjustedPositiveBranchDirection();
210 adjustedNegativeBranchDirection = calculateAdjustedNegativeBranchDirection();
211 }
212
213
219 protected int getAdjustedNegativeBranchDirection() {
220 return adjustedNegativeBranchDirection;
221 }
222
223
229 protected int getAdjustedPositiveBranchDirection() {
230 return adjustedPositiveBranchDirection;
231 }
232
233
239 public boolean isPortIntersectionDataProviderCreationEnabled() {
240 return portIntersectionDataProviderCreationEnabled;
241 }
242
243
248 public void setPortIntersectionDataProviderCreationEnabled(boolean enabled) {
249 this.portIntersectionDataProviderCreationEnabled = enabled;
250 }
251
252
257 public void prepareAll(final Graph2D graph) {
258 if (portIntersectionDataProviderCreationEnabled) {
259 graph.addDataProvider(IntersectionCalculator.SOURCE_INTERSECTION_CALCULATOR_DPKEY,
260 new NodeRealizerIntersectionCalculator(graph, true));
261 graph.addDataProvider(IntersectionCalculator.TARGET_INTERSECTION_CALCULATOR_DPKEY,
262 new NodeRealizerIntersectionCalculator(graph, false));
263 }
264
265 final DataMap branchMap = Maps.createHashedDataMap();
266 graph.addDataProvider(FlowchartLayouter.PREFERRED_DIRECTION_KEY, branchMap);
267
268 final NodeMap nodeTypeMap = Maps.createHashedNodeMap();
269 graph.addDataProvider(FlowchartLayouter.NODE_TYPE_DPKEY, nodeTypeMap);
270
271 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
272 final Node node = nc.node();
273 nodeTypeMap.setInt(node, (int) getType(graph.getRealizer(node)));
274 }
275
276 final EdgeMap edgeTypeMap = Maps.createHashedEdgeMap();
277 graph.addDataProvider(FlowchartLayouter.EDGE_TYPE_DPKEY, edgeTypeMap);
278
279 for (EdgeCursor ec = graph.edges(); ec.ok(); ec.next()) {
280 final Edge edge = ec.edge();
281 final EdgeRealizer realizer = graph.getRealizer(edge);
282
283 edgeTypeMap.setInt(edge, (int) getType(realizer));
284 branchMap.setInt(edge, getBranchType(realizer));
285 }
286
287 final HierarchyManager hm = graph.getHierarchyManager();
288 if (hm != null) {
289 graph.addDataProvider(LABEL_LAYOUT_DPKEY, new DefaultGroupLabelExclusion(hm));
290 }
291 }
292
293
298 public void restoreAll(final Graph2D graph) {
299 final HierarchyManager hm = graph.getHierarchyManager();
300 if (hm != null) {
301 graph.removeDataProvider(LABEL_LAYOUT_DPKEY);
302 }
303
304 if (portIntersectionDataProviderCreationEnabled) {
305 graph.removeDataProvider(IntersectionCalculator.SOURCE_INTERSECTION_CALCULATOR_DPKEY);
306 graph.removeDataProvider(IntersectionCalculator.TARGET_INTERSECTION_CALCULATOR_DPKEY);
307 }
308 graph.removeDataProvider(FlowchartLayouter.NODE_TYPE_DPKEY);
309 graph.removeDataProvider(FlowchartLayouter.EDGE_TYPE_DPKEY);
310 graph.removeDataProvider(FlowchartLayouter.PREFERRED_DIRECTION_KEY);
311 }
312
313
318 protected byte getType(EdgeRealizer realizer) {
319 final NodeRealizer sourceRealizer = realizer.getSourceRealizer();
320 final NodeRealizer targetRealizer = realizer.getTargetRealizer();
321 if (sourceRealizer != null && getType(sourceRealizer) == FlowchartElements.NODE_TYPE_ANNOTATION
322 || targetRealizer != null && getType(targetRealizer) == FlowchartElements.NODE_TYPE_ANNOTATION) {
323 return FlowchartElements.EDGE_TYPE_MESSAGE_FLOW;
324 } else {
325 return FlowchartElements.EDGE_TYPE_SEQUENCE_FLOW;
326 }
327 }
328
329
334 protected byte getType(NodeRealizer realizer) {
335 if (realizer instanceof TableGroupNodeRealizer) {
336 return FlowchartElements.NODE_TYPE_POOL;
337 } else if (realizer instanceof GroupNodeRealizer) {
338 return FlowchartElements.NODE_TYPE_GROUP;
339 } else if (realizer instanceof GenericNodeRealizer) {
340 final String configuration = ((GenericNodeRealizer) realizer).getConfiguration();
341 if (nodeActivityElements.contains(configuration)) {
342 return FlowchartElements.NODE_TYPE_PROCESS;
343 } else if (nodeDataElements.contains(configuration)) {
344 return FlowchartElements.NODE_TYPE_DATA;
345 } else if (nodeAnnotationElements.contains(configuration)) {
346 return FlowchartElements.NODE_TYPE_ANNOTATION;
347 } else if (nodeGatewayElements.contains(configuration)) {
348 return FlowchartElements.NODE_TYPE_DECISION;
349 } else if (nodeEndElements.contains(configuration)) {
350 return FlowchartElements.NODE_TYPE_END_EVENT;
351 } else if (nodeEventElements.contains(configuration)) {
352 return FlowchartElements.NODE_TYPE_EVENT;
353 } else if (nodeReferenceElements.contains(configuration)) {
354 return FlowchartElements.NODE_TYPE_PROCESS;
355 } else if (nodeStartElements.contains(configuration)) {
356 return FlowchartElements.NODE_TYPE_START_EVENT;
357 }
358 }
359
360 return FlowchartElements.TYPE_INVALID;
361 }
362
363
368 protected int getBranchType(EdgeRealizer realizer) {
369 if (isPositiveBranch(realizer)) {
370 return getAdjustedPositiveBranchDirection();
371 } else if (isNegativeBranch(realizer)) {
372 return getAdjustedNegativeBranchDirection();
373 } else {
374 return FlowchartLayouter.DIRECTION_UNDEFINED;
375 }
376 }
377
378
385 protected boolean isPositiveBranch(EdgeRealizer realizer) {
386 return (int) getType(realizer.getSourceRealizer()) == (int) FlowchartElements.NODE_TYPE_DECISION
387 && realizer.labelCount() > 0 && isMatchingLabelText(realizer.getLabel(0), positiveBranchLabel);
388 }
389
390
397 protected boolean isNegativeBranch(EdgeRealizer realizer) {
398 return (int) getType(realizer.getSourceRealizer()) == (int) FlowchartElements.NODE_TYPE_DECISION
399 && realizer.labelCount() > 0 && isMatchingLabelText(realizer.getLabel(0), negativeBranchLabel);
400 }
401
402
405 private static boolean isMatchingLabelText(YLabel label, String text) {
406 final String labelText = label != null ? label.getText() : null;
407 return labelText != null && labelText.equalsIgnoreCase(text);
408 }
409
410
414 private int calculateAdjustedNegativeBranchDirection() {
415 final int positiveDir = getAdjustedPositiveBranchDirection();
416 final int negativeDir = preferredNegativeBranchDirection;
417
418 switch (negativeDir) {
419 case FlowchartLayouter.DIRECTION_STRAIGHT:
420 return positiveDir != FlowchartLayouter.DIRECTION_WITH_THE_FLOW ?
421 FlowchartLayouter.DIRECTION_WITH_THE_FLOW : FlowchartLayouter.DIRECTION_FLATWISE;
422
423 case FlowchartLayouter.DIRECTION_FLATWISE:
424 if (positiveDir == FlowchartLayouter.DIRECTION_RIGHT_IN_FLOW) {
425 return FlowchartLayouter.DIRECTION_LEFT_IN_FLOW;
426 } else if (positiveDir == FlowchartLayouter.DIRECTION_LEFT_IN_FLOW) {
427 return FlowchartLayouter.DIRECTION_RIGHT_IN_FLOW;
428 } else {
429 return negativeDir;
430 }
431
432 default:
433 case FlowchartLayouter.DIRECTION_AGAINST_THE_FLOW:
434 return FlowchartLayouter.DIRECTION_UNDEFINED;
435
436 case FlowchartLayouter.DIRECTION_WITH_THE_FLOW:
437 return positiveDir != negativeDir ? negativeDir : FlowchartLayouter.DIRECTION_FLATWISE;
438
439 case FlowchartLayouter.DIRECTION_LEFT_IN_FLOW:
440 return positiveDir != negativeDir ? negativeDir : FlowchartLayouter.DIRECTION_RIGHT_IN_FLOW;
441
442 case FlowchartLayouter.DIRECTION_RIGHT_IN_FLOW:
443 return positiveDir != negativeDir ? negativeDir : FlowchartLayouter.DIRECTION_LEFT_IN_FLOW;
444 }
445 }
446
447
451 private int calculateAdjustedPositiveBranchDirection() {
452 switch (preferredPositiveBranchDirection) {
453 case FlowchartLayouter.DIRECTION_STRAIGHT:
454 return FlowchartLayouter.DIRECTION_WITH_THE_FLOW;
455 case FlowchartLayouter.DIRECTION_AGAINST_THE_FLOW:
456 return FlowchartLayouter.DIRECTION_UNDEFINED;
457 case FlowchartLayouter.DIRECTION_FLATWISE:
458 if (preferredNegativeBranchDirection == FlowchartLayouter.DIRECTION_RIGHT_IN_FLOW) {
459 return FlowchartLayouter.DIRECTION_LEFT_IN_FLOW;
460 } else if (preferredNegativeBranchDirection == FlowchartLayouter.DIRECTION_LEFT_IN_FLOW) {
461 return FlowchartLayouter.DIRECTION_RIGHT_IN_FLOW;
462 } else {
463 return preferredPositiveBranchDirection;
464 }
465 default:
466 return preferredPositiveBranchDirection;
467 }
468 }
469
470
471 private static class DefaultGroupLabelExclusion extends DataProviderAdapter {
472 private final HierarchyManager hm;
473
474 DefaultGroupLabelExclusion( final HierarchyManager hm ) {
475 this.hm = hm;
476 }
477
478 public boolean getBool( final Object dataHolder ) {
479 if (dataHolder instanceof NodeLabel) {
480 final NodeRealizer nr = ((NodeLabel) dataHolder).getRealizer();
481 if (nr != null && nr.labelCount() > 0 && dataHolder == nr.getLabel(0)) {
482 final Node n = nr.getNode();
483 if (n != null) {
484 final Graph g = n.getGraph();
485 if (g != null && hm.contains(g)) {
486 return !hm.isGroupNode(n);
487 }
488 }
489 }
490 }
491 return true;
492 }
493 }
494 }
495