1
14 package demo.view.hierarchy;
15
16 import demo.view.DemoBase;
17 import y.base.Node;
18 import y.view.CreateEdgeMode;
19 import y.view.EditMode;
20 import y.view.GenericNodeRealizer;
21 import y.view.Graph2D;
22 import y.view.Graph2DView;
23 import y.view.Graph2DViewActions;
24 import y.view.NodeRealizer;
25 import y.view.PopupMode;
26 import y.view.ProxyShapeNodeRealizer;
27 import y.view.ViewMode;
28 import y.view.NodeLabel;
29 import y.view.LineType;
30 import y.view.hierarchy.DefaultGenericAutoBoundsFeature;
31 import y.view.hierarchy.DefaultHierarchyGraphFactory;
32 import y.view.hierarchy.GenericGroupNodeRealizer;
33 import y.view.hierarchy.HierarchyManager;
34
35 import javax.swing.Action;
36 import javax.swing.ActionMap;
37 import javax.swing.InputMap;
38 import javax.swing.JMenu;
39 import javax.swing.JMenuBar;
40 import javax.swing.JMenuItem;
41 import javax.swing.JPopupMenu;
42 import javax.swing.KeyStroke;
43 import java.awt.event.ActionEvent;
44 import java.awt.event.KeyEvent;
45 import java.awt.event.InputEvent;
46 import java.awt.Color;
47 import java.awt.EventQueue;
48 import java.util.HashMap;
49 import java.util.Locale;
50 import java.util.Map;
51
52
89 public class GroupingDemo extends DemoBase {
90
91
92 public static final String CONFIGURATION_GROUP = "GroupingDemo_GROUP_NODE";
93
94 protected static final Map actionNames;
95 static {
96 actionNames = new HashMap();
97 actionNames.put(Graph2DViewActions.CLOSE_GROUPS, "Close Selected Groups");
98 actionNames.put(Graph2DViewActions.OPEN_FOLDERS, "Open Selected Folders");
99 actionNames.put(Graph2DViewActions.GROUP_SELECTION, "Group Selection");
100 actionNames.put(Graph2DViewActions.UNGROUP_SELECTION, "Ungroup Selection");
101 actionNames.put(Graph2DViewActions.FOLD_SELECTION, "Fold Selection");
102
103 actionNames.put("CREATE_NEW_GROUP_NODE_ACTION", "Create Empty Group");
104 actionNames.put("CREATE_NEW_FOLDER_NODE_ACTION", "Create Empty Folder");
105 }
106
107
110 public GroupingDemo() {
111 Graph2D rootGraph = view.getGraph2D();
112 createHierarchyManager(rootGraph);
114 configureDefaultGroupNodeRealizers();
115 loadInitialGraph();
116 }
117
118 protected void loadInitialGraph() {
119 loadGraph("resource/grouping.graphml");
120 }
121
122 protected HierarchyManager createHierarchyManager(Graph2D rootGraph) {
123 return new HierarchyManager(rootGraph);
124 }
125
126 protected void configureDefaultGroupNodeRealizers() {
127 DefaultHierarchyGraphFactory hgf = (DefaultHierarchyGraphFactory) getHierarchyManager().getGraphFactory();
129
130 Map map = GenericGroupNodeRealizer.createDefaultConfigurationMap();
131 GenericNodeRealizer.Factory factory = GenericNodeRealizer.getFactory();
132
133 factory.addConfiguration(CONFIGURATION_GROUP, map);
134 Object abf = factory.getImplementation(CONFIGURATION_GROUP,
135 GenericGroupNodeRealizer.GenericAutoBoundsFeature.class);
136 if (abf instanceof DefaultGenericAutoBoundsFeature) {
137 ((DefaultGenericAutoBoundsFeature) abf).setConsiderNodeLabelSize(true);
138 }
139
140 GenericGroupNodeRealizer gnr = new GenericGroupNodeRealizer();
141
142 gnr.setConfiguration(CONFIGURATION_GROUP);
144
145 gnr.setFillColor(new Color(202,236,255,132));
147 gnr.setLineColor(new Color(102, 102,153,255));
148 gnr.setLineType(LineType.DOTTED_1);
149 NodeLabel label = gnr.getLabel();
150 label.setBackgroundColor(new Color(153,204,255,255));
151 label.setTextColor(Color.BLACK);
152 label.setFontSize(15);
153
154 hgf.setProxyNodeRealizerEnabled(true);
155
156 hgf.setDefaultGroupNodeRealizer(gnr.createCopy());
157
158 gnr.setGroupClosed(true);
160 hgf.setDefaultFolderNodeRealizer(gnr.createCopy());
161 }
162
163 protected JMenuBar createMenuBar() {
164 JMenuBar mb = super.createMenuBar();
165 JMenu menu = new JMenu("Grouping");
166 populateGroupingMenu(menu);
167 mb.add(menu);
168 return mb;
169 }
170
171
178 protected void populateGroupingMenu(JMenu hierarchyMenu) {
179 registerAction(hierarchyMenu, Graph2DViewActions.CLOSE_GROUPS, true);
181 registerAction(hierarchyMenu, Graph2DViewActions.OPEN_FOLDERS, true);
182
183 hierarchyMenu.addSeparator();
184
185 registerAction(hierarchyMenu, Graph2DViewActions.GROUP_SELECTION, true);
187 registerAction(hierarchyMenu, Graph2DViewActions.UNGROUP_SELECTION, true);
188 registerAction(hierarchyMenu, Graph2DViewActions.FOLD_SELECTION, true);
189 }
190
191
192 protected EditMode createEditMode() {
193 EditMode mode = super.createEditMode();
194 mode.setPopupMode(createPopupMode());
196 mode.getMouseInputMode().setNodeSearchingEnabled(true);
197
198 ViewMode createEdgeMode = mode.getCreateEdgeMode();
201 if (createEdgeMode instanceof CreateEdgeMode) {
202 ((CreateEdgeMode) createEdgeMode).setIndicatingTargetNode(true);
203 }
204 return mode;
205 }
206
207 protected PopupMode createPopupMode() {
208 return new HierarchicPopupMode();
209 }
210
211
212
215 protected void registerViewActions() {
216 super.registerViewActions();
217
218 ActionMap actionMap = view.getCanvasComponent().getActionMap();
219 actionMap.put(Graph2DViewActions.DELETE_SELECTION, createDeleteSelectionActionImpl());
220 actionMap.put("CREATE_NEW_GROUP_NODE_ACTION", new CreateNewGroupNodeAction());
221 actionMap.put("CREATE_NEW_FOLDER_NODE_ACTION", new CreateNewFolderNodeAction());
222 InputMap inputMap = view.getCanvasComponent().getInputMap();
223 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK), "CREATE_NEW_GROUP_NODE_ACTION");
224 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK), "CREATE_NEW_FOLDER_NODE_ACTION");
225 }
226
227 protected Action createDeleteSelectionAction() {
228 final Action action = createDeleteSelectionActionImpl();
229 action.putValue(Action.SMALL_ICON, getIconResource("resource/delete.png"));
230 action.putValue(Action.SHORT_DESCRIPTION, "Delete Selection");
231 return action;
232 }
233
234
240 private Action createDeleteSelectionActionImpl() {
241 final Graph2DViewActions.DeleteSelectionAction action =
242 new Graph2DViewActions.DeleteSelectionAction(view);
243 action.setKeepingParentGroupNodeSizes(true);
244 return action;
245 }
246
247
248
251 public static void main(String[] args) {
252 EventQueue.invokeLater(new Runnable() {
253 public void run() {
254 Locale.setDefault(Locale.ENGLISH);
255 initLnF();
256 (new GroupingDemo()).start();
257 }
258 });
259 }
260
261
268 protected void populateGroupingPopup(JPopupMenu pm, final double x, final double y, Node node, boolean selected) {
269 registerAction(
271 pm, Graph2DViewActions.CLOSE_GROUPS,
272 node != null && getHierarchyManager().isGroupNode(node));
273 registerAction(
274 pm, Graph2DViewActions.OPEN_FOLDERS,
275 node != null && getHierarchyManager().isFolderNode(node));
276
277 pm.addSeparator();
278
279 registerAction(pm, Graph2DViewActions.GROUP_SELECTION, selected);
281 registerAction(pm, Graph2DViewActions.UNGROUP_SELECTION, selected);
282 registerAction(pm, Graph2DViewActions.FOLD_SELECTION, selected);
283
284 pm.addSeparator();
285
286 JMenuItem item = new JMenuItem(new CreateNewGroupNodeAction(view){
289 protected void setGroupNodeBounds(Graph2DView view, Graph2D graph, Node groupNode) {
290 graph.setLocation(groupNode, x, y);
291 }
292 });
293 item.setText("Create Empty Group");
294 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK));
295 pm.add(item);
296
297 item = new JMenuItem(new CreateNewFolderNodeAction(view){
298 protected void setFolderNodeBounds(Graph2DView view, Graph2D graph, Node groupNode) {
299 graph.setLocation(groupNode, x, y);
300 }
301 });
302 item.setText("Create Empty Folder");
303 item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK));
304 pm.add(item);
305 }
306
307
313 protected void registerAction(final Object menu, final Object key, final boolean enabled) {
314 final ActionMap viewActions = view.getCanvasComponent().getActionMap();
315
316 final Action action = viewActions.get(key);
317 if (action != null) {
318 final JMenuItem item = new JMenuItem(action);
319 final String name = (String) actionNames.get(key);
320 if (name != null) {
321 item.setText(name);
322 }
323 item.setEnabled(enabled);
324
325 final InputMap imap = view.getCanvasComponent().getInputMap();
331 final KeyStroke[] keyStrokes = imap.allKeys();
332 if (keyStrokes != null) {
333 for (int i = 0; i < keyStrokes.length; ++i) {
334 if (imap.get(keyStrokes[i]) == key) {
335 item.setAccelerator(keyStrokes[i]);
336 break;
337 }
338 }
339 }
340
341 if (menu instanceof JMenu) {
342 ((JMenu) menu).add(item);
343 } else if (menu instanceof JPopupMenu) {
344 ((JPopupMenu) menu).add(item);
345 }
346 }
347 }
348
349 protected HierarchyManager getHierarchyManager() {
350 return view.getGraph2D().getHierarchyManager();
351 }
352
353
357
360 class HierarchicPopupMode extends PopupMode {
361 public JPopupMenu getPaperPopup(double x, double y) {
362 JPopupMenu pm = new JPopupMenu();
363 populateGroupingPopup(pm, x, y, null, false);
364 return pm;
365 }
366
367 public JPopupMenu getNodePopup(Node v) {
368 Graph2D graph = getGraph2D();
369 JPopupMenu pm = new JPopupMenu();
370 populateGroupingPopup(pm, graph.getCenterX(v), graph.getCenterY(v), v, true);
371 return pm;
372 }
373
374 public JPopupMenu getSelectionPopup(double x, double y) {
375 JPopupMenu pm = new JPopupMenu();
376 populateGroupingPopup(pm, x, y, null, getGraph2D().selectedNodes().ok());
377 return pm;
378 }
379 }
380
381
384 public static class CreateNewGroupNodeAction extends Graph2DViewActions.AbstractGroupingAction {
385
386 public CreateNewGroupNodeAction() {
387 this(null);
388 }
389
390 public CreateNewGroupNodeAction(final Graph2DView view) {
391 super("CREATE_NEW_GROUP_NODE", view);
392 }
393
394 public void actionPerformed(ActionEvent e) {
395 final Graph2DView graph2DView = getView(e);
396 if (graph2DView != null) {
397 createGroupNode(graph2DView);
398 graph2DView.getGraph2D().updateViews();
399 }
400 }
401
402
405 protected Node createGroupNode(Graph2DView view) {
406 final Graph2D graph = view.getGraph2D();
407 graph.firePreEvent();
408 Node groupNode;
409 try {
410 groupNode = createGroupNodeImpl(graph);
411 assignGroupName(groupNode, view);
412 setGroupNodeBounds(view, graph, groupNode);
413 } finally {
414 graph.firePostEvent();
415 }
416 return groupNode;
417 }
418
419 protected Node createGroupNodeImpl(Graph2D graph) {
420 return getHierarchyManager(graph).createGroupNode(graph);
421 }
422
423 protected void setGroupNodeBounds(Graph2DView view, Graph2D graph, Node groupNode) {
424 double x = view.getCenter().getX();
425 double y = view.getCenter().getY();
426 graph.setCenter(groupNode, x, y);
427 }
428
429 protected void assignGroupName(Node groupNode, Graph2DView view) {
430 NodeRealizer nr = view.getGraph2D().getRealizer(groupNode);
431 if (nr instanceof ProxyShapeNodeRealizer) {
432 ProxyShapeNodeRealizer pnr = (ProxyShapeNodeRealizer) nr;
433 pnr.getRealizer(0).setLabelText(createGroupName(groupNode, view));
434 pnr.getRealizer(1).setLabelText(createFolderName(groupNode, view));
435 } else {
436 nr.setLabelText(createGroupName(groupNode, view));
437 }
438 }
439
440 protected String createFolderName(Node folderNode, Graph2DView view) {
441 return "Folder";
442 }
443
444 protected String createGroupName(Node groupNode, Graph2DView view) {
445 return "Group";
446 }
447 }
448
449
452 public static class CreateNewFolderNodeAction extends Graph2DViewActions.AbstractGroupingAction {
453
454 public CreateNewFolderNodeAction() {
455 this(null);
456 }
457
458 public CreateNewFolderNodeAction(final Graph2DView view) {
459 super("CREATE_NEW_FOLDER_NODE", view);
460 }
461
462 public void actionPerformed(ActionEvent e) {
463 final Graph2DView graph2DView = getView(e);
464 if (graph2DView != null) {
465 createFolderNode(graph2DView);
466 graph2DView.getGraph2D().updateViews();
467 }
468 }
469
470
473 protected Node createFolderNode(Graph2DView view) {
474 final Graph2D graph = view.getGraph2D();
475 graph.firePreEvent();
476 Node groupNode;
477 try {
478 groupNode = createFolderNodeImpl(graph);
479 assignFolderName(groupNode, view);
480 setFolderNodeBounds(view, graph, groupNode);
481 } finally {
482 graph.firePostEvent();
483 }
484 return groupNode;
485 }
486
487 protected Node createFolderNodeImpl(Graph2D graph) {
488 return getHierarchyManager(graph).createFolderNode(graph);
489 }
490
491 protected void setFolderNodeBounds(Graph2DView view, Graph2D graph, Node folderNode) {
492 double x = view.getCenter().getX();
493 double y = view.getCenter().getY();
494 graph.setCenter(folderNode, x, y);
495 }
496
497 protected void assignFolderName(Node groupNode, Graph2DView view) {
498 NodeRealizer nr = view.getGraph2D().getRealizer(groupNode);
499 if (nr instanceof ProxyShapeNodeRealizer) {
500 ProxyShapeNodeRealizer pnr = (ProxyShapeNodeRealizer) nr;
501 pnr.getRealizer(0).setLabelText(createGroupName(groupNode, view));
502 pnr.getRealizer(1).setLabelText(createFolderName(groupNode, view));
503 } else {
504 nr.setLabelText(createGroupName(groupNode, view));
505 }
506 }
507
508 protected String createFolderName(Node folderNode, Graph2DView view) {
509 return "Folder";
510 }
511
512 protected String createGroupName(Node groupNode, Graph2DView view) {
513 return "Group";
514 }
515 }
516 }
517