1
28 package demo.layout.partial;
29
30 import demo.view.hierarchy.GroupingDemo;
31
32 import java.awt.Dimension;
33 import java.awt.BorderLayout;
34 import java.awt.Color;
35 import java.awt.event.ActionEvent;
36 import java.awt.event.KeyEvent;
37 import java.awt.event.InputEvent;
38 import java.awt.event.MouseEvent;
39 import java.util.Map;
40 import java.net.URL;
41
42 import y.layout.Layouter;
43 import y.layout.partial.PartialLayouter;
44 import y.util.DataProviderAdapter;
45 import y.view.Graph2D;
46 import y.view.Graph2DLayoutExecutor;
47 import y.view.Graph2DTraversal;
48 import y.view.Graph2DView;
49 import y.view.HitInfo;
50 import y.view.NodeRealizer;
51 import y.view.Graph2DViewActions;
52 import y.view.GenericNodeRealizer;
53 import y.view.LineType;
54 import y.view.NodeLabel;
55 import y.view.EdgeRealizer;
56 import y.view.ProxyShapeNodeRealizer;
57 import y.view.Selections;
58 import y.view.ViewMode;
59 import y.view.hierarchy.DefaultHierarchyGraphFactory;
60 import y.view.hierarchy.GenericGroupNodeRealizer;
61 import y.view.hierarchy.DefaultGenericAutoBoundsFeature;
62 import y.view.hierarchy.HierarchyManager;
63 import y.base.Node;
64 import y.base.NodeCursor;
65 import y.base.EdgeCursor;
66 import y.base.Edge;
67 import y.base.DataProvider;
68 import y.option.TableEditorFactory;
69 import y.option.OptionHandler;
70 import y.option.Editor;
71
72 import javax.swing.Action;
73 import javax.swing.BorderFactory;
74 import javax.swing.JToolBar;
75 import javax.swing.AbstractAction;
76 import javax.swing.ActionMap;
77 import javax.swing.InputMap;
78 import javax.swing.KeyStroke;
79 import javax.swing.JComponent;
80 import javax.swing.JSplitPane;
81 import javax.swing.JPanel;
82
83
84
87 public abstract class PartialLayoutBase extends GroupingDemo {
88 protected static final Color COLOR_FIXED_NODE = Color.GRAY;
90 protected static final Color COLOR_PARTIAL_NODE = new Color(255, 153, 0);
91 protected static final Color COLOR_FIXED_EDGE = Color.BLACK;
92 protected static final Color COLOR_PARTIAL_EDGE = COLOR_PARTIAL_NODE;
93 protected final OptionHandler optionHandler;
94
95
100 protected PartialLayoutBase( final String helpFilePath ) {
101 super();
102
103 JComponent helpPane = null;
104 if (helpFilePath != null) {
105 final URL url = getResource(helpFilePath);
106 if (url == null) {
107 System.err.println("Could not locate help file: " + helpFilePath);
108 } else {
109 helpPane = createHelpPane(url);
110 }
111 }
112
113 final JPanel propertiesPanel = new JPanel(new BorderLayout());
115 optionHandler = createOptionHandler();
116 propertiesPanel.add(createOptionTable(optionHandler), BorderLayout.NORTH);
117 if (helpPane != null) {
118 helpPane.setPreferredSize(new Dimension(400, 400));
119 propertiesPanel.add(helpPane);
120 }
121
122 final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, view, propertiesPanel);
123 splitPane.setBorder(BorderFactory.createEmptyBorder());
124 splitPane.setResizeWeight(0.95);
125 splitPane.setContinuousLayout(false);
126 contentPane.add(splitPane, BorderLayout.CENTER);
127 }
128
129
137 protected JToolBar createToolBar() {
138 final Action reloadAction = new AbstractAction("Reload") {
139 public void actionPerformed(ActionEvent e) {
140 loadInitialGraph();
141 }
142 };
143 reloadAction.putValue(Action.SHORT_DESCRIPTION, "Reload the initial graph");
144
145 JToolBar bar = super.createToolBar();
146
147 bar.addSeparator();
148 bar.add(new ColorSelectionAction("Lock Selection", true, view));
149 bar.addSeparator(TOOLBAR_SMALL_SEPARATOR);
150 bar.add(new ColorSelectionAction("Unlock Selection", false, view));
151
152 bar.addSeparator();
153 bar.add(reloadAction);
154
155 bar.addSeparator();
156 bar.add(createActionControl(new LayoutAction("Layout")));
157
158 return bar;
159 }
160
161
165 protected void registerViewModes() {
166 super.registerViewModes();
167
168 view.addViewMode(new ToggleColorMode());
169 }
170
171 protected void configureDefaultGroupNodeRealizers() {
172 DefaultHierarchyGraphFactory hgf = (DefaultHierarchyGraphFactory) getHierarchyManager().getGraphFactory();
174
175 Map map = GenericGroupNodeRealizer.createDefaultConfigurationMap();
176 GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
177
178 factory.addConfiguration(CONFIGURATION_GROUP, map);
179 Object abf = factory.getImplementation(CONFIGURATION_GROUP,
180 GenericGroupNodeRealizer.GenericAutoBoundsFeature.class);
181 if (abf instanceof DefaultGenericAutoBoundsFeature) {
182 ((DefaultGenericAutoBoundsFeature) abf).setConsiderNodeLabelSize(true);
183 }
184
185 GenericGroupNodeRealizer gnr = new GenericGroupNodeRealizer();
186
187 gnr.setConfiguration(CONFIGURATION_GROUP);
189
190 gnr.setFillColor(new Color(202, 236, 255, 132));
192 gnr.setLineColor(new Color(102, 102, 153, 255));
193 gnr.setLineType(LineType.DOTTED_1);
194 NodeLabel label = gnr.getLabel();
195 label.setBackgroundColor(COLOR_PARTIAL_NODE);
196 label.setTextColor(Color.BLACK);
197 label.setFontSize(15);
198
199 hgf.setProxyNodeRealizerEnabled(true);
200
201 hgf.setDefaultGroupNodeRealizer(gnr.createCopy());
202 hgf.setDefaultFolderNodeRealizer(gnr.createCopy());
203 }
204
205
206
213 private static void setLabelBackgroundColor( final NodeRealizer nr, final Color color ) {
214 if (nr instanceof ProxyShapeNodeRealizer) {
215 final ProxyShapeNodeRealizer pnr = (ProxyShapeNodeRealizer) nr;
216 for (int i = 0, n = pnr.realizerCount(); i < n; ++i) {
217 setLabelBackgroundColor(pnr.getRealizer(i), color);
218 }
219 } else {
220 nr.getLabel().setBackgroundColor(color);
221 }
222 }
223
224
225 private JComponent createOptionTable(OptionHandler oh) {
226 oh.setAttribute(TableEditorFactory.ATTRIBUTE_INFO_POSITION, TableEditorFactory.InfoPosition.NONE);
227
228 TableEditorFactory tef = new TableEditorFactory();
229 Editor editor = tef.createEditor(oh);
230
231 JComponent optionComponent = editor.getComponent();
232 optionComponent.setPreferredSize(new Dimension(400, 200));
233 optionComponent.setMaximumSize(new Dimension(400, 200));
234 return optionComponent;
235 }
236
237
241 protected abstract OptionHandler createOptionHandler();
242
243
250 protected void layoutSubgraph() {
251 Graph2DLayoutExecutor layoutExecutor = new Graph2DLayoutExecutor();
252 layoutExecutor.getLayoutMorpher().setKeepZoomFactor(true);
253 layoutExecutor.doLayout(view, createConfiguredPartialLayouter());
254 }
255
256
260 protected abstract Layouter createConfiguredPartialLayouter();
261
262
265 protected void registerViewActions() {
266 super.registerViewActions();
267
268 ActionMap actionMap = view.getCanvasComponent().getActionMap();
269 actionMap.put("DUPLICATE_ACTION", new DuplicateSubgraphAction("Duplicate and Layout Subgraph"));
270
271 InputMap inputMap = view.getCanvasComponent().getInputMap();
272 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.CTRL_MASK), "DUPLICATE_ACTION");
273
274 }
275
276
280 class LayoutAction extends AbstractAction {
281 LayoutAction(String name) {
282 super(name, SHARED_LAYOUT_ICON);
283 }
284
285 public void actionPerformed(ActionEvent e) {
286 PartialElementsMarkers ps = new PartialElementsMarkers();
288 boolean selectionExists = ps.markByColor(view.getGraph2D());
289 if (selectionExists) {
290 layoutSubgraph();
291 }
292 ps.resetMarkers(view.getGraph2D());
293 }
294 }
295
296
300 class DuplicateSubgraphAction extends AbstractAction {
301 DuplicateSubgraphAction(String name) {
302 super(name);
303 }
304
305
309 public void actionPerformed(ActionEvent e) {
310 final Graph2DViewActions.DuplicateAction duplicateAction = new Graph2DViewActions.DuplicateAction(view);
312 duplicateAction.duplicate(view);
313
314 PartialElementsMarkers ps = new PartialElementsMarkers();
316 final boolean selectionExists = ps.markBySelection(view.getGraph2D());
317 if (selectionExists) {
318 layoutSubgraph();
319 }
320 ps.resetMarkers(view.getGraph2D());
321 }
322 }
323
324
332 static class PartialElementsMarkers {
333 DataProvider odpSelectedNodes;
334 DataProvider odpSelectedEdges;
335
336
346 boolean markBySelection(final Graph2D graph) {
347 odpSelectedNodes = graph.getDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY);
349 odpSelectedEdges = graph.getDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY);
350
351 graph.addDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY, Selections.createSelectionNodeMap(graph));
353 graph.addDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY, Selections.createSelectionEdgeMap(graph));
354
355 return (graph.selectedNodes().ok() || graph.selectedEdges().ok());
356 }
357
358
368 boolean markByColor(final Graph2D graph) {
369 odpSelectedNodes = graph.getDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY);
371 odpSelectedEdges = graph.getDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY);
372
373 DataProviderAdapter isPartialNode = new DataProviderAdapter() {
375 public boolean getBool(Object dataHolder) {
376 Node n = (Node) dataHolder;
377 if (graph.getHierarchyManager().isGroupNode(n) ||
378 graph.getHierarchyManager().isFolderNode(n)) {
379 return COLOR_PARTIAL_NODE.equals(graph.getRealizer(n).getLabel().getBackgroundColor());
380 } else {
381 return COLOR_PARTIAL_NODE.equals(graph.getRealizer(n).getFillColor());
382 }
383 }
384 };
385
386 DataProviderAdapter isPartialEdge = new DataProviderAdapter() {
387 public boolean getBool(Object dataHolder) {
388 return COLOR_PARTIAL_EDGE.equals(graph.getRealizer((Edge) dataHolder).getLineColor());
389 }
390 };
391
392 graph.addDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY, isPartialNode);
393 graph.addDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY, isPartialEdge);
394
395 for (NodeCursor nodeCursor = graph.nodes(); nodeCursor.ok(); nodeCursor.next()) {
396 Node node = nodeCursor.node();
397 if (isPartialNode.getBool(node)){
398 return true;
399 }
400 }
401 for (EdgeCursor edgeCursor = graph.edges(); edgeCursor.ok(); edgeCursor.next()) {
402 Edge edge = edgeCursor.edge();
403 if (isPartialEdge.getBool(edge)){
404 return true;
405 }
406 }
407
408 return false;
409 }
410
411 void resetMarkers(Graph2D graph) {
412 graph.removeDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY);
414 if (odpSelectedNodes != null) {
415 graph.addDataProvider(PartialLayouter.PARTIAL_NODES_DPKEY, odpSelectedNodes);
417 }
418
419 graph.removeDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY);
420 if (odpSelectedEdges != null) {
421 graph.addDataProvider(PartialLayouter.PARTIAL_EDGES_DPKEY, odpSelectedEdges);
423 }
424 }
425 }
426
427
435 static class ToggleColorMode extends ViewMode {
436
441 public void mouseClicked( final double x, final double y ) {
442 if (lastClickEvent.getButton() == MouseEvent.BUTTON1 &&
443 lastClickEvent.getClickCount() == 2) {
444 mouseClickedImpl(x, y);
445 }
446 }
447
448 private void mouseClickedImpl( final double x, final double y ) {
449 final HitInfo info = view.getHitInfoFactory().createHitInfo(
450 x, y, Graph2DTraversal.NODES | Graph2DTraversal.EDGES, true);
451 if (info.hasHitNodes()) {
452 toggleColor(info.getHitNode());
453 } else if (info.hasHitEdges()) {
454 toggleColor(info.getHitEdge());
455 }
456 }
457
458
462 private void toggleColor( final Edge edge ) {
463 final EdgeRealizer er = view.getGraph2D().getRealizer(edge);
464 if (er.getLineColor() == COLOR_PARTIAL_EDGE) {
465 er.setLineColor(COLOR_FIXED_EDGE);
466 } else {
467 er.setLineColor(COLOR_PARTIAL_EDGE);
468 }
469 view.getGraph2D().updateViews();
470 }
471
472
476 private void toggleColor( final Node node ) {
477 final Graph2D g = view.getGraph2D();
478 final NodeRealizer nr = g.getRealizer(node);
479 final HierarchyManager hierarchyManager = g.getHierarchyManager();
480 if (hierarchyManager.isGroupNode(node) ||
481 hierarchyManager.isFolderNode(node)) {
482 if (nr.getLabel().getBackgroundColor() == COLOR_PARTIAL_NODE) {
483 setLabelBackgroundColor(nr, COLOR_FIXED_NODE);
484 } else {
485 setLabelBackgroundColor(nr, COLOR_PARTIAL_NODE);
486 }
487 } else {
488 if (nr.getFillColor() == COLOR_PARTIAL_NODE) {
489 nr.setFillColor(COLOR_FIXED_NODE);
490 } else {
491 nr.setFillColor(COLOR_PARTIAL_NODE);
492 }
493 }
494 g.updateViews();
495 }
496 }
497
498
506 static class ColorSelectionAction extends AbstractAction {
507 private final boolean fixed;
508 private final Graph2DView view;
509
510
524 ColorSelectionAction(
525 final String name,
526 final boolean fixed,
527 final Graph2DView view
528 ) {
529 super(name);
530 this.fixed = fixed;
531 this.view = view;
532 }
533
534 public void actionPerformed( final ActionEvent e ) {
535 final Graph2D g = view.getGraph2D();
536 g.firePreEvent();
537 g.backupRealizers();
538
539 try {
540 final Color nodeColor = fixed ? COLOR_FIXED_NODE : COLOR_PARTIAL_NODE;
541 for (NodeCursor nc = g.nodes(); nc.ok(); nc.next()) {
542 final Node n = nc.node();
543 if (g.isSelected(n)) {
544 if (g.getHierarchyManager().isGroupNode(n) ||
545 g.getHierarchyManager().isFolderNode(n)) {
546 setLabelBackgroundColor(g.getRealizer(n), nodeColor);
547 } else {
548 g.getRealizer(n).setFillColor(nodeColor);
549 }
550 }
551 }
552
553 final Color edgeColor = fixed ? COLOR_FIXED_EDGE : COLOR_PARTIAL_EDGE;
554 for (EdgeCursor ec = g.edges(); ec.ok(); ec.next()) {
555 final Edge edge = ec.edge();
556 if (g.isSelected(edge)) {
557 g.getRealizer(edge).setLineColor(edgeColor);
558 }
559 }
560
561 g.updateViews();
562 } finally {
563 g.firePostEvent();
564 }
565 }
566 }
567 }