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