1
28 package demo.layout.hierarchic;
29
30 import demo.view.hierarchy.GroupingDemo;
31 import y.base.DataMap;
32 import y.base.DataProvider;
33 import y.base.Edge;
34 import y.base.EdgeCursor;
35 import y.base.EdgeMap;
36 import y.base.Node;
37 import y.base.NodeCursor;
38 import y.base.NodeMap;
39 import y.layout.PortConstraint;
40 import y.layout.PortConstraintKeys;
41 import y.layout.hierarchic.IncrementalHierarchicLayouter;
42 import y.layout.hierarchic.incremental.EdgeLayoutDescriptor;
43 import y.layout.hierarchic.incremental.IncrementalHintsFactory;
44 import y.module.PortConstraintModule;
45 import y.util.Maps;
46 import y.view.Graph2D;
47 import y.view.Graph2DLayoutExecutor;
48 import y.view.Graph2DViewActions;
49 import y.view.hierarchy.HierarchyManager;
50
51 import javax.swing.AbstractAction;
52 import javax.swing.Action;
53 import javax.swing.JLabel;
54 import javax.swing.JToolBar;
55 import java.awt.EventQueue;
56 import java.awt.event.ActionEvent;
57 import java.util.Locale;
58
59
60
69 public class IncrementalHierarchicFoldExpandDemo extends GroupingDemo {
70
71 private final IncrementalHierarchicLayouter layouter;
72 private PortConstraintModule pcModule;
73
74 public IncrementalHierarchicFoldExpandDemo() {
75
76 layouter = new IncrementalHierarchicLayouter();
78 layouter.setOrthogonallyRouted(true);
79 layouter.setRecursiveGroupLayeringEnabled(true);
80 layouter.getEdgeLayoutDescriptor().setRecursiveEdgeStyle(EdgeLayoutDescriptor.RECURSIVE_EDGE_STYLE_DIRECTED);
81 layouter.setMinimumLayerDistance(40);
82
83 pcModule = new PortConstraintModule();
85
86 view.fitContent();
87 }
88
89
92 protected void registerViewActions() {
93 super.registerViewActions();
94 view.getCanvasComponent().getActionMap().put(Graph2DViewActions.CLOSE_GROUPS, new CloseGroupsAndLayoutAction());
95 view.getCanvasComponent().getActionMap().put(Graph2DViewActions.OPEN_FOLDERS, new OpenFoldersAndLayoutAction());
96 }
97
98
102 class OpenFoldersAndLayoutAction extends Graph2DViewActions.OpenFoldersAction {
103
104 OpenFoldersAndLayoutAction() {
105 super(IncrementalHierarchicFoldExpandDemo.this.view);
106 }
107
108 public void openFolder(Node folderNode, Graph2D graph) {
109 final NodeMap alternativeBounds = Maps.createHashedNodeMap();
111 alternativeBounds.set(folderNode, graph.getRectangle(folderNode));
112 graph.addDataProvider(IncrementalHierarchicLayouter.ALTERNATIVE_GROUP_BOUNDS_DPKEY, alternativeBounds);
113
114 final EdgeMap alternativePathMap = Maps.createHashedEdgeMap();
116 for (EdgeCursor edgeCursor = folderNode.edges(); edgeCursor.ok(); edgeCursor.next()) {
117 final Edge edge = edgeCursor.edge();
118 alternativePathMap.set(edge, graph.getPath(edge));
119 }
120 graph.addDataProvider(IncrementalHierarchicLayouter.ALTERNATIVE_EDGE_PATH_DPKEY, alternativePathMap);
121
122 super.openFolder(folderNode, graph);
123
124 layoutIncrementally(null);
125
126 graph.removeDataProvider(IncrementalHierarchicLayouter.ALTERNATIVE_GROUP_BOUNDS_DPKEY);
127 graph.removeDataProvider(IncrementalHierarchicLayouter.ALTERNATIVE_EDGE_PATH_DPKEY);
128
129 graph.setSelected(folderNode, true);
130 graph.updateViews();
131 }
132 }
133
134
138 class CloseGroupsAndLayoutAction extends Graph2DViewActions.CloseGroupsAction {
139
140 CloseGroupsAndLayoutAction() {
141 super(IncrementalHierarchicFoldExpandDemo.this.view);
142 }
143
144 public void closeGroup(Node groupNode, Graph2D graph) {
145 final NodeMap alternativeBounds = Maps.createHashedNodeMap();
147 alternativeBounds.set(groupNode, graph.getRectangle(groupNode));
148 graph.addDataProvider(IncrementalHierarchicLayouter.ALTERNATIVE_GROUP_BOUNDS_DPKEY, alternativeBounds);
149
150 final EdgeMap alternativePathMap = Maps.createHashedEdgeMap();
152 final HierarchyManager hm = graph.getHierarchyManager();
153 for (EdgeCursor edgeCursor = graph.edges(); edgeCursor.ok(); edgeCursor.next()) {
154 final Edge edge = edgeCursor.edge();
155 final Node source = edge.source();
156 final Node target = edge.target();
157
158 if (hm.isAncestor(groupNode, source) || hm.isAncestor(groupNode, target)
159 || source == groupNode || target == groupNode){
160 alternativePathMap.set(edge, graph.getPath(edge));
161 }
162 }
163 graph.addDataProvider(IncrementalHierarchicLayouter.ALTERNATIVE_EDGE_PATH_DPKEY, alternativePathMap);
164
165 super.closeGroup(groupNode, graph);
166
167 layoutIncrementally(null);
168
169 graph.removeDataProvider(IncrementalHierarchicLayouter.ALTERNATIVE_GROUP_BOUNDS_DPKEY);
170 graph.removeDataProvider(IncrementalHierarchicLayouter.ALTERNATIVE_EDGE_PATH_DPKEY);
171
172 graph.updateViews();
173 }
174 }
175
176
177
180 protected void loadInitialGraph() {
181 loadGraph("resource/IncrementalHierarchicGroupDemo.graphml");
182 }
183
184
187 protected JToolBar createToolBar() {
188 final JToolBar toolBar = super.createToolBar();
189 addLayoutActions(toolBar);
190 toolBar.addSeparator();
191 toolBar.add(new PortConstraintConfigurationAction());
192 return toolBar;
193 }
194
195 protected void addLayoutActions(JToolBar toolBar) {
196 final Action incrementalLayoutAction = new AbstractAction(
197 "Incremental", SHARED_LAYOUT_ICON) {
198 public void actionPerformed(ActionEvent e) {
199 layoutIncrementally();
200 }
201 };
202
203 final Action layoutAction = new AbstractAction(
204 "Complete", SHARED_LAYOUT_ICON) {
205 public void actionPerformed(ActionEvent e) {
206 layout();
207 }
208 };
209
210 toolBar.addSeparator();
211 toolBar.add(new JLabel("Layout: "));
212 toolBar.add(createActionControl(incrementalLayoutAction));
213 toolBar.add(createActionControl(layoutAction));
214 }
215
216
219 class PortConstraintConfigurationAction extends AbstractAction {
220 PortConstraintConfigurationAction() {
221 super("Port Constraints");
222 }
223
224 public void actionPerformed(ActionEvent ev) {
225 pcModule.getOptionHandler().showEditor();
226 pcModule.start(view.getGraph2D());
227 }
228 }
229
230
233 void layoutIncrementally() {
234 final Graph2D graph = view.getGraph2D();
235
236 final DataMap incrementalElements = Maps.createHashedDataMap();
238 final IncrementalHintsFactory ihf = layouter.createIncrementalHintsFactory();
240
241 for (NodeCursor nc = graph.selectedNodes(); nc.ok(); nc.next()) {
242 incrementalElements.set(nc.node(), ihf.createLayerIncrementallyHint(nc.node()));
243 }
244
245 for (EdgeCursor ec = graph.selectedEdges(); ec.ok(); ec.next()) {
246 incrementalElements.set(ec.edge(), ihf.createSequenceIncrementallyHint(ec.edge()));
247 }
248
249 layoutIncrementally(incrementalElements);
250
251 graph.removeDataProvider(IncrementalHierarchicLayouter.FOLDER_NODES_DPKEY);
252 }
253
254
257 void layoutIncrementally(DataMap incrementalElements) {
258 final Graph2D graph = view.getGraph2D();
259
260 final NodeMap folderNodes = getFolderNodes(graph);
262 graph.addDataProvider(IncrementalHierarchicLayouter.FOLDER_NODES_DPKEY, folderNodes);
263
264 layouter.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_INCREMENTAL);
265
266 if (incrementalElements != null) {
267 graph.addDataProvider(IncrementalHierarchicLayouter.INCREMENTAL_HINTS_DPKEY, incrementalElements);
268 }
269
270 final DataProvider spcProvider = graph.getDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY);
272 final DataProvider tpcProvider = graph.getDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY);
273 removePortConstraintsAtInterEdges(graph, spcProvider, tpcProvider);
274
275 try {
276 final Graph2DLayoutExecutor layoutExecutor = new Graph2DLayoutExecutor();
277 layoutExecutor.getLayoutMorpher().setSmoothViewTransform(true);
278 layoutExecutor.doLayout(view, layouter);
279 } finally {
280 if (incrementalElements != null) {
281 graph.removeDataProvider(IncrementalHierarchicLayouter.INCREMENTAL_HINTS_DPKEY);
282 }
283 graph.removeDataProvider(IncrementalHierarchicLayouter.FOLDER_NODES_DPKEY);
284
285 if (spcProvider != null) {
287 graph.addDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY, spcProvider);
288 }
289 if (tpcProvider != null) {
290 graph.addDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY, tpcProvider);
291 }
292 }
293 }
294
295
296
299 void layout() {
300 final Graph2D graph = view.getGraph2D();
301 final NodeMap folderNodes = getFolderNodes(graph);
303 graph.addDataProvider(IncrementalHierarchicLayouter.FOLDER_NODES_DPKEY, folderNodes);
304
305 layouter.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_FROM_SCRATCH);
306 final Graph2DLayoutExecutor layoutExecutor = new Graph2DLayoutExecutor();
307 layoutExecutor.getLayoutMorpher().setSmoothViewTransform(true);
308 layoutExecutor.doLayout(view, layouter);
309
310 graph.removeDataProvider(IncrementalHierarchicLayouter.FOLDER_NODES_DPKEY);
311 }
312
313
327 private void removePortConstraintsAtInterEdges(Graph2D graph, DataProvider spcProvider, DataProvider tpcProvider) {
328 final HierarchyManager hm = graph.getHierarchyManager();
329
330 if (hm == null || (spcProvider == null && tpcProvider == null)) {
331 return;
333 }
334
335
336 final EdgeMap tmpSpcProvider = Maps.createHashedEdgeMap();
337 final EdgeMap tmpTpcProvider = Maps.createHashedEdgeMap();
338 for (EdgeCursor edgeCursor = graph.edges(); edgeCursor.ok(); edgeCursor.next()) {
339 final Edge edge = edgeCursor.edge();
340 if (spcProvider != null) {
341 final PortConstraint spc = (PortConstraint) spcProvider.get(edge);
342 final Node source = edge.source();
343 if (spc != null && hm.isFolderNode(source) && hm.isInterEdge(edge) && hm.getRealSource(edge) != source) {
344 tmpSpcProvider.set(edge, null);
347 } else {
348 tmpSpcProvider.set(edge, spc);
349 }
350 }
351 if (tpcProvider != null) {
352 final PortConstraint tpc = (PortConstraint) tpcProvider.get(edge);
353 final Node target = edge.target();
354 if (tpc != null && hm.isFolderNode(target) && hm.isInterEdge(edge) && hm.getRealTarget(edge) != target) {
355 tmpTpcProvider.set(edge, null);
358 } else {
359 tmpTpcProvider.set(edge, tpc);
360 }
361 }
362 }
363
364 if (spcProvider != null) {
366 graph.addDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY, tmpSpcProvider);
367 }
368 if (tpcProvider != null) {
369 graph.addDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY, tmpTpcProvider);
370 }
371 }
372
373
376 private NodeMap getFolderNodes(Graph2D graph) {
377 final HierarchyManager hierarchy = graph.getHierarchyManager();
378 final NodeMap folderNodes = Maps.createHashedNodeMap();
379 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
380 final Node node = nc.node();
381 if (hierarchy.isFolderNode(node)) {
382 folderNodes.setBool(node, true);
383 }
384 }
385 return folderNodes;
386 }
387
388
392 public static void main(String[] args) {
393 EventQueue.invokeLater(new Runnable() {
394 public void run() {
395 Locale.setDefault(Locale.ENGLISH);
396 initLnF();
397 (new IncrementalHierarchicFoldExpandDemo()).start();
398 }
399 });
400 }
401 }
402