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