001: /*******************************************************************************
002: * Copyright (c) 2003, 2004 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Common Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/cpl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.openwfe.gpe.parts;
011:
012: import java.util.HashMap;
013: import java.util.Iterator;
014: import java.util.List;
015: import java.util.Map;
016:
017: import org.eclipse.draw2d.Connection;
018: import org.eclipse.draw2d.IFigure;
019: import org.eclipse.draw2d.Viewport;
020: import org.eclipse.draw2d.geometry.Point;
021: import org.eclipse.draw2d.geometry.PointList;
022: import org.eclipse.draw2d.geometry.Rectangle;
023:
024: /**
025: * @author hudsonr
026: * Created on Apr 28, 2003
027: */
028: public class GraphAnimation {
029:
030: static final long DURATION = 230;
031:
032: static long current;
033: static double progress;
034: static long start = -1;
035: static long finish;
036: static Viewport viewport;
037: //static IFigure trackMe;
038: //static IFigure showMe;
039: //static Point trackLocation;
040:
041: static boolean PLAYBACK;
042: static boolean RECORDING;
043:
044: static Map initialStates;
045: static Map finalStates;
046:
047: static void end() {
048: Iterator iter = initialStates.keySet().iterator();
049: while (iter.hasNext()) {
050: IFigure f = ((IFigure) iter.next());
051: f.revalidate();
052: f.setVisible(true);
053: }
054: //$TODO instead of performing a final normal layout, what about setting progress=1.0?
055: initialStates = null;
056: finalStates = null;
057: PLAYBACK = false;
058: // trackMe = null;
059: // showMe = null;
060: viewport = null;
061: }
062:
063: static boolean captureLayout(IFigure root) {
064:
065: RECORDING = true;
066:
067: while (!(root instanceof Viewport))
068: root = root.getParent();
069: viewport = (Viewport) root;
070: while (root.getParent() != null)
071: root = root.getParent();
072:
073: initialStates = new HashMap();
074: finalStates = new HashMap();
075:
076: //This part records all layout results.
077: root.validate();
078: Iterator iter = initialStates.keySet().iterator();
079: if (!iter.hasNext()) {
080: //Nothing layed out, so abort the animation
081: RECORDING = false;
082: return false;
083: }
084: while (iter.hasNext())
085: recordFinalState((IFigure) iter.next());
086:
087: start = System.currentTimeMillis();
088: finish = start + DURATION;
089: current = start + 20;
090:
091: RECORDING = false;
092: PLAYBACK = true;
093: return true;
094: }
095:
096: static boolean playbackState(Connection conn) {
097: if (!PLAYBACK)
098: return false;
099:
100: PointList list1 = (PointList) initialStates.get(conn);
101: PointList list2 = (PointList) finalStates.get(conn);
102: if (list1 == null) {
103: conn.setVisible(false);
104: return true;
105: }
106: if (list1.size() == list2.size()) {
107: Point pt1 = new Point(), pt2 = new Point();
108: PointList points = conn.getPoints();
109: points.removeAllPoints();
110: for (int i = 0; i < list1.size(); i++) {
111: list1.getPoint(pt2, i);
112: list2.getPoint(pt1, i);
113: pt1.x = (int) Math.round(pt1.x * progress
114: + (1 - progress) * pt2.x);
115: pt1.y = (int) Math.round(pt1.y * progress
116: + (1 - progress) * pt2.y);
117: points.addPoint(pt1);
118: }
119: conn.setPoints(points);
120: }
121: return true;
122: }
123:
124: static boolean playbackState(IFigure container) {
125: if (!PLAYBACK)
126: return false;
127:
128: List children = container.getChildren();
129: Rectangle rect1, rect2;
130: for (int i = 0; i < children.size(); i++) {
131: IFigure child = (IFigure) children.get(i);
132: rect1 = (Rectangle) initialStates.get(child);
133: rect2 = (Rectangle) finalStates.get(child);
134: if (rect2 == null)
135: continue;
136: child.setBounds(new Rectangle((int) Math.round(progress
137: * rect2.x + (1 - progress) * rect1.x), (int) Math
138: .round(progress * rect2.y + (1 - progress)
139: * rect1.y), (int) Math.round(progress
140: * rect2.width + (1 - progress) * rect1.width),
141: (int) Math.round(progress * rect2.height
142: + (1 - progress) * rect1.height)));
143: // child.invalidate();
144: }
145: return true;
146: }
147:
148: static void recordFinalState(Connection conn) {
149: //$TODO
150: PointList points1 = (PointList) initialStates.get(conn);
151: PointList points2 = conn.getPoints().getCopy();
152:
153: if (points1 != null && points1.size() != points2.size()) {
154: Point p = new Point(), q = new Point();
155:
156: int size1 = points1.size() - 1;
157: int size2 = points2.size() - 1;
158:
159: int i1 = size1;
160: int i2 = size2;
161:
162: double current1 = 1.0;
163: double current2 = 1.0;
164:
165: double prev1 = 1.0;
166: double prev2 = 1.0;
167:
168: while (i1 > 0 || i2 > 0) {
169: if (Math.abs(current1 - current2) < 0.1 && i1 > 0
170: && i2 > 0) {
171: //Both points are the same, use them and go on;
172: prev1 = current1;
173: prev2 = current2;
174: i1--;
175: i2--;
176: current1 = (double) i1 / size1;
177: current2 = (double) i2 / size2;
178: } else if (current1 < current2) {
179: //2 needs to catch up
180: // current1 < current2 < prev1
181: points1.getPoint(p, i1);
182: points1.getPoint(q, i1 + 1);
183:
184: p.x = (int) (((q.x * (current2 - current1) + p.x
185: * (prev1 - current2)) / (prev1 - current1)));
186: p.y = (int) (((q.y * (current2 - current1) + p.y
187: * (prev1 - current2)) / (prev1 - current1)));
188:
189: points1.insertPoint(p, i1 + 1);
190:
191: prev1 = prev2 = current2;
192: i2--;
193: current2 = (double) i2 / size2;
194:
195: } else {
196: //1 needs to catch up
197: // current2< current1 < prev2
198:
199: points2.getPoint(p, i2);
200: points2.getPoint(q, i2 + 1);
201:
202: p.x = (int) (((q.x * (current1 - current2) + p.x
203: * (prev2 - current1)) / (prev2 - current2)));
204: p.y = (int) (((q.y * (current1 - current2) + p.y
205: * (prev2 - current1)) / (prev2 - current2)));
206:
207: points2.insertPoint(p, i2 + 1);
208:
209: prev2 = prev1 = current1;
210: i1--;
211: current1 = (double) i1 / size1;
212: }
213: }
214: }
215: finalStates.put(conn, points2);
216: }
217:
218: static void recordFinalState(IFigure child) {
219: if (child instanceof Connection) {
220: recordFinalState((Connection) child);
221: return;
222: }
223: Rectangle rect2 = child.getBounds().getCopy();
224: Rectangle rect1 = (Rectangle) initialStates.get(child);
225: if (rect1.isEmpty()) {
226: rect1.x = rect2.x;
227: rect1.y = rect2.y;
228: rect1.width = rect2.width;
229: }
230: finalStates.put(child, rect2);
231: }
232:
233: static void recordInitialState(Connection connection) {
234: if (!RECORDING)
235: return;
236: PointList points = connection.getPoints().getCopy();
237: if (points.size() == 2
238: && points.getPoint(0).equals(
239: Point.SINGLETON.setLocation(0, 0))
240: && points.getPoint(1).equals(
241: Point.SINGLETON.setLocation(100, 100)))
242: initialStates.put(connection, null);
243: else
244: initialStates.put(connection, points);
245: }
246:
247: static void recordInitialState(IFigure container) {
248: if (!RECORDING)
249: return;
250:
251: List children = container.getChildren();
252: IFigure child;
253: for (int i = 0; i < children.size(); i++) {
254: child = (IFigure) children.get(i);
255: initialStates.put(child, child.getBounds().getCopy());
256: }
257: }
258:
259: static void swap() {
260: Map temp = finalStates;
261: finalStates = initialStates;
262: initialStates = temp;
263: }
264:
265: static boolean step() {
266: current = System.currentTimeMillis() + 30;
267: progress = (double) (current - start) / (finish - start);
268: progress = Math.min(progress, 0.999);
269: Iterator iter = initialStates.keySet().iterator();
270:
271: while (iter.hasNext())
272: ((IFigure) iter.next()).revalidate();
273: viewport.validate();
274:
275: // Point loc = viewport.getViewLocation();
276: // loc.translate(trackMe.getBounds().getLocation().getDifference(trackLocation));
277: // viewport.setViewLocation(loc);
278: // trackLocation = trackMe.getBounds().getLocation();
279:
280: return current < finish;
281: }
282:
283: }
|