1
28 package demo.view.hierarchy;
29
30 import demo.view.DemoBase;
31 import y.base.Node;
32 import y.view.CreateEdgeMode;
33 import y.view.EditMode;
34 import y.view.GenericNodeRealizer;
35 import y.view.Graph2D;
36 import y.view.Graph2DView;
37 import y.view.Graph2DViewActions;
38 import y.view.NodeRealizer;
39 import y.view.PopupMode;
40 import y.view.ProxyShapeNodeRealizer;
41 import y.view.ViewMode;
42 import y.view.NodeLabel;
43 import y.view.LineType;
44 import y.view.hierarchy.DefaultGenericAutoBoundsFeature;
45 import y.view.hierarchy.DefaultHierarchyGraphFactory;
46 import y.view.hierarchy.GenericGroupNodeRealizer;
47 import y.view.hierarchy.HierarchyManager;
48
49 import javax.swing.Action;
50 import javax.swing.ActionMap;
51 import javax.swing.InputMap;
52 import javax.swing.JMenu;
53 import javax.swing.JMenuBar;
54 import javax.swing.JMenuItem;
55 import javax.swing.JPopupMenu;
56 import javax.swing.KeyStroke;
57 import java.awt.event.ActionEvent;
58 import java.awt.event.KeyEvent;
59 import java.awt.event.InputEvent;
60 import java.awt.Color;
61 import java.awt.EventQueue;
62 import java.util.HashMap;
63 import java.util.Locale;
64 import java.util.Map;
65
66
101 public class GroupingDemo extends DemoBase {
102
103
104 public static final String CONFIGURATION_GROUP = "GroupingDemo_GROUP_NODE";
105
106 protected static final Map actionNames;
107 static {
108 actionNames = new HashMap();
109 actionNames.put(Graph2DViewActions.CLOSE_GROUPS, "Close Selected Groups");
110 actionNames.put(Graph2DViewActions.OPEN_FOLDERS, "Open Selected Folders");
111 actionNames.put(Graph2DViewActions.GROUP_SELECTION, "Group Selection");
112 actionNames.put(Graph2DViewActions.UNGROUP_SELECTION, "Ungroup Selection");
113 actionNames.put(Graph2DViewActions.FOLD_SELECTION, "Fold Selection");
114
115 actionNames.put("CREATE_NEW_GROUP_NODE_ACTION", "Create Empty Group");
116 actionNames.put("CREATE_NEW_FOLDER_NODE_ACTION", "Create Empty Folder");
117 }
118
119
122 public GroupingDemo() {
123 configureDefaultGroupNodeRealizers();
124 loadInitialGraph();
125 }
126
127 protected void initialize() {
128 createHierarchyManager(view.getGraph2D());
131 }
132
133 protected void loadInitialGraph() {
134 loadGraph("resource/grouping.graphml");
135 }
136
137 protected HierarchyManager createHierarchyManager(Graph2D rootGraph) {
138 return new HierarchyManager(rootGraph);
139 }
140
141 protected void configureDefaultGroupNodeRealizers() {
142 DefaultHierarchyGraphFactory hgf = (DefaultHierarchyGraphFactory) getHierarchyManager().getGraphFactory();
144
145 Map map = GenericGroupNodeRealizer.createDefaultConfigurationMap();
146 GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
147
148 factory.addConfiguration(CONFIGURATION_GROUP, map);
149 Object abf = factory.getImplementation(CONFIGURATION_GROUP,
150 GenericGroupNodeRealizer.GenericAutoBoundsFeature.class);
151 if (abf instanceof DefaultGenericAutoBoundsFeature) {
152 ((DefaultGenericAutoBoundsFeature) abf).setConsiderNodeLabelSize(true);
153 }
154
155 GenericGroupNodeRealizer gnr = new GenericGroupNodeRealizer();
156
157 gnr.setConfiguration(CONFIGURATION_GROUP);
159
160 gnr.setFillColor(new Color(202,236,255,132));
162 gnr.setLineColor(new Color(102, 102,153,255));
163 gnr.setLineType(LineType.DOTTED_1);
164 NodeLabel label = gnr.getLabel();
165 label.setBackgroundColor(new Color(153,204,255,255));
166 label.setTextColor(Color.BLACK);
167 label.setFontSize(15);
168
169 hgf.setProxyNodeRealizerEnabled(true);
170
171 hgf.setDefaultGroupNodeRealizer(gnr.createCopy());
172
173 gnr.setGroupClosed(true);
175 hgf.setDefaultFolderNodeRealizer(gnr.createCopy());
176 }
177
178 protected JMenuBar createMenuBar() {
179 JMenuBar mb = super.createMenuBar();
180 JMenu menu = new JMenu("Grouping");
181 populateGroupingMenu(menu);
182 mb.add(menu);
183 return mb;
184 }
185
186
193 protected void populateGroupingMenu(JMenu hierarchyMenu) {
194 registerAction(hierarchyMenu, Graph2DViewActions.CLOSE_GROUPS, true);
196 registerAction(hierarchyMenu, Graph2DViewActions.OPEN_FOLDERS, true);
197
198 hierarchyMenu.addSeparator();
199
200 registerAction(hierarchyMenu, Graph2DViewActions.GROUP_SELECTION, true);
202 registerAction(hierarchyMenu, Graph2DViewActions.UNGROUP_SELECTION, true);
203 registerAction(hierarchyMenu, Graph2DViewActions.FOLD_SELECTION, true);
204 }
205
206
207 protected EditMode createEditMode() {
208 EditMode mode = super.createEditMode();
209 mode.setPopupMode(createPopupMode());
211 mode.getMouseInputMode().setNodeSearchingEnabled(true);
212
213 ViewMode createEdgeMode = mode.getCreateEdgeMode();
216 if (createEdgeMode instanceof CreateEdgeMode) {
217 ((CreateEdgeMode) createEdgeMode).setIndicatingTargetNode(true);
218 }
219 return mode;
220 }
221
222 protected PopupMode createPopupMode() {
223 return new HierarchicPopupMode();
224 }
225
226
227
230 protected void registerViewActions() {
231 super.registerViewActions();
232
233 ActionMap actionMap = view.getCanvasComponent().getActionMap();
234 actionMap.put(Graph2DViewActions.DELETE_SELECTION, createDeleteSelectionActionImpl());
235 actionMap.put("CREATE_NEW_GROUP_NODE_ACTION", new CreateNewGroupNodeAction());
236 actionMap.put("CREATE_NEW_FOLDER_NODE_ACTION", new CreateNewFolderNodeAction());
237 InputMap inputMap = view.getCanvasComponent().getInputMap();
238 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK), "CREATE_NEW_GROUP_NODE_ACTION");
239 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK), "CREATE_NEW_FOLDER_NODE_ACTION");
240 }
241
242 protected Action createDeleteSelectionAction() {
243 final Action action = createDeleteSelectionActionImpl();
244 action.putValue(Action.SMALL_ICON, getIconResource("resource/delete.png"));
245 action.putValue(Action.SHORT_DESCRIPTION, "Delete Selection");
246 return action;
247 }
248
249
255 private Action createDeleteSelectionActionImpl() {
256 final Graph2DViewActions.DeleteSelectionAction action =
257 new Graph2DViewActions.DeleteSelectionAction(view);
258 action.setKeepingParentGroupNodeSizes(true);
259 return action;
260 }
261
262
263
266 public static void main(String[] args) {
267 EventQueue.invokeLater(new Runnable() {
268 public void run() {
269 Locale.setDefault(Locale.ENGLISH);
270 initLnF();
271 (new GroupingDemo()).start();
272 }
273 });
274 }
275
276
283 protected void populateGroupingPopup(JPopupMenu pm, final double x, final double y, Node node, boolean selected) {
284 registerAction(
286 pm, Graph2DViewActions.CLOSE_GROUPS,
287 node != null && getHierarchyManager().isGroupNode(node));
288 registerAction(
289 pm, Graph2DViewActions.OPEN_FOLDERS,
290 node != null && getHierarchyManager().isFolderNode(node));
291
292 pm.addSeparator();
293
294 registerAction(pm, Graph2DViewActions.GROUP_SELECTION, selected);
296 registerAction(pm, Graph2DViewActions.UNGROUP_SELECTION, selected);
297 registerAction(pm, Graph2DViewActions.FOLD_SELECTION, selected);
298
299 pm.addSeparator();
300
301 JMenuItem item = new JMenuItem(new CreateNewGroupNodeAction(view){
304 protected void setGroupNodeBounds(Graph2DView view, Graph2D graph, Node groupNode) {
305 graph.setLocation(groupNode, x, y);
306 }
307 });
308 item.setText("Create Empty Group");
309 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK));
310 pm.add(item);
311
312 item = new JMenuItem(new CreateNewFolderNodeAction(view){
313 protected void setFolderNodeBounds(Graph2DView view, Graph2D graph, Node groupNode) {
314 graph.setLocation(groupNode, x, y);
315 }
316 });
317 item.setText("Create Empty Folder");
318 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK));
319 pm.add(item);
320 }
321
322
328 protected void registerAction(final Object menu, final Object key, final boolean enabled) {
329 final ActionMap viewActions = view.getCanvasComponent().getActionMap();
330
331 final Action action = viewActions.get(key);
332 if (action != null) {
333 final JMenuItem item = new JMenuItem(action);
334 final String name = (String) actionNames.get(key);
335 if (name != null) {
336 item.setText(name);
337 }
338 item.setEnabled(enabled);
339
340 final InputMap imap = view.getCanvasComponent().getInputMap();
346 final KeyStroke[] keyStrokes = imap.allKeys();
347 if (keyStrokes != null) {
348 for (int i = 0; i < keyStrokes.length; ++i) {
349 if (imap.get(keyStrokes[i]) == key) {
350 item.setAccelerator(keyStrokes[i]);
351 break;
352 }
353 }
354 }
355
356 if (menu instanceof JMenu) {
357 ((JMenu) menu).add(item);
358 } else if (menu instanceof JPopupMenu) {
359 ((JPopupMenu) menu).add(item);
360 }
361 }
362 }
363
364 protected HierarchyManager getHierarchyManager() {
365 return view.getGraph2D().getHierarchyManager();
366 }
367
368
372
375 class HierarchicPopupMode extends PopupMode {
376 public JPopupMenu getPaperPopup(double x, double y) {
377 JPopupMenu pm = new JPopupMenu();
378 populateGroupingPopup(pm, x, y, null, false);
379 return pm;
380 }
381
382 public JPopupMenu getNodePopup(Node v) {
383 Graph2D graph = getGraph2D();
384 JPopupMenu pm = new JPopupMenu();
385 populateGroupingPopup(pm, graph.getCenterX(v), graph.getCenterY(v), v, true);
386 return pm;
387 }
388
389 public JPopupMenu getSelectionPopup(double x, double y) {
390 JPopupMenu pm = new JPopupMenu();
391 populateGroupingPopup(pm, x, y, null, getGraph2D().selectedNodes().ok());
392 return pm;
393 }
394 }
395
396
399 public static class CreateNewGroupNodeAction extends Graph2DViewActions.AbstractGroupingAction {
400
401 public CreateNewGroupNodeAction() {
402 this(null);
403 }
404
405 public CreateNewGroupNodeAction(final Graph2DView view) {
406 super("CREATE_NEW_GROUP_NODE", view);
407 }
408
409 public void actionPerformed(ActionEvent e) {
410 final Graph2DView graph2DView = getView(e);
411 if (graph2DView != null) {
412 createGroupNode(graph2DView);
413 graph2DView.getGraph2D().updateViews();
414 }
415 }
416
417
420 protected Node createGroupNode(Graph2DView view) {
421 final Graph2D graph = view.getGraph2D();
422 graph.firePreEvent();
423 Node groupNode;
424 try {
425 groupNode = createGroupNodeImpl(graph);
426 assignGroupName(groupNode, view);
427 setGroupNodeBounds(view, graph, groupNode);
428 } finally {
429 graph.firePostEvent();
430 }
431 return groupNode;
432 }
433
434 protected Node createGroupNodeImpl(Graph2D graph) {
435 return getHierarchyManager(graph).createGroupNode(graph);
436 }
437
438 protected void setGroupNodeBounds(Graph2DView view, Graph2D graph, Node groupNode) {
439 double x = view.getCenter().getX();
440 double y = view.getCenter().getY();
441 graph.setCenter(groupNode, x, y);
442 }
443
444 protected void assignGroupName(Node groupNode, Graph2DView view) {
445 NodeRealizer nr = view.getGraph2D().getRealizer(groupNode);
446 if (nr instanceof ProxyShapeNodeRealizer) {
447 ProxyShapeNodeRealizer pnr = (ProxyShapeNodeRealizer) nr;
448 pnr.getRealizer(0).setLabelText(createGroupName(groupNode, view));
449 pnr.getRealizer(1).setLabelText(createFolderName(groupNode, view));
450 } else {
451 nr.setLabelText(createGroupName(groupNode, view));
452 }
453 }
454
455 protected String createFolderName(Node folderNode, Graph2DView view) {
456 return "Folder";
457 }
458
459 protected String createGroupName(Node groupNode, Graph2DView view) {
460 return "Group";
461 }
462 }
463
464
467 public static class CreateNewFolderNodeAction extends Graph2DViewActions.AbstractGroupingAction {
468
469 public CreateNewFolderNodeAction() {
470 this(null);
471 }
472
473 public CreateNewFolderNodeAction(final Graph2DView view) {
474 super("CREATE_NEW_FOLDER_NODE", view);
475 }
476
477 public void actionPerformed(ActionEvent e) {
478 final Graph2DView graph2DView = getView(e);
479 if (graph2DView != null) {
480 createFolderNode(graph2DView);
481 graph2DView.getGraph2D().updateViews();
482 }
483 }
484
485
488 protected Node createFolderNode(Graph2DView view) {
489 final Graph2D graph = view.getGraph2D();
490 graph.firePreEvent();
491 Node groupNode;
492 try {
493 groupNode = createFolderNodeImpl(graph);
494 assignFolderName(groupNode, view);
495 setFolderNodeBounds(view, graph, groupNode);
496 } finally {
497 graph.firePostEvent();
498 }
499 return groupNode;
500 }
501
502 protected Node createFolderNodeImpl(Graph2D graph) {
503 return getHierarchyManager(graph).createFolderNode(graph);
504 }
505
506 protected void setFolderNodeBounds(Graph2DView view, Graph2D graph, Node folderNode) {
507 double x = view.getCenter().getX();
508 double y = view.getCenter().getY();
509 graph.setCenter(folderNode, x, y);
510 }
511
512 protected void assignFolderName(Node groupNode, Graph2DView view) {
513 NodeRealizer nr = view.getGraph2D().getRealizer(groupNode);
514 if (nr instanceof ProxyShapeNodeRealizer) {
515 ProxyShapeNodeRealizer pnr = (ProxyShapeNodeRealizer) nr;
516 pnr.getRealizer(0).setLabelText(createGroupName(groupNode, view));
517 pnr.getRealizer(1).setLabelText(createFolderName(groupNode, view));
518 } else {
519 nr.setLabelText(createGroupName(groupNode, view));
520 }
521 }
522
523 protected String createFolderName(Node folderNode, Graph2DView view) {
524 return "Folder";
525 }
526
527 protected String createGroupName(Node groupNode, Graph2DView view) {
528 return "Group";
529 }
530 }
531 }
532