1
28 package demo.layout.hierarchic;
29
30 import demo.view.DemoBase;
31 import demo.view.DemoDefaults;
32
33 import y.base.DataMap;
34 import y.base.EdgeCursor;
35 import y.base.EdgeList;
36 import y.base.Node;
37 import y.base.NodeCursor;
38 import y.geom.YInsets;
39 import y.layout.grouping.Grouping;
40 import y.layout.hierarchic.IncrementalHierarchicLayouter;
41 import y.layout.hierarchic.incremental.IncrementalHintsFactory;
42 import y.util.Maps;
43 import y.view.EditMode;
44 import y.view.GenericNodeRealizer;
45 import y.view.GenericNodeRealizer.Factory;
46 import y.view.Graph2D;
47 import y.view.Graph2DCanvas;
48 import y.view.Graph2DLayoutExecutor;
49 import y.view.HitInfo;
50 import y.view.LineType;
51 import y.view.NodeLabel;
52 import y.view.NodeRealizer;
53 import y.view.ShinyPlateNodePainter;
54 import y.view.SmartNodeLabelModel;
55 import y.view.TooltipMode;
56 import y.view.ViewMode;
57 import y.view.hierarchy.DefaultHierarchyGraphFactory;
58 import y.view.hierarchy.GenericGroupNodeRealizer;
59 import y.view.hierarchy.GroupLayoutConfigurator;
60 import y.view.hierarchy.HierarchyManager;
61 import y.view.tabular.TableGroupNodeRealizer;
62 import y.view.tabular.TableGroupNodeRealizer.Column;
63 import y.view.tabular.TableGroupNodeRealizer.Table;
64 import y.view.tabular.TableNodePainter;
65 import y.view.tabular.TableStyle;
66
67 import java.awt.Color;
68 import java.awt.EventQueue;
69 import java.awt.event.ActionEvent;
70 import java.awt.event.MouseEvent;
71 import java.util.Locale;
72 import java.util.Map;
73
74 import javax.swing.AbstractAction;
75 import javax.swing.JToolBar;
76
77
104 public class SwimlaneGroupDemo extends IncrementalHierarchicGroupDemo {
105 private static final Color NODE_COLOR = DemoDefaults.DEFAULT_NODE_COLOR;
106 private static final Color NODE_GRADIENT_COLOR = Color.WHITE;
107 private static final Color NODE_LINE_COLOR = DemoDefaults.DEFAULT_NODE_LINE_COLOR;
108 private static final Color GROUP_NODE_COLOR = new Color(255, 255, 255, 127);
109 private static final Color GROUP_NODE_LINE_COLOR = DemoDefaults.DEFAULT_NODE_COLOR;
110 private static final Color GROUP_NODE_LABEL_COLOR = DemoDefaults.DEFAULT_NODE_COLOR;
111 private static final Color ODD_LANE_COLOR = DemoDefaults.DEFAULT_CONTRAST_COLOR;
112 private static final Color EVEN_LANE_COLOR = new Color(237, 247, 247);
113
114 private static final String NODE_CONFIGURATION = "NODE_CONFIGURATION";
115 private static final String SWIMLANE_CONFIGURATION = "SWIMLANE_CONFIGURATION";
116
117 static {
118 initConfigurations();
119 }
120
121
122 public SwimlaneGroupDemo() {
123 view.addViewMode(new TriggerIncrementalLayout());
124 configureRealizers(view.getGraph2D());
125 loadInitialGraph();
126 }
127
128
131 protected void loadInitialGraph() {
132 final Graph2D graph = view.getGraph2D();
133 graph.clear();
134
135 HierarchyManager hierarchy = getHierarchyManager();
136
137 if (layouter != null && hierarchy != null) {
138 final TableGroupNodeRealizer tgnr = new TableGroupNodeRealizer();
140 tgnr.setConfiguration(SWIMLANE_CONFIGURATION);
141
142 tgnr.setLabelText("Swimlane Pool");
143 NodeLabel label = tgnr.getLabel();
144 SmartNodeLabelModel labelModel = new SmartNodeLabelModel();
145 label.setLabelModel(labelModel,
146 labelModel.createDiscreteModelParameter(SmartNodeLabelModel.POSITION_TOP));
147 tgnr.getLabel().setVisible(false);
150
151 final TableStyle.SimpleStyle oddLane =
153 new TableStyle.SimpleStyle(null, null, ODD_LANE_COLOR);
154 tgnr.setStyleProperty(TableNodePainter.COLUMN_STYLE_ID, oddLane);
155 tgnr.setStyleProperty(TableNodePainter.COLUMN_SELECTION_STYLE_ID, oddLane);
156
157 final TableStyle.SimpleStyle evenLane =
158 new TableStyle.SimpleStyle(null, null, EVEN_LANE_COLOR);
159 tgnr.setStyleProperty(TableNodePainter.ALTERNATE_COLUMN_STYLE_ID, evenLane);
160 tgnr.setStyleProperty(TableNodePainter.ALTERNATE_COLUMN_SELECTION_STYLE_ID, evenLane);
161
162 final TableStyle.SimpleStyle none = new TableStyle.SimpleStyle();
163 tgnr.setStyleProperty(TableNodePainter.ROW_STYLE_ID, none);
164 tgnr.setStyleProperty(TableNodePainter.ROW_SELECTION_STYLE_ID, none);
165 tgnr.setStyleProperty(TableNodePainter.TABLE_STYLE_ID, none);
166 tgnr.setStyleProperty(TableNodePainter.TABLE_SELECTION_STYLE_ID, none);
167
168 tgnr.setDefaultColumnInsets(new YInsets(25, 5, 0, 5));
170 tgnr.setDefaultMinimumColumnWidth(50);
171 tgnr.setDefaultRowInsets(new YInsets(15, 0, 15, 0));
172
173 final Column[] columns = new Column[9];
175 final Table table = tgnr.getTable();
176 for (int i = 0; i < columns.length; ++i) {
177 columns[i] = i == 0 ? table.getColumn(0) : table.addColumn();
178
179 final NodeLabel nl = tgnr.createNodeLabel();
180 nl.setText("Lane " + (i + 1));
181 tgnr.configureColumnLabel(nl, columns[i], true, 0);
182 tgnr.addLabel(nl);
183 }
184
185 tgnr.updateTableBounds();
186
187
188 final Node pool = hierarchy.createGroupNode(graph);
189 graph.setRealizer(pool, tgnr);
190
191 final Node n00 = graph.createNode();
192 final Node n01 = graph.createNode();
193 final Node g03 = hierarchy.createGroupNode(graph);
194 final Node g04 = hierarchy.createGroupNode(graph);
195 final Node n05 = graph.createNode();
196 final Node n06 = graph.createNode();
197 final Node n07 = graph.createNode();
198 final Node g08 = hierarchy.createGroupNode(graph);
199 final Node n09 = graph.createNode();
200 final Node n10 = graph.createNode();
201 final Node n11 = graph.createNode();
202 final Node g12 = hierarchy.createGroupNode(graph);
203 final Node n13 = graph.createNode();
204 final Node n14 = graph.createNode();
205 final Node n15 = graph.createNode();
206 final Node n16 = graph.createNode();
207 final Node n17 = graph.createNode();
208 final Node g18 = hierarchy.createGroupNode(graph);
209 final Node n19 = graph.createNode();
210 final Node n20 = graph.createNode();
211 final Node n21 = graph.createNode();
212 final Node n22 = graph.createNode();
213 final Node n23 = graph.createNode();
214
215 hierarchy.setParentNode(n00, pool);
217 hierarchy.setParentNode(n01, pool);
218
219 hierarchy.setParentNode(g03, pool);
220 hierarchy.setParentNode(g04, pool);
221 hierarchy.setParentNode(n05, pool);
222 hierarchy.setParentNode(n06, pool);
223 hierarchy.setParentNode(n07, pool);
224
225 hierarchy.setParentNode(g08, g03);
226 hierarchy.setParentNode(n09, g03);
227 hierarchy.setParentNode(n10, g03);
228 hierarchy.setParentNode(n11, g03);
229
230 hierarchy.setParentNode(g12, g08);
231 hierarchy.setParentNode(n13, g08);
232 hierarchy.setParentNode(n14, g08);
233
234 hierarchy.setParentNode(n15, g12);
235 hierarchy.setParentNode(n16, g12);
236 hierarchy.setParentNode(n17, g12);
237
238 hierarchy.setParentNode(g18, g04);
239 hierarchy.setParentNode(n19, g04);
240 hierarchy.setParentNode(n20, g04);
241
242 hierarchy.setParentNode(n21, g18);
243 hierarchy.setParentNode(n22, g18);
244 hierarchy.setParentNode(n23, g18);
245
246
247 hierarchy.createEdge(n00, n01);
248 hierarchy.createEdge(n01, n06);
249 hierarchy.createEdge(n06, n07);
250 hierarchy.createEdge(n06, n05);
251 hierarchy.createEdge(n06, n20);
252 hierarchy.createEdge(n07, n11);
253 hierarchy.createEdge(n09, n05);
254 hierarchy.createEdge(n10, n05);
255 hierarchy.createEdge(n11, n09);
256 hierarchy.createEdge(n11, n14);
257 hierarchy.createEdge(n13, n09);
258 hierarchy.createEdge(n14, n13);
259 hierarchy.createEdge(n14, n15);
260 hierarchy.createEdge(n15, n13);
261 hierarchy.createEdge(n15, n17);
262 hierarchy.createEdge(n16, n13);
263 hierarchy.createEdge(n17, n16);
264 hierarchy.createEdge(n19, n05);
265 hierarchy.createEdge(n20, n19);
266 hierarchy.createEdge(n20, n21);
267 hierarchy.createEdge(n21, n22);
268 hierarchy.createEdge(n21, n23);
269 hierarchy.createEdge(n21, n05);
270 hierarchy.createEdge(n22, n05);
271 hierarchy.createEdge(n23, n05);
272
273 table.moveToColumn(n00, columns[8]);
275 table.moveToColumn(n01, columns[5]);
276 table.moveToColumn(n05, columns[5]);
280 table.moveToColumn(n06, columns[5]);
281 table.moveToColumn(n07, columns[1]);
282 table.moveToColumn(n09, columns[1]);
284 table.moveToColumn(n10, columns[0]);
285 table.moveToColumn(n11, columns[1]);
286 table.moveToColumn(n13, columns[2]);
288 table.moveToColumn(n14, columns[2]);
289 table.moveToColumn(n15, columns[3]);
290 table.moveToColumn(n16, columns[2]);
291 table.moveToColumn(n17, columns[4]);
292 table.moveToColumn(n19, columns[7]);
294 table.moveToColumn(n20, columns[6]);
295 table.moveToColumn(n21, columns[6]);
296 table.moveToColumn(n22, columns[6]);
297 table.moveToColumn(n23, columns[6]);
298
299 initLabels(graph);
301
302 layout();
303 }
304
305 view.fitContent();
306 view.getGraph2D().updateViews();
307 getUndoManager().resetQueue();
308 }
309
310
314 private void initLabels(final Graph2D graph) {
315 Node tableNode = null;
316 Table table = null;
317 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
318 final NodeRealizer nr = graph.getRealizer(nc.node());
319 if (nr instanceof TableGroupNodeRealizer) {
320 tableNode = nc.node();
321 table = ((TableGroupNodeRealizer) nr).getTable();
322 break;
323 }
324 }
325
326 HierarchyManager hierarchy = getHierarchyManager();
327
328 int grp = 0;
329 int fldr = 0;
330 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
331 if (nc.node() == tableNode) {
332 continue;
333 }
334
335 if (hierarchy.isNormalNode(nc.node())) {
336 final Column column = table == null ? null : table.getColumn(nc.node());
337 if (column != null) {
338 graph.getRealizer(nc.node()).setLabelText(
339 Integer.toString(column.getIndex() + 1));
340 } else {
341 graph.getRealizer(nc.node()).setLabelText("");
342 }
343 NodeLabel label = graph.getRealizer(nc.node()).getLabel();
344 SmartNodeLabelModel model = new SmartNodeLabelModel();
345 label.setLabelModel(model, model.getDefaultParameter());
346 } else if (hierarchy.isGroupNode(nc.node())) {
347 graph.getRealizer(nc.node()).setLabelText(
348 "Group " + (++grp));
349 } else if (hierarchy.isFolderNode(nc.node())) {
350 graph.getRealizer(nc.node()).setLabelText(
351 "Folder " + (++fldr));
352 }
353 }
354 }
355
356
361
362
366 void layoutIncrementally() {
367 Graph2D graph = view.getGraph2D();
368
369 layouter.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_INCREMENTAL);
370
371 DataMap incrementalElements = Maps.createHashedDataMap();
373 final IncrementalHintsFactory ihf = layouter.createIncrementalHintsFactory();
375
376 final GroupLayoutConfigurator glc = new GroupLayoutConfigurator(graph);
378 glc.prepareAll();
379 final Grouping grouping = new Grouping(graph);
380
381 for (NodeCursor nc = graph.selectedNodes(); nc.ok(); nc.next()) {
383 Node n = nc.node();
384 incrementalElements.set(n, ihf.createLayerIncrementallyHint(nc.node()));
385 if (grouping.isGroupNode(n)) {
386 EdgeList markedEdges = grouping.getEdgesGoingIn(n);
388 markedEdges.addAll(grouping.getEdgesGoingOut(n));
389 for (EdgeCursor ec = markedEdges.edges(); ec.ok(); ec.next()) {
390 incrementalElements.set(ec.edge(), ihf.createSequenceIncrementallyHint(ec.edge()));
391 }
392 }
393 }
394 grouping.dispose();
395 glc.restoreAll();
396
397 for (EdgeCursor ec = graph.selectedEdges(); ec.ok(); ec.next()) {
398 incrementalElements.set(ec.edge(), ihf.createSequenceIncrementallyHint(ec.edge()));
399 }
400 graph.addDataProvider(IncrementalHierarchicLayouter.INCREMENTAL_HINTS_DPKEY, incrementalElements);
401
402 try {
403 final Graph2DLayoutExecutor layoutExecutor =
404 new Graph2DLayoutExecutor(Graph2DLayoutExecutor.ANIMATED);
405 layoutExecutor.setConfiguringTableNodeRealizers(true);
406 layoutExecutor.doLayout(view, layouter);
407 } finally {
408 graph.removeDataProvider(IncrementalHierarchicLayouter.INCREMENTAL_HINTS_DPKEY);
409 }
410
411 initLabels(graph);
413 graph.updateViews();
414 }
415
416
419 void layout() {
420 final Graph2D graph = view.getGraph2D();
421 layouter.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_FROM_SCRATCH);
422
423 final Graph2DLayoutExecutor layoutExecutor = new Graph2DLayoutExecutor();
424 layoutExecutor.setConfiguringTableNodeRealizers(true);
425 layoutExecutor.doLayout(view, layouter);
426
427 initLabels(graph);
429 graph.updateViews();
430 }
431
432
437
438 protected void addLayoutActions(JToolBar toolBar) {
439 toolBar.addSeparator();
440 toolBar.add(createActionControl(new AbstractAction(
441 "Layout", SHARED_LAYOUT_ICON) {
442 public void actionPerformed(ActionEvent e) {
443 layout();
444 }
445 }));
446 }
447
448 protected EditMode createEditMode() {
449 final EditMode editMode = new EditMode() {
450 protected void nodeCreated(final Node v) {
451 layoutIncrementally();
452 }
453 };
454 editMode.getMouseInputMode().setNodeSearchingEnabled(true);
456
457 editMode.assignNodeLabel(false);
460
461 editMode.setChildNodeCreationEnabled(true);
463
464 return editMode;
465 }
466
467
470 protected TooltipMode createTooltipMode() {
471 return new TooltipMode() {
472 protected String getNodeTip(Node node) {
473 NodeRealizer nodeRealizer = view.getGraph2D().getRealizer(node);
474 if (nodeRealizer instanceof TableGroupNodeRealizer) {
475 MouseEvent event = getLastMoveEvent();
477 Graph2DCanvas canvas = (Graph2DCanvas) view.getCanvasComponent();
478 double x = canvas.translateX(event.getX());
479 double y = canvas.translateY(event.getY());
480 int index = ((TableGroupNodeRealizer) nodeRealizer).getTable().columnAt(x,y).getIndex() + 1;
482 return nodeRealizer.getLabel(index).getText();
483 } else {
484 return super.getNodeTip(node);
486 }
487 }
488 };
489 }
490
491 void configureRealizers(final Graph2D graph) {
492 graph.setDefaultNodeRealizer(createDefaultNodeRealizer());
493 final DefaultHierarchyGraphFactory hgf =
494 (DefaultHierarchyGraphFactory) graph.getHierarchyManager().getGraphFactory();
495 hgf.setDefaultGroupNodeRealizer(createDefaultGroupNodeRealizer());
496 hgf.setDefaultFolderNodeRealizer(createDefaultFolderNodeRealizer());
497 }
498
499 private NodeRealizer createDefaultNodeRealizer() {
500 Factory factory = GenericNodeRealizer.getFactory();
501 Map map = factory.createDefaultConfigurationMap();
502 ShinyPlateNodePainter painter = new ShinyPlateNodePainter();
503 map.put(GenericNodeRealizer.Painter.class, painter);
504 map.put(GenericNodeRealizer.ContainsTest.class, painter);
505 factory.addConfiguration(NODE_CONFIGURATION, map);
506 GenericNodeRealizer gnr = new GenericNodeRealizer(NODE_CONFIGURATION);
507 gnr.setFillColor(NODE_COLOR);
508 gnr.setLineColor(NODE_LINE_COLOR);
509 gnr.setFillColor2(NODE_GRADIENT_COLOR);
510 gnr.setLineType(LineType.LINE_1);
511 return gnr;
512 }
513
514 private NodeRealizer createDefaultGroupNodeRealizer() {
515 GenericGroupNodeRealizer defaultGroup = new GenericGroupNodeRealizer();
516 defaultGroup.setConfiguration(CONFIGURATION_GROUP);
517 defaultGroup.setSize(100, 60);
518 defaultGroup.setFillColor(GROUP_NODE_COLOR);
519 defaultGroup.setGroupClosed(false);
520 defaultGroup.setLineType(LineType.LINE_2);
521 defaultGroup.setLineColor(GROUP_NODE_LINE_COLOR);
522 defaultGroup.getLabel().setBackgroundColor(GROUP_NODE_LABEL_COLOR);
523 defaultGroup.getLabel().setTextColor(getBlackOrWhite(GROUP_NODE_LABEL_COLOR));
524 return defaultGroup;
525 }
526
527 private NodeRealizer createDefaultFolderNodeRealizer() {
528 GenericGroupNodeRealizer defaultFolder = new GenericGroupNodeRealizer();
529 defaultFolder.setConfiguration(CONFIGURATION_GROUP);
530 defaultFolder.setSize(100, 60);
531 defaultFolder.setFillColor(GROUP_NODE_COLOR);
532 defaultFolder.setGroupClosed(true);
533 defaultFolder.setLineType(LineType.LINE_2);
534 defaultFolder.setLineColor(GROUP_NODE_LINE_COLOR);
535 defaultFolder.getLabel().setBackgroundColor(GROUP_NODE_LABEL_COLOR);
536 defaultFolder.getLabel().setTextColor(getBlackOrWhite(GROUP_NODE_LABEL_COLOR));
537 return defaultFolder;
538 }
539
540 private Color getBlackOrWhite(Color c) {
541 if (c.getRed() + c.getGreen() + c.getBlue() > 3 * 127) {
542 return Color.BLACK;
543 } else {
544 return Color.WHITE;
545 }
546 }
547
548
549 public static void main(String[] args) {
550 EventQueue.invokeLater(new Runnable() {
551 public void run() {
552 Locale.setDefault(Locale.ENGLISH);
553 initLnF();
554 (new SwimlaneGroupDemo()).start();
555 }
556 });
557 }
558
559
560
564 private static void initConfigurations() {
565 final Map map = TableGroupNodeRealizer.createDefaultConfigurationMap();
567 map.put(TableGroupNodeRealizer.Painter.class,
568 TableNodePainter.newAlternatingColumnsInstance());
569 map.put(TableGroupNodeRealizer.GenericMouseInputEditorProvider.class, null);
570
571 TableGroupNodeRealizer.getFactory()
573 .addConfiguration(SWIMLANE_CONFIGURATION, map);
574 }
575
576
577
581 class TriggerIncrementalLayout extends ViewMode {
582 private boolean dragging;
583 private boolean hasHitNodes;
584
585 TriggerIncrementalLayout() {
586 this.dragging = false;
587 this.hasHitNodes = false;
588 }
589
590 public void mouseDraggedLeft(final double x, final double y) {
591 dragging = true;
592 }
593
594 public void mousePressedLeft(final double x, final double y) {
595 getGraph2D().firePreEvent();
596 final HitInfo info = DemoBase.checkNodeHit(view, x, y);
597 hasHitNodes = info.hasHitNodes();
598 }
599
600 public void mouseReleasedLeft(final double x, final double y) {
601 if (dragging && hasHitNodes) {
602 layoutIncrementally();
603 }
604 hasHitNodes = false;
605 dragging = false;
606 getGraph2D().firePostEvent();
607 }
608 }
609 }
610