1
14 package demo.layout.partial;
15
16 import demo.view.hierarchy.GroupingDemo;
17
18 import java.awt.Dimension;
19 import java.awt.BorderLayout;
20 import java.awt.Color;
21 import java.awt.event.ActionEvent;
22 import java.awt.event.KeyEvent;
23 import java.awt.event.InputEvent;
24 import java.awt.event.MouseEvent;
25 import java.util.Map;
26 import java.net.URL;
27
28 import y.layout.Layouter;
29 import y.layout.partial.PartialLayouter;
30 import y.util.DataProviderAdapter;
31 import y.view.Graph2D;
32 import y.view.Graph2DLayoutExecutor;
33 import y.view.Graph2DTraversal;
34 import y.view.Graph2DView;
35 import y.view.HitInfo;
36 import y.view.NodeRealizer;
37 import y.view.Graph2DViewActions;
38 import y.view.GenericNodeRealizer;
39 import y.view.LineType;
40 import y.view.NodeLabel;
41 import y.view.EdgeRealizer;
42 import y.view.ProxyShapeNodeRealizer;
43 import y.view.Selections;
44 import y.view.ViewMode;
45 import y.view.hierarchy.DefaultHierarchyGraphFactory;
46 import y.view.hierarchy.GenericGroupNodeRealizer;
47 import y.view.hierarchy.DefaultGenericAutoBoundsFeature;
48 import y.view.hierarchy.HierarchyManager;
49 import y.base.Node;
50 import y.base.NodeCursor;
51 import y.base.EdgeCursor;
52 import y.base.Edge;
53 import y.base.DataProvider;
54 import y.option.TableEditorFactory;
55 import y.option.OptionHandler;
56 import y.option.Editor;
57
58 import javax.swing.Action;
59 import javax.swing.BorderFactory;
60 import javax.swing.JToolBar;
61 import javax.swing.AbstractAction;
62 import javax.swing.ActionMap;
63 import javax.swing.InputMap;
64 import javax.swing.KeyStroke;
65 import javax.swing.JComponent;
66 import javax.swing.JSplitPane;
67 import javax.swing.JPanel;
68
69
70
73 public abstract class PartialLayoutBase extends GroupingDemo {
74 protected static final Color COLOR_FIXED_NODE = Color.GRAY;
76 protected static final Color COLOR_PARTIAL_NODE = new Color(255, 153, 0);
77 protected static final Color COLOR_FIXED_EDGE = Color.BLACK;
78 protected static final Color COLOR_PARTIAL_EDGE = COLOR_PARTIAL_NODE;
79 protected final OptionHandler optionHandler;
80
81
86 protected PartialLayoutBase( final String helpFilePath ) {
87 super();
88
89 JComponent helpPane = null;
90 if (helpFilePath != null) {
91 final URL url = getClass().getResource(helpFilePath);
92 if (url == null) {
93 System.err.println("Could not locate help file: " + helpFilePath);
94 } else {
95 helpPane = createHelpPane(url);
96 }
97 }
98
99 final JPanel propertiesPanel = new JPanel(new BorderLayout());
101 optionHandler = createOptionHandler();
102 propertiesPanel.add(createOptionTable(optionHandler), BorderLayout.NORTH);
103 if (helpPane != null) {
104 helpPane.setPreferredSize(new Dimension(400, 400));
105 propertiesPanel.add(helpPane);
106 }
107
108 final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, view, propertiesPanel);
109 splitPane.setBorder(BorderFactory.createEmptyBorder());
110 splitPane.setResizeWeight(0.95);
111 splitPane.setContinuousLayout(false);
112 contentPane.add(splitPane, BorderLayout.CENTER);
113 }
114
115
123 protected JToolBar createToolBar() {
124 final Action reloadAction = new AbstractAction("Reload") {
125 public void actionPerformed(ActionEvent e) {
126 loadInitialGraph();
127 }
128 };
129 reloadAction.putValue(Action.SHORT_DESCRIPTION, "Reload the initial graph");
130
131 JToolBar bar = super.createToolBar();
132
133 bar.addSeparator();
134 bar.add(new ColorSelectionAction("Lock Selection", true, view));
135 bar.addSeparator(TOOLBAR_SMALL_SEPARATOR);
136 bar.add(new ColorSelectionAction("Unlock Selection", false, view));
137
138 bar.addSeparator();
139 bar.add(reloadAction);
140
141 bar.addSeparator();
142 bar.add(createActionControl(new LayoutAction("Layout")));
143
144 return bar;
145 }
146
147
151 protected void registerViewModes() {
152 super.registerViewModes();
153
154 view.addViewMode(new ToggleColorMode());
155 }
156
157 protected void configureDefaultGroupNodeRealizers() {
158 DefaultHierarchyGraphFactory hgf = (DefaultHierarchyGraphFactory) getHierarchyManager().getGraphFactory();
160
161 Map map = GenericGroupNodeRealizer.createDefaultConfigurationMap();
162 GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
163
164 factory.addConfiguration(CONFIGURATION_GROUP, map);
165 Object abf = factory.getImplementation(CONFIGURATION_GROUP,
166 GenericGroupNodeRealizer.GenericAutoBoundsFeature.class);
167 if (abf instanceof DefaultGenericAutoBoundsFeature) {
168 ((DefaultGenericAutoBoundsFeature) abf).setConsiderNodeLabelSize(true);
169 }
170
171 GenericGroupNodeRealizer gnr = new GenericGroupNodeRealizer();
172
173 gnr.setConfiguration(CONFIGURATION_GROUP);
175
176 gnr.setFillColor(new Color(202, 236, 255, 132));
178 gnr.setLineColor(new Color(102, 102, 153, 255));
179 gnr.setLineType(LineType.DOTTED_1);
180 NodeLabel label = gnr.getLabel();
181 label.setBackgroundColor(COLOR_PARTIAL_NODE);
182 label.setTextColor(Color.BLACK);
183 label.setFontSize(15);
184
185 hgf.setProxyNodeRealizerEnabled(true);
186
187 hgf.setDefaultGroupNodeRealizer(gnr.createCopy());
188 hgf.setDefaultFolderNodeRealizer(gnr.createCopy());
189 }
190
191
192
199 private static void setLabelBackgroundColor( final NodeRealizer nr, final Color color ) {
200 if (nr instanceof ProxyShapeNodeRealizer) {
201 final ProxyShapeNodeRealizer pnr = (ProxyShapeNodeRealizer) nr;
202 for (int i = 0, n = pnr.realizerCount(); i < n; ++i) {
203 setLabelBackgroundColor(pnr.getRealizer(i), color);
204 }
205 } else {
206 nr.getLabel().setBackgroundColor(color);
207 }
208 }
209
210
211 private JComponent createOptionTable(OptionHandler oh) {
212 oh.setAttribute(TableEditorFactory.ATTRIBUTE_INFO_POSITION, TableEditorFactory.InfoPosition.NONE);
213
214 TableEditorFactory tef = new TableEditorFactory();
215 Editor editor = tef.createEditor(oh);
216
217 JComponent optionComponent = editor.getComponent();
218 optionComponent.setPreferredSize(new Dimension(400, 200));
219 optionComponent.setMaximumSize(new Dimension(400, 200));
220 return optionComponent;
221 }
222
223
227 protected abstract OptionHandler createOptionHandler();
228
229
236 protected void layoutSubgraph() {
237 Graph2DLayoutExecutor layoutExecutor = new Graph2DLayoutExecutor();
238 layoutExecutor.getLayoutMorpher().setKeepZoomFactor(true);
239 layoutExecutor.doLayout(view, createConfiguredPartialLayouter());
240 }
241
242
246 protected abstract Layouter createConfiguredPartialLayouter();
247
248
251 protected void registerViewActions() {
252 super.registerViewActions();
253
254 ActionMap actionMap = view.getCanvasComponent().getActionMap();
255 actionMap.put("DUPLICATE_ACTION", new DuplicateSubgraphAction("Duplicate and Layout Subgraph"));
256
257 InputMap inputMap = view.getCanvasComponent().getInputMap();
258 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_MASK), "DUPLICATE_ACTION");
259
260 }
261
262
266 class LayoutAction extends AbstractAction {
267 LayoutAction(String name) {
268 super(name, SHARED_LAYOUT_ICON);
269 }
270
271 public void actionPerformed(ActionEvent e) {
272 PartialElementsMarkers ps = new PartialElementsMarkers();
274 boolean selectionExists = ps.markByColor(view.getGraph2D());
275 if (selectionExists) {
276 layoutSubgraph();
277 }
278 ps.resetMarkers(view.getGraph2D());
279 }
280 }
281
282
286 class DuplicateSubgraphAction extends AbstractAction {
287 DuplicateSubgraphAction(String name) {
288 super(name);
289 }
290
291
295 public void actionPerformed(ActionEvent e) {
296 final Graph2DViewActions.DuplicateAction duplicateAction = new Graph2DViewActions.DuplicateAction(view);
298 duplicateAction.duplicate(view);
299
300 PartialElementsMarkers ps = new PartialElementsMarkers();
302 final boolean selectionExists = ps.markBySelection(view.getGraph2D());
303 if (selectionExists) {
304 layoutSubgraph();
305 }
306 ps.resetMarkers(view.getGraph2D());
307 }
308 }
309
310
318 static class PartialElementsMarkers {
319 DataProvider odpSelectedNodes;
320 DataProvider odpSelectedEdges;
321
322
332 boolean markBySelection(final Graph2D graph) {
333 odpSelectedNodes = graph.getDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY);
335 odpSelectedEdges = graph.getDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY);
336
337 graph.addDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY, Selections.createSelectionNodeMap(graph));
339 graph.addDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY, Selections.createSelectionEdgeMap(graph));
340
341 return (graph.selectedNodes().ok() || graph.selectedEdges().ok());
342 }
343
344
354 boolean markByColor(final Graph2D graph) {
355 odpSelectedNodes = graph.getDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY);
357 odpSelectedEdges = graph.getDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY);
358
359 DataProviderAdapter isPartialNode = new DataProviderAdapter() {
361 public boolean getBool(Object dataHolder) {
362 Node n = (Node) dataHolder;
363 if (graph.getHierarchyManager().isGroupNode(n) ||
364 graph.getHierarchyManager().isFolderNode(n)) {
365 return COLOR_PARTIAL_NODE.equals(graph.getRealizer(n).getLabel().getBackgroundColor());
366 } else {
367 return COLOR_PARTIAL_NODE.equals(graph.getRealizer(n).getFillColor());
368 }
369 }
370 };
371
372 DataProviderAdapter isPartialEdge = new DataProviderAdapter() {
373 public boolean getBool(Object dataHolder) {
374 return COLOR_PARTIAL_EDGE.equals(graph.getRealizer((Edge) dataHolder).getLineColor());
375 }
376 };
377
378 graph.addDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY, isPartialNode);
379 graph.addDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY, isPartialEdge);
380
381 for (NodeCursor nodeCursor = graph.nodes(); nodeCursor.ok(); nodeCursor.next()) {
382 Node node = nodeCursor.node();
383 if (isPartialNode.getBool(node)){
384 return true;
385 }
386 }
387 for (EdgeCursor edgeCursor = graph.edges(); edgeCursor.ok(); edgeCursor.next()) {
388 Edge edge = edgeCursor.edge();
389 if (isPartialEdge.getBool(edge)){
390 return true;
391 }
392 }
393
394 return false;
395 }
396
397 void resetMarkers(Graph2D graph) {
398 graph.removeDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY);
400 if (odpSelectedNodes != null) {
401 graph.addDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY, odpSelectedNodes);
403 }
404
405 graph.removeDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY);
406 if (odpSelectedEdges != null) {
407 graph.addDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY, odpSelectedEdges);
409 }
410 }
411 }
412
413
421 static class ToggleColorMode extends ViewMode {
422
427 public void mouseClicked( final double x, final double y ) {
428 if (lastClickEvent.getButton() == MouseEvent.BUTTON1 &&
429 lastClickEvent.getClickCount() == 2) {
430 mouseClickedImpl(x, y);
431 }
432 }
433
434 private void mouseClickedImpl( final double x, final double y ) {
435 final HitInfo info = view.getHitInfoFactory().createHitInfo(
436 x, y, Graph2DTraversal.NODES | Graph2DTraversal.EDGES, true);
437 if (info.hasHitNodes()) {
438 toggleColor(info.getHitNode());
439 } else if (info.hasHitEdges()) {
440 toggleColor(info.getHitEdge());
441 }
442 }
443
444
448 private void toggleColor( final Edge edge ) {
449 final EdgeRealizer er = view.getGraph2D().getRealizer(edge);
450 if (er.getLineColor() == COLOR_PARTIAL_EDGE) {
451 er.setLineColor(COLOR_FIXED_EDGE);
452 } else {
453 er.setLineColor(COLOR_PARTIAL_EDGE);
454 }
455 view.getGraph2D().updateViews();
456 }
457
458
462 private void toggleColor( final Node node ) {
463 final Graph2D g = view.getGraph2D();
464 final NodeRealizer nr = g.getRealizer(node);
465 final HierarchyManager hierarchyManager = g.getHierarchyManager();
466 if (hierarchyManager.isGroupNode(node) ||
467 hierarchyManager.isFolderNode(node)) {
468 if (nr.getLabel().getBackgroundColor() == COLOR_PARTIAL_NODE) {
469 setLabelBackgroundColor(nr, COLOR_FIXED_NODE);
470 } else {
471 setLabelBackgroundColor(nr, COLOR_PARTIAL_NODE);
472 }
473 } else {
474 if (nr.getFillColor() == COLOR_PARTIAL_NODE) {
475 nr.setFillColor(COLOR_FIXED_NODE);
476 } else {
477 nr.setFillColor(COLOR_PARTIAL_NODE);
478 }
479 }
480 g.updateViews();
481 }
482 }
483
484
492 static class ColorSelectionAction extends AbstractAction {
493 private final boolean fixed;
494 private final Graph2DView view;
495
496
510 ColorSelectionAction(
511 final String name,
512 final boolean fixed,
513 final Graph2DView view
514 ) {
515 super(name);
516 this.fixed = fixed;
517 this.view = view;
518 }
519
520 public void actionPerformed( final ActionEvent e ) {
521 final Graph2D g = view.getGraph2D();
522
523 final Color nodeColor = fixed ? COLOR_FIXED_NODE : COLOR_PARTIAL_NODE;
524 for (NodeCursor nc = g.nodes(); nc.ok(); nc.next()) {
525 final Node n = nc.node();
526 if (g.isSelected(n)) {
527 if (g.getHierarchyManager().isGroupNode(n) ||
528 g.getHierarchyManager().isFolderNode(n)) {
529 setLabelBackgroundColor(g.getRealizer(n), nodeColor);
530 } else {
531 g.getRealizer(n).setFillColor(nodeColor);
532 }
533 }
534 }
535
536 final Color edgeColor = fixed ? COLOR_FIXED_EDGE : COLOR_PARTIAL_EDGE;
537 for (EdgeCursor ec = g.edges(); ec.ok(); ec.next()) {
538 final Edge edge = ec.edge();
539 if (g.isSelected(edge)) {
540 g.getRealizer(edge).setLineColor(edgeColor);
541 }
542 }
543
544 g.updateViews();
545 }
546 }
547 }