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