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