1
14 package demo.layout.mixed;
15
16 import demo.view.hierarchy.GroupingDemo;
17 import y.base.DataProvider;
18 import y.base.Edge;
19 import y.base.EdgeCursor;
20 import y.base.EdgeList;
21 import y.base.EdgeMap;
22 import y.layout.LayoutGraph;
23 import y.layout.LayoutTool;
24 import y.layout.Layouter;
25 import y.layout.ParallelEdgeLayouter;
26 import y.layout.circular.CircularLayouter;
27 import y.layout.grouping.RecursiveGroupLayouter;
28 import y.layout.hierarchic.IncrementalHierarchicLayouter;
29 import y.layout.organic.SmartOrganicLayouter;
30 import y.layout.orthogonal.OrthogonalGroupLayouter;
31 import y.layout.router.GroupNodeRouterStage;
32 import y.layout.router.OrthogonalEdgeRouter;
33 import y.util.DataProviderAdapter;
34 import y.view.Graph2D;
35 import y.view.Graph2DLayoutExecutor;
36 import y.view.Graph2DView;
37 import y.view.Graph2DViewActions;
38
39 import javax.swing.AbstractAction;
40 import javax.swing.Action;
41 import javax.swing.ActionMap;
42 import javax.swing.JComboBox;
43 import javax.swing.JMenu;
44 import javax.swing.JToggleButton;
45 import javax.swing.JToolBar;
46 import java.awt.EventQueue;
47 import java.awt.event.ActionEvent;
48 import java.awt.event.ActionListener;
49 import java.util.Locale;
50
51
57 public class RecursiveLayoutDemo extends GroupingDemo {
58 private static final int TYPE_ORTHOGONAL = 0;
59 private static final int TYPE_HIERARCHIC = 1;
60 private static final int TYPE_CIRCULAR = 2;
61 private static final int TYPE_ORGANIC = 3;
62
63 private int layoutType;
64 private boolean useInterEdgeRouter;
65
66 public RecursiveLayoutDemo() {
67 this(null);
68 }
69
70 public RecursiveLayoutDemo(final String helpFilePath) {
71 super();
72 addHelpPane(helpFilePath);
73 }
74
75 protected void loadInitialGraph() {
76 loadGraph("resource/recursive.graphml");
77 }
78
79
82 protected JToolBar createToolBar() {
83 layoutType = TYPE_ORTHOGONAL;
84 final JComboBox layoutTypeSelection = new JComboBox(
85 new String[]{"Orthogonal Style", "Hierarchic Style", "Circular Style", "Organic Style"});
86 layoutTypeSelection.setSelectedIndex(layoutType);
87 layoutTypeSelection.setMaximumSize(layoutTypeSelection.getPreferredSize());
88 layoutTypeSelection.addActionListener(new ActionListener() {
89 public void actionPerformed(ActionEvent e) {
90 switch (layoutTypeSelection.getSelectedIndex()) {
91 default:
92 case 0:
93 layoutType = TYPE_ORTHOGONAL;
94 break;
95 case 1:
96 layoutType = TYPE_HIERARCHIC;
97 break;
98 case 2:
99 layoutType = TYPE_CIRCULAR;
100 break;
101 case 3:
102 layoutType = TYPE_ORGANIC;
103 break;
104 }
105 doLayout();
106 }
107 });
108
109 useInterEdgeRouter = true;
110 final JToggleButton toggleRouteInterEdges = new JToggleButton("Inter-Edge Routing", useInterEdgeRouter);
111 toggleRouteInterEdges.addActionListener(new ActionListener() {
112 public void actionPerformed(ActionEvent e) {
113 useInterEdgeRouter = toggleRouteInterEdges.isSelected();
114 doLayout();
115 }
116 });
117
118 final Action layoutAction = new AbstractAction(
119 "Layout", SHARED_LAYOUT_ICON) {
120 public void actionPerformed(ActionEvent e) {
121 doLayout();
122 }
123 };
124
125 JToolBar toolBar = super.createToolBar();
126 toolBar.addSeparator();
127 toolBar.add(createActionControl(layoutAction));
128 toolBar.addSeparator(TOOLBAR_SMALL_SEPARATOR);
129 toolBar.add(layoutTypeSelection);
130 toolBar.addSeparator(TOOLBAR_SMALL_SEPARATOR);
131 toolBar.add(toggleRouteInterEdges);
132 return toolBar;
133 }
134
135
138 protected void registerViewActions() {
139 super.registerViewActions();
140
141 ActionMap actionMap = view.getCanvasComponent().getActionMap();
142 actionMap.put(Graph2DViewActions.CLOSE_GROUPS, new MyCloseGroupsAction(view));
143 actionMap.put(Graph2DViewActions.OPEN_FOLDERS, new MyOpenFoldersAction(view));
144 }
145
146
149 protected void populateGroupingMenu(JMenu hierarchyMenu) {
150 registerAction(hierarchyMenu, Graph2DViewActions.CLOSE_GROUPS, true);
152 registerAction(hierarchyMenu, Graph2DViewActions.OPEN_FOLDERS, true);
153
154 hierarchyMenu.addSeparator();
155
156 registerAction(hierarchyMenu, Graph2DViewActions.GROUP_SELECTION, true);
158 registerAction(hierarchyMenu, Graph2DViewActions.UNGROUP_SELECTION, true);
159 registerAction(hierarchyMenu, Graph2DViewActions.FOLD_SELECTION, true);
160 }
161
162
165 class MyCloseGroupsAction extends Graph2DViewActions.CloseGroupsAction {
166
167 MyCloseGroupsAction(Graph2DView view) {
168 super(view);
169 }
170
171 public void actionPerformed(ActionEvent e) {
172 super.actionPerformed(e);
173 doLayout();
174 }
175 }
176
177
180 class MyOpenFoldersAction extends Graph2DViewActions.OpenFoldersAction {
181
182 MyOpenFoldersAction(Graph2DView view) {
183 super(view);
184 }
185
186 public void actionPerformed(ActionEvent e) {
187 super.actionPerformed(e);
188 doLayout();
189 }
190 }
191
192 void doLayout() {
193 final RecursiveGroupLayouter rgl;
194 final Layouter coreLayout;
195
196 if (layoutType == TYPE_ORTHOGONAL) {
197 coreLayout = new OrthogonalGroupLayouter();
198 rgl = createOrthogonalRecursiveGroupLayout(coreLayout, OrthogonalEdgeRouter.MONOTONIC_NONE);
199
200 } else if (layoutType == TYPE_HIERARCHIC) {
201 final IncrementalHierarchicLayouter ihl = new IncrementalHierarchicLayouter();
202 ihl.setOrthogonallyRouted(true);
203 coreLayout = ihl;
204 rgl = createOrthogonalRecursiveGroupLayout(coreLayout, OrthogonalEdgeRouter.MONOTONIC_VERTICAL);
205
206 } else if (layoutType == TYPE_ORGANIC) {
207 coreLayout = new SmartOrganicLayouter();
208 rgl = createRecursiveGroupLayout(coreLayout);
209 rgl.setAutoAssignPortCandidatesEnabled(true);
210
211 } else {
212 final CircularLayouter cl = new CircularLayouter();
213 cl.setParallelEdgeLayouter(createParallelEdgeLayouter());
214
215 coreLayout = cl;
216 rgl = createRecursiveGroupLayout(coreLayout);
217 }
218
219 final Graph2D graph = view.getGraph2D();
220 try {
221 graph.addDataProvider(RecursiveGroupLayouter.GROUP_NODE_LAYOUTER_DPKEY, new DataProviderAdapter() {
223 public Object get(Object dataHolder) {
224 return coreLayout;
225 }
226 });
227
228 new Graph2DLayoutExecutor().doLayout(view, rgl);
229 view.fitContent();
230
231 } finally {
232 graph.removeDataProvider(RecursiveGroupLayouter.GROUP_NODE_LAYOUTER_DPKEY);
233 }
234 }
235
236 RecursiveGroupLayouter createOrthogonalRecursiveGroupLayout(Layouter coreLayout, final byte monotonicPathType) {
237 final RecursiveGroupLayouter rgl = new RecursiveGroupLayouter(coreLayout) {
238 protected void routeInterEdges(LayoutGraph graph, EdgeList interEdges) {
239 if (useInterEdgeRouter) {
240 DataProvider selectedEdges = graph.getDataProvider(Layouter.SELECTED_EDGES);
242 EdgeMap edge2IsInterEdge = graph.createEdgeMap();
243 for (EdgeCursor ec = interEdges.edges(); ec.ok(); ec.next()) {
244 edge2IsInterEdge.setBool(ec.edge(), true);
245 }
246 graph.addDataProvider(Layouter.SELECTED_EDGES, edge2IsInterEdge);
247
248 OrthogonalEdgeRouter oer = createOrthogonalEdgeRouter();
250 if (monotonicPathType != OrthogonalEdgeRouter.MONOTONIC_NONE) {
251 oer.setMonotonicPathRestriction(monotonicPathType);
252 }
253 new GroupNodeRouterStage(oer).doLayout(graph);
254
255 if (selectedEdges != null) {
257 graph.addDataProvider(Layouter.SELECTED_EDGES, selectedEdges);
258 } else {
259 graph.removeDataProvider(Layouter.SELECTED_EDGES);
260 }
261 graph.disposeEdgeMap(edge2IsInterEdge);
262 } else {
263 super.routeInterEdges(graph, interEdges);
264 }
265 }
266 };
267
268 rgl.setConsiderSketchEnabled(true);
269
270 return rgl;
271 }
272
273 RecursiveGroupLayouter createRecursiveGroupLayout(Layouter coreLayout) {
274 RecursiveGroupLayouter rgl = new RecursiveGroupLayouter(coreLayout) {
275 protected void routeInterEdges(LayoutGraph graph, EdgeList interEdges) {
276 if (useInterEdgeRouter) {
277 EdgeMap edge2IsInterEdge = graph.createEdgeMap();
279 for (EdgeCursor ec = interEdges.edges(); ec.ok(); ec.next()) {
280 Edge e = ec.edge();
281 edge2IsInterEdge.setBool(e, true);
282 LayoutTool.resetPath(graph, e);
283 }
284
285 graph.addDataProvider(ParallelEdgeLayouter.SCOPE_DPKEY, edge2IsInterEdge);
287 createParallelEdgeLayouter().doLayout(graph);
288 graph.removeDataProvider(ParallelEdgeLayouter.SCOPE_DPKEY);
289 graph.disposeEdgeMap(edge2IsInterEdge);
290 } else {
291 super.routeInterEdges(graph, interEdges);
292 }
293 }
294 };
295
296 rgl.setConsiderSketchEnabled(true);
297
298 return rgl;
299 }
300
301 static OrthogonalEdgeRouter createOrthogonalEdgeRouter() {
302 OrthogonalEdgeRouter oer = new OrthogonalEdgeRouter();
303 oer.setCrossingCost(2.0);
304 oer.setLocalCrossingMinimizationEnabled(true);
305 oer.setReroutingEnabled(true);
306 oer.setSphereOfAction(OrthogonalEdgeRouter.ROUTE_SELECTED_EDGES);
307 return oer;
308 }
309
310 static ParallelEdgeLayouter createParallelEdgeLayouter() {
311 ParallelEdgeLayouter pel = new ParallelEdgeLayouter();
312 pel.setLineDistance(10.0);
313 pel.setJoinEndsEnabled(true);
314 return pel;
315 }
316
317
320 public static void main(String[] args) {
321 EventQueue.invokeLater(new Runnable() {
322 public void run() {
323 Locale.setDefault(Locale.ENGLISH);
324 initLnF();
325 new RecursiveLayoutDemo("resource/recursivelayouthelp.html").start();
326 }
327 });
328 }
329 }
330