1
14 package demo.layout.tree;
15
16 import demo.view.DemoBase;
17 import y.anim.AnimationPlayer;
18 import y.base.Edge;
19 import y.base.EdgeMap;
20 import y.base.Node;
21 import y.base.NodeCursor;
22 import y.base.NodeMap;
23 import y.geom.YPoint;
24 import y.layout.PortConstraint;
25 import y.layout.PortConstraintKeys;
26 import y.layout.tree.AbstractRotatableNodePlacer;
27 import y.layout.tree.AbstractRotatableNodePlacer.RootAlignment;
28 import y.layout.tree.DefaultNodePlacer;
29 import y.layout.tree.GenericTreeLayouter;
30 import y.layout.tree.NodePlacer;
31 import y.layout.tree.SimpleNodePlacer;
32 import y.util.DataProviderAdapter;
33 import y.view.CreateChildEdgeMode;
34 import y.view.EdgeRealizer;
35 import y.view.EditMode;
36 import y.view.Graph2D;
37 import y.view.HotSpotMode;
38 import y.view.NodeRealizer;
39 import y.view.PopupMode;
40 import y.view.PortAssignmentMoveSelectionMode;
41
42 import javax.swing.AbstractAction;
43 import java.awt.Color;
44 import java.awt.Cursor;
45 import java.awt.event.ActionEvent;
46 import java.lang.reflect.Method;
47
48
52 public abstract class AbstractTreeDemo extends DemoBase {
53 protected GenericTreeLayouter treeLayouter = new GenericTreeLayouter();
54
55 protected EdgeMap sourcePortMap;
56 protected EdgeMap targetPortMap;
57 protected NodeMap portAssignmentMap;
58 protected NodeMap nodePlacerMap;
59 protected PortAssignmentMoveSelectionMode portAssignmentMoveMode = new TreePortAssignmentMode();
60 protected Color[] layerColors = {Color.red, Color.orange, Color.yellow, Color.blue, Color.cyan,
61 Color.green};
62
63
66 protected AbstractTreeDemo() {
67 view.addViewMode(new TreeCreateEditMode());
68
69 AnimationPlayer animationPlayer = new AnimationPlayer();
70 animationPlayer.addAnimationListener(view);
71
72 Graph2D graph = view.getGraph2D();
73
74 sourcePortMap = graph.createEdgeMap();
75 targetPortMap = graph.createEdgeMap();
76 portAssignmentMap = graph.createNodeMap();
77 nodePlacerMap = graph.createNodeMap();
78 graph.addDataProvider(GenericTreeLayouter.NODE_PLACER_DPKEY, nodePlacerMap);
79 graph.addDataProvider(GenericTreeLayouter.PORT_ASSIGNMENT_DPKEY, portAssignmentMap);
80 graph.addDataProvider(GenericTreeLayouter.CHILD_COMPARATOR_DPKEY, new ChildEdgeComparatorProvider());
81 graph.addDataProvider(PortConstraintKeys.SOURCE_PORT_CONSTRAINT_KEY, sourcePortMap);
82 graph.addDataProvider(PortConstraintKeys.TARGET_PORT_CONSTRAINT_KEY, targetPortMap);
83
84 portAssignmentMoveMode.setSpc(sourcePortMap);
85 portAssignmentMoveMode.setTpc(targetPortMap);
86 }
87
88
93 public void setNodePlacer(Node node, NodePlacer placer) {
94 nodePlacerMap.set(node, placer);
95 }
96
97
100 public void calcLayout() {
101 if (!view.getGraph2D().isEmpty()) {
102 Cursor oldCursor = view.getCanvasComponent().getCursor();
103 try {
104 view.getCanvasComponent().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
105 view.applyLayoutAnimated(treeLayouter);
106 } finally {
107 view.getCanvasComponent().setCursor(oldCursor);
108 }
109 }
110 }
111
112
115 protected PopupMode createTreePopupMode() {
116 return null;
117 }
118
119
122 protected void registerViewModes() {
123 }
124
125 protected NodePlacer createDefaultNodePlacer() {
126 return new SimpleNodePlacer();
127 }
128
129 protected final class ChildEdgeComparatorProvider extends DataProviderAdapter {
130 public Object get(Object dataHolder) {
131 NodePlacer placer = (NodePlacer) nodePlacerMap.get(dataHolder);
132 if (placer instanceof AbstractRotatableNodePlacer) {
133 return ((AbstractRotatableNodePlacer) placer).createComparator();
134 }
135 if (placer instanceof DefaultNodePlacer) {
136 return ((DefaultNodePlacer) placer).createComparator();
137 }
138 return null;
139 }
140 }
141
142 private final class TreeHotSpotMode extends HotSpotMode {
143 public void mouseReleasedLeft(double x, double y) {
144 super.mouseReleasedLeft(x, y);
145 calcLayout();
146 }
147 }
148
149 protected class TreeCreateEditMode extends EditMode {
150 TreeCreateEditMode() {
151 if (portAssignmentMoveMode == null) {
152 throw new IllegalStateException("portAssignmentMoveMode is null");
153 }
154 setMoveSelectionMode(portAssignmentMoveMode);
155 setCreateEdgeMode(new TreeCreateChildEdgeMode());
156 setHotSpotMode(new TreeHotSpotMode());
157 setPopupMode(AbstractTreeDemo.this.createTreePopupMode());
158 }
159
160 public boolean doAllowNodeCreation() {
161 return getGraph2D().N() == 0;
162 }
163
164 protected void nodeCreated(Node v) {
165 super.nodeCreated(v);
166 setNodePlacer(v, createDefaultNodePlacer());
167 }
168 }
169
170 private final class TreeCreateChildEdgeMode extends CreateChildEdgeMode {
171 protected void edgeCreated(Edge edge) {
172 int depth = 1;
173 for (Node node = edge.source(); node.inDegree() > 0; node = node.firstInEdge().source()) {
174 depth++;
175 }
176 Graph2D g = getGraph2D();
177 g.getRealizer(edge.target()).setFillColor(layerColors[depth % layerColors.length]);
178 EdgeRealizer er = g.getRealizer(edge);
179 if (nodePlacerMap.get(edge.source()) == null) {
180 parseNodePlacement(g, edge, er);
181 }
182
183 nodePlacerMap.set(edge.target(), new SimpleNodePlacer());
184 parseTargetPort(g, edge, er);
185 g.unselectAll();
186 calcLayout();
187 }
188
189 protected NodeRealizer activeDummyTargetRealizer;
190
191 protected boolean acceptSourceNode(Node source, double x, double y) {
192 final boolean accept = super.acceptSourceNode(source, x, y);
193 activeDummyTargetRealizer = createChildNodeRealizer();
194 int depth = 1;
195 for (Node n = source; n.inDegree() > 0; n = n.firstInEdge().source()){
196 depth++;
197 }
198 activeDummyTargetRealizer.setFillColor(layerColors[depth % layerColors.length]);
199 return accept;
200 }
201
202 protected NodeRealizer createDummyTargetNodeRealizer(double x, double y) {
203 return activeDummyTargetRealizer;
204 }
205
206 private void parseNodePlacement(Graph2D g, Edge e, EdgeRealizer er) {
207 nodePlacerMap.set(e.source(), new SimpleNodePlacer());
208 }
209
210 private void parseTargetPort(Graph2D g, Edge e, EdgeRealizer er) {
211 if (er.bendCount() > 0) {
212 YPoint lastPoint = new YPoint(er.lastBend().getX(), er.lastBend().getY());
213 NodeRealizer target = g.getRealizer(e.target());
214 double dx = lastPoint.x - target.getCenterX();
215 double dy = lastPoint.y - target.getCenterY();
216 byte side;
217 if (Math.abs(dx) > Math.abs(dy)) {
218 if (dx > 0.0) {
219 side = PortConstraint.EAST;
220 } else {
221 side = PortConstraint.WEST;
222 }
223 } else {
224 if (dy > 0.0) {
225 side = PortConstraint.SOUTH;
226 } else {
227 side = PortConstraint.NORTH;
228 }
229 }
230 targetPortMap.set(e, PortConstraint.create(side));
231 }
232 }
233
234 protected NodeRealizer createChildNodeRealizer() {
235 NodeRealizer retValue = super.createChildNodeRealizer();
236 retValue.setLabelText("");
237 return retValue;
238 }
239
240 }
241
242 protected class SetHorizontalAlignmentAction extends AbstractAction {
243 private RootAlignment alignment;
244
245 protected SetHorizontalAlignmentAction(String name, RootAlignment alignment) {
246 super(name);
247 this.alignment = alignment;
248 }
249
250 public void actionPerformed(ActionEvent e) {
251 for (NodeCursor nodeCursor = view.getGraph2D().selectedNodes(); nodeCursor.ok(); nodeCursor.next()) {
252 Node node = nodeCursor.node();
253 NodePlacer nodePlacer = (NodePlacer) nodePlacerMap.get(node);
254
255 try {
256 Method method = nodePlacer.getClass().getMethod("setRootAlignment", new Class[]{RootAlignment.class});
257 method.invoke(nodePlacer, new Object[]{alignment});
258 } catch (Exception ex) {
259 }
260 }
261 calcLayout();
262 }
263 }
264
265 abstract class SetNodePlacerAction extends AbstractAction {
266 protected SetNodePlacerAction(String name) {
267 super(name);
268 }
269
270 public void actionPerformed(ActionEvent e) {
271 for (NodeCursor nodeCursor = view.getGraph2D().selectedNodes(); nodeCursor.ok(); nodeCursor.next()) {
272 Node node = nodeCursor.node();
273 nodePlacerMap.set(node, createNodePlacer());
274 }
275 calcLayout();
276 }
277
278 protected abstract NodePlacer createNodePlacer();
279 }
280
281 private final class TreePortAssignmentMode extends PortAssignmentMoveSelectionMode {
282 TreePortAssignmentMode() {
283 super(null, null);
284 }
285
286 protected boolean isPortReassignmentAllowed(Edge edge, boolean source) {
287 return !source;
288 }
289
290 protected void selectionMovedAction(double dx, double dy, double x, double y) {
291 super.selectionMovedAction(dx, dy, x, y);
292 calcLayout();
293 }
294
295 }
296 }
297