1
28 package demo.view.uml;
29
30 import y.anim.AnimationFactory;
31 import y.anim.AnimationObject;
32 import y.anim.AnimationPlayer;
33 import y.anim.CompositeAnimationObject;
34 import y.base.DataProvider;
35 import y.base.Edge;
36 import y.base.EdgeCursor;
37 import y.base.EdgeMap;
38 import y.base.Node;
39 import y.base.NodeCursor;
40 import y.geom.YDimension;
41 import y.geom.YPoint;
42 import y.layout.AbstractLayoutStage;
43 import y.layout.BufferedLayouter;
44 import y.layout.GraphLayout;
45 import y.layout.LayoutGraph;
46 import y.layout.Layouter;
47 import y.layout.router.polyline.EdgeRouter;
48 import y.util.DataProviderAdapter;
49 import y.util.Maps;
50 import y.view.Drawable;
51 import y.view.Graph2D;
52 import y.view.Graph2DView;
53 import y.view.Graph2DViewRepaintManager;
54 import y.view.LayoutMorpher;
55 import y.view.NodePort;
56 import y.view.NodeRealizer;
57
58 import java.awt.Graphics2D;
59 import java.awt.Rectangle;
60 import java.util.HashMap;
61
62
69 abstract class UmlClassAnimation implements AnimationObject, Drawable {
70 protected static final int DURATION = 300;
71
72 protected final Graph2DView view;
73 protected final NodeRealizer context;
74 protected final boolean isClosing;
75 private final UmlClassConfiguration painter;
76 private final Graph2DViewRepaintManager repaintManager;
77 private double state;
78
79
86 UmlClassAnimation(
87 final Graph2DView view,
88 final NodeRealizer context,
89 final boolean isClosing
90 ) {
91 this.view = view;
92 this.context = context;
93 this.isClosing = isClosing;
94 painter = new UmlClassConfiguration();
95 this.repaintManager = new Graph2DViewRepaintManager(view);
96 }
97
98
110 public void play() {
111 final AnimationPlayer player = new AnimationPlayer();
112 player.addAnimationListener(repaintManager);
113 view.addDrawable(this);
114
115 final Graph2D graph = view.getGraph2D();
117 final Node currentNode = context.getNode();
118 for (EdgeCursor ec = currentNode.edges(); ec.ok(); ec.next()) {
119 final Edge edge = ec.edge();
120 repaintManager.add(graph.getRealizer(edge));
121 }
122
123 EdgeMap sourcePorts = Maps.createHashedEdgeMap();
125 EdgeMap targetPorts = Maps.createHashedEdgeMap();
126 for (EdgeCursor ec = currentNode.edges(); ec.ok(); ec.next()) {
127 final Edge edge = ec.edge();
128 sourcePorts.set(edge, graph.getSourcePointAbs(edge));
129 targetPorts.set(edge, graph.getTargetPointAbs(edge));
130 }
131 if (!isClosing) {
132 open();
133 }
134
135 final NodeRealizer currentRealizer = graph.getRealizer(currentNode);
137 for (EdgeCursor ec = currentNode.outEdges(); ec.ok(); ec.next()) {
138 final Edge outEdge = ec.edge();
139 final NodePort port = UmlRealizerFactory.createDummyNodePort(currentRealizer, (YPoint) sourcePorts.get(outEdge));
140 currentRealizer.addPort(port);
141 port.bindSourcePort(outEdge);
142 }
143 for (EdgeCursor ec = currentNode.inEdges(); ec.ok(); ec.next()) {
144 final Edge inEdge = ec.edge();
145 final NodePort port = UmlRealizerFactory.createDummyNodePort(currentRealizer, (YPoint) targetPorts.get(inEdge));
146 currentRealizer.addPort(port);
147 port.bindTargetPort(inEdge);
148 }
149
150 if (isClosing) {
152 graph.addDataProvider(PreserveNodeSizeLayoutStage.NODE_SIZE_DPKEY, new DataProviderAdapter() {
153 public Object get(Object dataHolder) {
154 if (dataHolder == currentNode) {
155 return getClosedSize();
156 } else {
157 return null;
158 }
159 }
160 });
161 }
162
163 final EdgeRouter edgeRouter = new EdgeRouter();
165 edgeRouter.setSphereOfAction(EdgeRouter.ROUTE_EDGES_AT_SELECTED_NODES);
166 graph.addDataProvider(EdgeRouter.SELECTED_NODES, new DataProviderAdapter() {
167 public boolean getBool(Object dataHolder) {
168 if (dataHolder instanceof Node) {
169 Node node = (Node) dataHolder;
170 return node == currentNode;
171 }
172 return false;
173 }
174 });
175
176 final BufferedLayouter layouter = new BufferedLayouter(new PreserveNodeSizeLayoutStage(edgeRouter));
178 final GraphLayout graphLayout = layouter.calcLayout(graph);
179
180 graph.removeDataProvider(PreserveNodeSizeLayoutStage.NODE_SIZE_DPKEY);
182 graph.removeDataProvider(EdgeRouter.SELECTED_NODES);
183
184 final CompositeAnimationObject concurrentAnimation = AnimationFactory.createConcurrency();
186 final LayoutMorpher morpher = new LayoutMorpher(view, graphLayout);
187 morpher.setPreferredDuration(DURATION);
188 morpher.setKeepZoomFactor(true);
189 concurrentAnimation.addAnimation(morpher);
190 concurrentAnimation.addAnimation(this);
191
192 player.animate(concurrentAnimation);
193
194 if (isClosing) {
196 sourcePorts = Maps.createHashedEdgeMap();
197 targetPorts = Maps.createHashedEdgeMap();
198 for (EdgeCursor ec = currentNode.edges(); ec.ok(); ec.next()) {
199 final Edge edge = ec.edge();
200 sourcePorts.set(edge, graph.getSourcePointAbs(edge));
201 targetPorts.set(edge, graph.getTargetPointAbs(edge));
202 }
203
204 close();
205
206 for (EdgeCursor ec = currentNode.edges(); ec.ok(); ec.next()) {
207 final Edge edge = ec.edge();
208 graph.setSourcePointAbs(edge, (YPoint) sourcePorts.get(edge));
209 graph.setTargetPointAbs(edge, (YPoint) targetPorts.get(edge));
210 }
211 }
212
213 for (int i = currentRealizer.portCount() - 1; i >= 0; i--) {
215 currentRealizer.removePort(i);
216 }
217 for (EdgeCursor ec = currentNode.edges(); ec.ok(); ec.next()) {
218 final Edge edge = ec.edge();
219 repaintManager.remove(graph.getRealizer(edge));
220 }
221 view.removeDrawable(this);
222 player.removeAnimationListener(repaintManager);
223 }
224
225
228 protected abstract void close();
229
230
233 protected abstract void open();
234
235
238 protected abstract YDimension getClosedSize();
239
240
245 protected abstract double getFixedY();
246
247
252 protected abstract double getMovingY();
253
254
258 protected void stateUpdated(final double state) {
259 }
260
261 public void initAnimation() {
262 context.setVisible(false);
263 repaintManager.add(this);
264 }
265
266 public void calcFrame(final double time) {
267 state = isClosing ? 1.0 - time : time;
268 stateUpdated(state);
269 }
270
271 public void disposeAnimation() {
272 repaintManager.remove(this);
273 context.setVisible(true);
274 }
275
276 public long preferredDuration() {
277 return DURATION;
278 }
279
280 public void paint(final Graphics2D graphics) {
281 painter.paintAnimatedNode(context, graphics, getFixedY(), getMovingY(), state);
282 }
283
284 public Rectangle getBounds() {
285 final double lineWidth = UmlRealizerFactory.LINE_EDGE_CREATION_BUTTON_OUTLINE.getLineWidth();
286 final int minX = (int) Math.floor(context.getX() - lineWidth * 0.5);
287 final int minY = (int) Math.floor(context.getY() - lineWidth * 0.5);
288 final int maxX = (int) Math.ceil(context.getX() + context.getWidth() + lineWidth * 0.5);
289 final int maxY = (int) Math.ceil(context.getY() + context.getHeight() + lineWidth * 0.5);
290 return new Rectangle(minX, minY, maxX - minX, maxY - minY);
291 }
292
293
298 private static final class PreserveNodeSizeLayoutStage extends AbstractLayoutStage {
299 public static final Object NODE_SIZE_DPKEY = "PreserveNodeSizeLayoutStage.NODE_SIZE_DPKEY";
300
301 public PreserveNodeSizeLayoutStage(Layouter layouter) {
302 super(layouter);
303 }
304
305 public boolean canLayout(LayoutGraph graph) {
306 return canLayoutCore(graph);
307 }
308
309 public void doLayout(LayoutGraph graph) {
310 final HashMap oldSizes = new HashMap();
312 final DataProvider dp = graph.getDataProvider(NODE_SIZE_DPKEY);
313 if (dp != null) {
314 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
315 final Node node = nc.node();
316 final Object size = dp.get(node);
317 if (size instanceof YDimension) {
318 oldSizes.put(node, graph.getSize(node));
319 final YPoint location = graph.getLocation(node);
320 graph.setSize(node, (YDimension) size);
321 graph.setLocation(node, location);
322 }
323 }
324 }
325
326 doLayoutCore(graph);
328
329 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
331 final Node node = nc.node();
332 final YDimension size = (YDimension) oldSizes.get(node);
333 if (size != null) {
334 final EdgeMap sourcePorts = Maps.createHashedEdgeMap();
337 final EdgeMap targetPorts = Maps.createHashedEdgeMap();
338 for (EdgeCursor ec = node.edges(); ec.ok(); ec.next()) {
339 final Edge edge = ec.edge();
340 sourcePorts.set(edge, graph.getSourcePointAbs(edge));
341 targetPorts.set(edge, graph.getTargetPointAbs(edge));
342 }
343
344 final YPoint location = graph.getLocation(node);
346 graph.setSize(node, size);
347 graph.setLocation(node, location);
348
349 for (EdgeCursor ec = node.edges(); ec.ok(); ec.next()) {
351 final Edge edge = ec.edge();
352 graph.setSourcePointAbs(edge, (YPoint) sourcePorts.get(edge));
353 graph.setTargetPointAbs(edge, (YPoint) targetPorts.get(edge));
354 }
355 }
356 }
357 }
358 }
359 }
360