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