1
14 package demo.view.layout.hierarchic;
15
16 import y.base.DataProvider;
17 import y.base.Node;
18 import y.base.NodeCursor;
19 import y.base.NodeMap;
20 import y.layout.hierarchic.IncrementalHierarchicLayouter;
21 import y.layout.hierarchic.incremental.SwimLaneDescriptor;
22 import y.view.EditMode;
23 import y.view.Graph2D;
24 import y.view.HitInfo;
25 import y.view.ShapeNodeRealizer;
26 import y.view.ViewMode;
27 import y.view.NodeRealizer;
28 import y.view.hierarchy.HierarchyEditMode;
29 import y.view.hierarchy.DefaultHierarchyGraphFactory;
30
31 import java.awt.Color;
32 import java.awt.event.ActionEvent;
33 import java.util.Iterator;
34 import java.util.TreeSet;
35 import javax.swing.AbstractAction;
36 import javax.swing.JToolBar;
37
38
65 public class SwimLaneGroupDemo extends IncrementalHierarchicGroupDemo {
66 private final SwimLaneDrawable swimLaneDrawable;
67
68 public SwimLaneGroupDemo() {
69 final Graph2D graph = view.getGraph2D();
70 swimLaneDrawable = new SwimLaneDrawable(graph, createSwimLaneMap(graph));
71 swimLaneDrawable.setEvenLaneColor(new Color(0, 130, 183));
72 swimLaneDrawable.setOddLaneColor(new Color(17, 144, 126));
73
74 view.addBackgroundDrawable(swimLaneDrawable);
75 view.addViewMode(new SwimLaneViewMode());
76
77 configureRealizers(graph);
78
79 loadInitialGraph();
80 }
81
82
85 protected void loadInitialGraph() {
86 final Graph2D graph = view.getGraph2D();
87 graph.clear();
88
89 if (swimLaneDrawable != null) {
90 swimLaneDrawable.updateLanes();
91 }
92
93 if (layouter != null && hierarchy != null) {
94 final Node n00 = graph.createNode();
95 final Node n01 = graph.createNode();
96 final Node g02 = hierarchy.createGroupNode(graph);
97 final Node g03 = hierarchy.createGroupNode(graph);
98 final Node g04 = hierarchy.createGroupNode(graph);
99 final Node n05 = graph.createNode();
100 final Node n06 = graph.createNode();
101 final Node n07 = graph.createNode();
102 final Node g08 = hierarchy.createGroupNode(graph);
103 final Node n09 = graph.createNode();
104 final Node n10 = graph.createNode();
105 final Node n11 = graph.createNode();
106 final Node g12 = hierarchy.createGroupNode(graph);
107 final Node n13 = graph.createNode();
108 final Node n14 = graph.createNode();
109 final Node n15 = graph.createNode();
110 final Node n16 = graph.createNode();
111 final Node n17 = graph.createNode();
112 final Node g18 = hierarchy.createGroupNode(graph);
113 final Node n19 = graph.createNode();
114 final Node n20 = graph.createNode();
115 final Node n21 = graph.createNode();
116 final Node n22 = graph.createNode();
117 final Node n23 = graph.createNode();
118
119 hierarchy.setParentNode(g03, g02);
120 hierarchy.setParentNode(g04, g02);
121 hierarchy.setParentNode(n05, g02);
122 hierarchy.setParentNode(n06, g02);
123 hierarchy.setParentNode(n07, g02);
124
125 hierarchy.setParentNode(g08, g03);
126 hierarchy.setParentNode(n09, g03);
127 hierarchy.setParentNode(n10, g03);
128 hierarchy.setParentNode(n11, g03);
129
130 hierarchy.setParentNode(g12, g08);
131 hierarchy.setParentNode(n13, g08);
132 hierarchy.setParentNode(n14, g08);
133
134 hierarchy.setParentNode(n15, g12);
135 hierarchy.setParentNode(n16, g12);
136 hierarchy.setParentNode(n17, g12);
137
138 hierarchy.setParentNode(g18, g04);
139 hierarchy.setParentNode(n19, g04);
140 hierarchy.setParentNode(n20, g04);
141
142 hierarchy.setParentNode(n21, g18);
143 hierarchy.setParentNode(n22, g18);
144 hierarchy.setParentNode(n23, g18);
145
146 hierarchy.createEdge(n00, n01);
147 hierarchy.createEdge(n01, n06);
148 hierarchy.createEdge(n06, n07);
149 hierarchy.createEdge(n06, n05);
150 hierarchy.createEdge(n06, n20);
151 hierarchy.createEdge(n07, n11);
152 hierarchy.createEdge(n09, n05);
153 hierarchy.createEdge(n10, n05);
154 hierarchy.createEdge(n11, n09);
155 hierarchy.createEdge(n11, n14);
156 hierarchy.createEdge(n13, n09);
157 hierarchy.createEdge(n14, n13);
158 hierarchy.createEdge(n14, n15);
159 hierarchy.createEdge(n15, n13);
160 hierarchy.createEdge(n15, n17);
161 hierarchy.createEdge(n16, n13);
162 hierarchy.createEdge(n17, n16);
163 hierarchy.createEdge(n19, n05);
164 hierarchy.createEdge(n20, n19);
165 hierarchy.createEdge(n20, n21);
166 hierarchy.createEdge(n21, n22);
167 hierarchy.createEdge(n21, n23);
168 hierarchy.createEdge(n21, n05);
169 hierarchy.createEdge(n22, n05);
170 hierarchy.createEdge(n23, n05);
171
172 final NodeMap swimLaneNm = createSwimLaneMap(graph);
173 swimLaneNm.set(n00, createSwimLaneDescriptor(9));
174 swimLaneNm.set(n01, createSwimLaneDescriptor(6));
175 swimLaneNm.set(n05, createSwimLaneDescriptor(6));
179 swimLaneNm.set(n06, createSwimLaneDescriptor(6));
180 swimLaneNm.set(n07, createSwimLaneDescriptor(2));
181 swimLaneNm.set(n09, createSwimLaneDescriptor(2));
183 swimLaneNm.set(n10, createSwimLaneDescriptor(1));
184 swimLaneNm.set(n11, createSwimLaneDescriptor(2));
185 swimLaneNm.set(n13, createSwimLaneDescriptor(3));
187 swimLaneNm.set(n14, createSwimLaneDescriptor(3));
188 swimLaneNm.set(n15, createSwimLaneDescriptor(4));
189 swimLaneNm.set(n16, createSwimLaneDescriptor(3));
190 swimLaneNm.set(n17, createSwimLaneDescriptor(5));
191 swimLaneNm.set(n19, createSwimLaneDescriptor(8));
193 swimLaneNm.set(n20, createSwimLaneDescriptor(7));
194 swimLaneNm.set(n21, createSwimLaneDescriptor(7));
195 swimLaneNm.set(n22, createSwimLaneDescriptor(7));
196 swimLaneNm.set(n23, createSwimLaneDescriptor(7));
197
198 initLabels(graph, swimLaneNm);
199
200 layout();
201 }
202
203 view.fitContent();
204 view.getGraph2D().updateViews();
205 }
206
207
212 private void initLabels( final Graph2D graph, final NodeMap node2sld ) {
213 int grp = 0;
214 int fldr = 0;
215 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
216 if (hierarchy.isNormalNode(nc.node())) {
217 final SwimLaneDescriptor sld =
218 (SwimLaneDescriptor) node2sld.get(nc.node());
219 if (sld != null) {
220 graph.getRealizer(nc.node()).setLabelText(
221 String.valueOf(sld.getClientObject()));
222 }
223 } else if (hierarchy.isGroupNode(nc.node())) {
224 graph.getRealizer(nc.node()).setLabelText(
225 "Group " + (++grp));
226 } else if (hierarchy.isFolderNode(nc.node())) {
227 graph.getRealizer(nc.node()).setLabelText(
228 "Folder " + (++fldr));
229 }
230 }
231 }
232
233
237 private void initLabelsByIndex( final Graph2D graph, final NodeMap node2sld ) {
238 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
239 if (!hierarchy.isNormalNode(nc.node())) {
240 continue;
241 }
242
243 final SwimLaneDescriptor sld = (SwimLaneDescriptor) node2sld.get(nc.node());
244 graph.getRealizer(nc.node()).setLabelText(
245 sld != null ? String.valueOf(sld.getComputedLaneIndex() + 1) : "");
246 }
247 }
248
249
253 private NodeMap createSwimLaneMap( final Graph2D graph ) {
254 final DataProvider swimLaneDp =
255 graph.getDataProvider(
256 IncrementalHierarchicLayouter.SWIMLANE_DESCRIPTOR_DPKEY);
257 if (swimLaneDp instanceof NodeMap) {
258 return (NodeMap)swimLaneDp;
259 } else {
260 final NodeMap swimLaneNm = graph.createNodeMap();
261 graph.addDataProvider(
262 IncrementalHierarchicLayouter.SWIMLANE_DESCRIPTOR_DPKEY,
263 swimLaneNm);
264 return swimLaneNm;
265 }
266 }
267
268
271 private SwimLaneDescriptor createSwimLaneDescriptor( final int i ) {
272 final Integer key = new Integer(i);
273 final SwimLaneDescriptor sld = new SwimLaneDescriptor(key);
274 sld.setLeftLaneInset(5);
275 sld.setRightLaneInset(5);
276 return sld;
277 }
278
279
284 private SwimLaneDescriptor closestSwimLane(
285 final double x,
286 final TreeSet swimLanes
287 ) {
288 if (swimLanes.isEmpty()) {
289 return createSwimLaneDescriptor(1);
290 }
291
292 final SwimLaneDescriptor first = (SwimLaneDescriptor) swimLanes.first();
293 final SwimLaneDescriptor last = (SwimLaneDescriptor) swimLanes.last();
294
295 SwimLaneDescriptor result = null;
296 if (x < first.getComputedLanePosition()) {
297 final int id = ((Integer) first.getClientObject()).intValue() - 1;
298 result = createSwimLaneDescriptor(id);
299 } else if (x > last.getComputedLanePosition() + last.getComputedLaneWidth()) {
300 final int id = ((Integer) last.getClientObject()).intValue() + 1;
301 result = createSwimLaneDescriptor(id);
302 } else {
303 for (Iterator it = swimLanes.iterator(); it.hasNext();) {
304 final SwimLaneDescriptor sld = (SwimLaneDescriptor) it.next();
305 if (sld.getComputedLanePosition() <= x &&
306 x < sld.getComputedLanePosition() + sld.getComputedLaneWidth()) {
307 result = sld;
308 break;
309 }
310 }
311 }
312
313 return result;
314 }
315
316 private SwimLaneDescriptor getMinimalSLD( final Node node ) {
317 if (hierarchy.isGroupNode(node)) {
318 SwimLaneDescriptor sld = null;
319 for (NodeCursor nc = hierarchy.getChildren(node); nc.ok(); nc.next()) {
320 final SwimLaneDescriptor _sld = getMinimalSLD(nc.node());
321 if (sld == null) {
322 if (_sld != null) {
323 sld = _sld;
324 }
325 } else {
326 if (_sld != null && sld.compareTo(_sld) > 0) {
327 sld = _sld;
328 }
329 }
330 }
331 return sld;
332 } else {
333 return (SwimLaneDescriptor)createSwimLaneMap(view.getGraph2D()).get(node);
334 }
335 }
336
337
338
343
344 void layoutIncrementally() {
345 super.layoutIncrementally();
346 swimLaneDrawable.updateLanes();
347 view.getGraph2D().updateViews();
348 }
349
350 void layout() {
351 super.layout();
352 swimLaneDrawable.updateLanes();
353 view.getGraph2D().updateViews();
354 }
355
356 protected void openFolder( final Node folderNode ) {
357 createSwimLaneMap(view.getGraph2D()).set(folderNode, null);
358 super.openFolder(folderNode);
359 }
360
361 protected void closeGroup( final Node groupNode ) {
362 createSwimLaneMap(view.getGraph2D()).set(groupNode, getMinimalSLD(groupNode));
363 super.closeGroup(groupNode);
364 }
365
366 public void navigateToInnerGraph( final Node folderNode ) {
367 }
368
369 public void navigateToParentGraph() {
370 }
371
372
373
378
379 protected JToolBar createToolBar() {
380 final JToolBar jtb = super.createToolBar();
381 for (int i = jtb.getComponentCount(), n = i - 4; i --> n;) {
382 jtb.remove(i);
383 }
384 jtb.addSeparator();
385 jtb.add(new AbstractAction("New Layout") {
386 public void actionPerformed( ActionEvent e ) {
387 layout();
388 }
389 });
390 return jtb;
391 }
392
393 protected EditMode createEditMode() {
394 final EditMode oldMode = super.createEditMode();
395 final EditMode newMode = new SwimLaneHierarchyEditMode();
396 newMode.assignNodeLabel(false);
397 newMode.setPopupMode(oldMode.getPopupMode());
398 return newMode;
399 }
400
401 void configureRealizers( final Graph2D graph ) {
402 final ShapeNodeRealizer snr = new ShapeNodeRealizer();
403 snr.setShapeType(ShapeNodeRealizer.ROUND_RECT);
404 snr.setFillColor(new Color(255, 204, 0));
405
406 graph.setDefaultNodeRealizer(snr);
407
408 final DefaultHierarchyGraphFactory hgf =
409 (DefaultHierarchyGraphFactory) hierarchy.getGraphFactory();
410
411 final NodeRealizer gnr = hgf.getDefaultGroupNodeRealizer();
412 gnr.setFillColor(new Color(202, 236, 255, 132));
413 gnr.getLabel().setBackgroundColor(new Color(153, 204, 255, 204));
414 if (gnr instanceof ShapeNodeRealizer) {
415 ((ShapeNodeRealizer) gnr).setShapeType(ShapeNodeRealizer.ROUND_RECT);
416 }
417 final NodeRealizer fnr = hgf.getDefaultFolderNodeRealizer();
418 fnr.setFillColor(new Color(242, 240, 216, 204));
419 fnr.getLabel().setBackgroundColor(new Color(183, 182, 158, 204));
420 if (fnr instanceof ShapeNodeRealizer) {
421 ((ShapeNodeRealizer) fnr).setShapeType(ShapeNodeRealizer.ROUND_RECT);
422 }
423 }
424
425
426
431
432 public static void main( String[] args ) {
433 initLnF();
434 (new SwimLaneGroupDemo()).start();
435 }
436
437
438
442 class SwimLaneViewMode extends ViewMode {
443 private boolean dragging;
444 private boolean hasHitNodes;
445
446 SwimLaneViewMode() {
447 this.dragging = false;
448 this.hasHitNodes = false;
449 }
450
451 public void mouseDraggedLeft( final double x, final double y ) {
452 dragging = true;
453 }
454
455 public void mousePressedLeft( final double x, final double y ) {
456 final HitInfo info = new HitInfo(view, x, y, true, HitInfo.NODE);
457 hasHitNodes = info.hasHitNodes();
458 }
459
460 public void mouseReleasedLeft( final double x, final double y ) {
461 if (dragging && hasHitNodes) {
462 final Graph2D graph = view.getGraph2D();
463
464 final TreeSet swimLanes = new TreeSet();
465 final NodeMap node2sld = createSwimLaneMap(graph);
466 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
467 final SwimLaneDescriptor sld = (SwimLaneDescriptor) node2sld.get(nc.node());
468 if (sld != null) {
469 swimLanes.add(sld);
470 }
471 }
472
473 if (assignSwimLanes(graph, graph.selectedNodes(), swimLanes, node2sld)) {
474 layoutIncrementally();
475 initLabelsByIndex(graph, node2sld);
476 }
477 }
478 hasHitNodes = false;
479 dragging = false;
480 }
481
482 private boolean assignSwimLanes(
483 final Graph2D graph,
484 final NodeCursor nodes,
485 final TreeSet swimLanes,
486 final NodeMap node2sld
487 ) {
488 boolean dirty = false;
489 for (; nodes.ok(); nodes.next()) {
490 final Node node = nodes.node();
491 if (hierarchy.isGroupNode(node)) {
492 dirty |= assignSwimLanes(
493 graph, hierarchy.getChildren(node), swimLanes, node2sld);
494 } else {
495 final SwimLaneDescriptor sld =
496 closestSwimLane(graph.getCenterX(node), swimLanes);
497 if (sld != null) {
498 node2sld.set(node, sld);
499 dirty = true;
500 }
501 }
502 }
503 return dirty;
504 }
505 }
506
507
511 class SwimLaneHierarchyEditMode extends HierarchyEditMode {
512 protected Node createNode( final Graph2D graph, final double x, final double y ) {
513 final Node node = super.createNode(graph, x, y);
514 final TreeSet swimLanes = new TreeSet();
515 final NodeMap node2sld = createSwimLaneMap(graph);
516 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
517 final SwimLaneDescriptor sld = (SwimLaneDescriptor) node2sld.get(nc.node());
518 if (sld != null) {
519 swimLanes.add(sld);
520 }
521 }
522
523 final SwimLaneDescriptor sld = closestSwimLane(x, swimLanes);
524 if (sld != null) {
525 graph.setSelected(node, true);
526 node2sld.set(node, sld);
527 layoutIncrementally();
528 graph.setSelected(node, false);
529 initLabelsByIndex(graph, node2sld);
530 }
531
532 return node;
533 }
534 }
535 }
536