1   
28  package demo.layout.mixed;
29  
30  import y.base.Node;
31  import y.base.NodeMap;
32  import y.base.YList;
33  import y.base.NodeCursor;
34  import y.util.Comparators;
35  import y.view.Graph2D;
36  import y.view.NodeRealizer;
37  import y.view.Graph2DLayoutExecutor;
38  import y.view.Graph2DViewActions;
39  import y.view.hierarchy.GroupLayoutConfigurator;
40  import y.layout.grouping.RecursiveGroupLayouter;
41  import y.layout.grouping.Grouping;
42  import y.layout.Layouter;
43  import y.layout.PortCandidate;
44  import y.layout.LayoutOrientation;
45  import y.layout.LayoutMultiplexer;
46  import y.layout.LayoutGraph;
47  import y.layout.tree.TreeReductionStage;
48  import y.layout.tree.TreeLayouter;
49  import y.layout.hierarchic.IncrementalHierarchicLayouter;
50  import y.layout.hierarchic.GivenLayersLayerer;
51  import y.layout.hierarchic.incremental.NodeLayoutDescriptor;
52  import y.layout.hierarchic.incremental.HierarchicLayouter;
53  import y.layout.hierarchic.incremental.LayerConstraintFactory;
54  import y.util.DataProviderAdapter;
55  import y.util.DataProviders;
56  import y.util.Maps;
57  
58  import javax.swing.AbstractButton;
59  import javax.swing.Action;
60  import javax.swing.JToggleButton;
61  import javax.swing.JToolBar;
62  import javax.swing.AbstractAction;
63  import javax.swing.ActionMap;
64  import java.awt.event.ActionEvent;
65  import java.awt.EventQueue;
66  import java.util.Arrays;
67  import java.util.Comparator;
68  import java.util.Locale;
69  
70  import demo.view.hierarchy.GroupingDemo;
71  
72  
85  public class MixedLayoutDemo extends GroupingDemo {
86    static final int TABLE_MODE = 0;
87    static final int THREE_TIER_MODE = 1;
88  
89    private static final byte COMMON_NODE = 0;
90    private static final byte LEFT_TREE_GROUP_NODE = 1;
91    private static final byte LEFT_TREE_CONTENT_NODE = 2;
92    private static final byte RIGHT_TREE_GROUP_NODE = 3;
93    private static final byte RIGHT_TREE_CONTENT_NODE = 4;
94  
95    int mode;
96    boolean fromSketch;
97  
98    public MixedLayoutDemo() {
99      this(null);
100   }
101 
102   public MixedLayoutDemo( final String helpFilePath ) {
103     super();
104     addHelpPane(helpFilePath);
105   }
106 
107   protected void loadInitialGraph() {
108     loadGraph("resource/threetier.graphml");
109   }
110 
111   protected String[] getExampleResources() {
112     return new String[]{"resource/threetier.graphml", "resource/table.graphml"};
113   }
114 
115   protected JToolBar createToolBar() {
116     final AbstractAction fromSketchAction = new AbstractAction("From Sketch") {
117       public void actionPerformed(ActionEvent e) {
118         fromSketch = ((AbstractButton) e.getSource()).isSelected();
119       }
120     };
121     fromSketchAction.putValue(Action.SHORT_DESCRIPTION, "Toggles the 'From Sketch' mode of the layout");
122 
123     JToolBar toolBar = super.createToolBar();
124     toolBar.addSeparator();
125     toolBar.add(createActionControl(new LayoutAction()));
126     toolBar.addSeparator(TOOLBAR_SMALL_SEPARATOR);
127     toolBar.add(new JToggleButton(fromSketchAction));
128     return toolBar;
129   }
130 
131   protected void loadGraph(String resourceString) {
132     mode = "resource/threetier.graphml".equals(resourceString) ? THREE_TIER_MODE : TABLE_MODE;
133     super.loadGraph(resourceString);
134   }
135 
136   
139   protected void registerViewActions() {
140     super.registerViewActions();
141 
142     ActionMap actionMap = view.getCanvasComponent().getActionMap();
143     actionMap.put(Graph2DViewActions.CLOSE_GROUPS, new MyCloseGroupsAction());
144     actionMap.put(Graph2DViewActions.OPEN_FOLDERS, new MyOpenFoldersAction());
145   }
146 
147     class MyCloseGroupsAction extends Graph2DViewActions.CloseGroupsAction {
149     public void actionPerformed(ActionEvent e) {
150       super.actionPerformed(e);
151       doLayout();
152     }
153   }
154 
155     class MyOpenFoldersAction extends Graph2DViewActions.OpenFoldersAction {
157     public void actionPerformed(ActionEvent e) {
158       super.actionPerformed(e);
159       doLayout();
160     }
161   }
162 
163   
166   class LayoutAction extends AbstractAction {
167     LayoutAction() {
168       super("Layout", SHARED_LAYOUT_ICON);
169     }
170 
171     public void actionPerformed(ActionEvent e) {
172       doLayout();
173     }
174   }
175 
176   private void doLayout() {
177     if (mode == THREE_TIER_MODE) {
178       applyThreeTierLayout();
179     } else {
180       applyTableLayout();
181     }
182   }
183 
184   
185   void applyTableLayout() {
186     Graph2D graph = view.getGraph2D();
187 
188         YList candidates = new YList();
190     candidates.add(PortCandidate.createCandidate(PortCandidate.WEST));
191     candidates.add(PortCandidate.createCandidate(PortCandidate.EAST));
192     graph.addDataProvider(PortCandidate.SOURCE_PCLIST_DPKEY, DataProviders.createConstantDataProvider(candidates));
193     graph.addDataProvider(PortCandidate.TARGET_PCLIST_DPKEY, DataProviders.createConstantDataProvider(candidates));
194 
195         final RowLayouter rowLayouter = new RowLayouter(); 
198     final IncrementalHierarchicLayouter ihl = new IncrementalHierarchicLayouter();     ihl.setLayoutOrientation(LayoutOrientation.LEFT_TO_RIGHT);
200     if (fromSketch) {
201       ihl.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_INCREMENTAL);
202     }
203     ihl.setOrthogonallyRouted(true);
204 
205         graph.addDataProvider(RecursiveGroupLayouter.GROUP_NODE_LAYOUTER_DPKEY, new DataProviderAdapter() {
207       public Object get(Object dataHolder) {
208         return rowLayouter;
209       }
210     });
211 
212         GroupLayoutConfigurator glc = new GroupLayoutConfigurator(graph);
214     try {
215       glc.prepareAll();
216 
217             RecursiveGroupLayouter rgl = new RecursiveGroupLayouter(ihl);
219       rgl.setAutoAssignPortCandidatesEnabled(true);
220       rgl.setConsiderSketchEnabled(true);
221       new Graph2DLayoutExecutor().doLayout(view, rgl);
222     } finally {
223             glc.restoreAll();
225       graph.removeDataProvider(PortCandidate.SOURCE_PCLIST_DPKEY);
226       graph.removeDataProvider(PortCandidate.TARGET_PCLIST_DPKEY);
227       graph.removeDataProvider(LayoutMultiplexer.LAYOUTER_DPKEY);
228     }
229 
230     view.updateView();
231     view.fitContent();
232   }
233 
234   
237   private static byte getType(Node n, Grouping grouping, Graph2D graph) {
238     if (grouping.isGroupNode(n)) {
239       NodeRealizer realizer = graph.getRealizer(n);
240       if ("left".equals(realizer.getLabelText())) {
241         return LEFT_TREE_GROUP_NODE;
242       } else if ("right".equals(realizer.getLabelText())) {
243         return RIGHT_TREE_GROUP_NODE;
244       } else {
245         return COMMON_NODE;
246       }
247     } else {
248       Node groupNode = grouping.getParent(n);
249       if (groupNode != null) {
250         NodeRealizer realizer = graph.getRealizer(groupNode);
251         if ("left".equals(realizer.getLabelText())) {
252           return LEFT_TREE_CONTENT_NODE;
253         } else if ("right".equals(realizer.getLabelText())) {
254           return RIGHT_TREE_CONTENT_NODE;
255         } else {
256           return COMMON_NODE;
257         }
258       } else {
259         NodeRealizer realizer = graph.getRealizer(n);
260         if ("left".equals(realizer.getLabelText())) {
261           return LEFT_TREE_GROUP_NODE;
262         } else if ("right".equals(realizer.getLabelText())) {
263           return RIGHT_TREE_GROUP_NODE;
264         } else {
265           return COMMON_NODE;
266         }
267       }
268     }
269   }
270 
271   
274   void applyThreeTierLayout() {
275     final Graph2D graph = view.getGraph2D();
276 
277         final TreeReductionStage leftToRightTreeLayouter = new TreeReductionStage();
279     leftToRightTreeLayouter.setNonTreeEdgeRouter(leftToRightTreeLayouter.createStraightlineRouter());
280     TreeLayouter tl1 = new TreeLayouter();
281     tl1.setLayoutOrientation(LayoutOrientation.LEFT_TO_RIGHT);
282     tl1.setLayoutStyle(TreeLayouter.ORTHOGONAL_STYLE);
283     leftToRightTreeLayouter.setCoreLayouter(tl1);
284 
285     final TreeReductionStage rightToLeftTreeLayouter = new TreeReductionStage();
286     rightToLeftTreeLayouter.setNonTreeEdgeRouter(rightToLeftTreeLayouter.createStraightlineRouter());
287     TreeLayouter tl2 = new TreeLayouter();
288     tl2.setLayoutOrientation(LayoutOrientation.RIGHT_TO_LEFT);
289     tl2.setLayoutStyle(TreeLayouter.ORTHOGONAL_STYLE);
290     rightToLeftTreeLayouter.setCoreLayouter(tl2);
291 
292     final IncrementalHierarchicLayouter partitionLayouter = new IncrementalHierarchicLayouter();     partitionLayouter.setLayoutOrientation(LayoutOrientation.LEFT_TO_RIGHT);
294     if (fromSketch) {
295       partitionLayouter.setLayoutMode(IncrementalHierarchicLayouter.LAYOUT_MODE_INCREMENTAL);
296     }
297 
298     GroupLayoutConfigurator glc = new GroupLayoutConfigurator(graph);     glc.prepareAll();
300     final Grouping grouping = new Grouping(graph);
301 
302     if (!fromSketch) {
303             LayerConstraintFactory lcf = partitionLayouter.createLayerConstraintFactory(graph);
305       for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
306         Node n = nc.node();
307         byte type = getType(n, grouping, graph);
308         if (type == LEFT_TREE_GROUP_NODE) {
309           lcf.addPlaceNodeAtTopConstraint(n);
310         } else if (type == RIGHT_TREE_GROUP_NODE) {
311           lcf.addPlaceNodeAtBottomConstraint(n);
312         }
313       }
314     }
315 
316         NodeMap node2LayoutDescriptor = Maps.createHashedNodeMap();
318     for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
319       Node n = nc.node();
320       byte type = getType(n, grouping, graph);
321       if (type == LEFT_TREE_GROUP_NODE) {
322         NodeLayoutDescriptor nld = new NodeLayoutDescriptor();
323         nld.setLayerAlignment(1.0d);
324         node2LayoutDescriptor.set(n, nld);
325       } else if (type == RIGHT_TREE_GROUP_NODE) {
326         NodeLayoutDescriptor nld = new NodeLayoutDescriptor();
327         nld.setLayerAlignment(0.0d);
328         node2LayoutDescriptor.set(n, nld);
329       }
330     }
331     graph.addDataProvider(HierarchicLayouter.NODE_LAYOUT_DESCRIPTOR_DPKEY, node2LayoutDescriptor);
332 
333         graph.addDataProvider(RecursiveGroupLayouter.GROUP_NODE_LAYOUTER_DPKEY, new DataProviderAdapter() {
335       public Object get(Object dataHolder) {
336         byte type = getType((Node) dataHolder, grouping, graph);
337         if (type == LEFT_TREE_GROUP_NODE) {
338           return leftToRightTreeLayouter;
339         } else if (type == RIGHT_TREE_GROUP_NODE) {
340           return rightToLeftTreeLayouter;
341         } else {
342           return null;         }
344       }
345     });
346 
347         final YList candidates = new YList();
349     candidates.add(PortCandidate.createCandidate(PortCandidate.WEST));
350     candidates.add(PortCandidate.createCandidate(PortCandidate.EAST));
351     graph.addDataProvider(PortCandidate.SOURCE_PCLIST_DPKEY, DataProviders.createConstantDataProvider(candidates));
352     graph.addDataProvider(PortCandidate.TARGET_PCLIST_DPKEY, DataProviders.createConstantDataProvider(candidates));
353 
354         RecursiveGroupLayouter rgl = new RecursiveGroupLayouter(partitionLayouter);
356 
357     try {
358       rgl.setAutoAssignPortCandidatesEnabled(true);
359       rgl.setConsiderSketchEnabled(true);
360 
361       new Graph2DLayoutExecutor().doLayout(view, rgl);
362 
363     } finally {
364             grouping.dispose();
366       glc.restoreAll();
367       graph.removeDataProvider(PortCandidate.SOURCE_PCLIST_DPKEY);
368       graph.removeDataProvider(PortCandidate.TARGET_PCLIST_DPKEY);
369       graph.removeDataProvider(LayoutMultiplexer.LAYOUTER_DPKEY);
370       graph.removeDataProvider(HierarchicLayouter.NODE_LAYOUT_DESCRIPTOR_DPKEY);
371       graph.removeDataProvider(GivenLayersLayerer.LAYER_ID_KEY);
372     }
373 
374     view.updateView();
375     view.fitContent();
376   }
377 
378   
381   static class RowLayouter implements Layouter {
382     private static final double DISTANCE = 5.0;
383 
384     public boolean canLayout(LayoutGraph graph) {
385       return graph.edgeCount() == 0;
386     }
387 
388     public void doLayout(final LayoutGraph graph) {
389       Node[] rows = graph.getNodeArray();
390       Arrays.sort(rows, new Comparator() {
391         public int compare(Object o1, Object o2) {
392           return Comparators.compare(graph.getCenterY((Node) o1), graph.getCenterY((Node) o2));
393         }
394       });
395 
396       double currentY = 0.0;
397       for (int i = 0; i < rows.length; i++) {
398                 graph.setLocation(rows[i], 0.0, currentY);
400         currentY += graph.getHeight(rows[i]) + DISTANCE;
401       }
402     }
403   }
404 
405   
408   public static void main(String[] args) {
409     EventQueue.invokeLater(new Runnable() {
410       public void run() {
411         Locale.setDefault(Locale.ENGLISH);
412         initLnF();
413         (new MixedLayoutDemo("resource/mixedlayouthelp.html")).start();
414       }
415     });
416   }
417 }
418