1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g2d.multileveldiagram;
14 import java.awt.BasicStroke;
15 import java.awt.Color;
16 import java.awt.Stroke;
17 import java.awt.geom.AffineTransform;
18 import java.awt.geom.Path2D;
19 import java.awt.geom.Point2D;
20 import java.awt.geom.Rectangle2D;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
26 import java.util.WeakHashMap;
28 import org.simantics.g2d.diagram.DiagramClass;
29 import org.simantics.g2d.diagram.IDiagram;
30 import org.simantics.g2d.diagram.handler.DataElementMap;
31 import org.simantics.g2d.diagram.handler.LifeCycle;
32 import org.simantics.g2d.diagram.handler.Topology;
33 import org.simantics.g2d.diagram.handler.impl.DataElementMapImpl;
34 import org.simantics.g2d.diagram.handler.impl.PickContextImpl;
35 import org.simantics.g2d.diagram.handler.impl.TransactionContextImpl;
36 import org.simantics.g2d.diagram.impl.AbstractDiagram;
37 import org.simantics.g2d.element.ElementClass;
38 import org.simantics.g2d.element.ElementHints;
39 import org.simantics.g2d.element.ElementUtils;
40 import org.simantics.g2d.element.IElement;
41 import org.simantics.g2d.element.handler.AdditionalColor;
42 import org.simantics.g2d.element.handler.BendsHandler;
43 import org.simantics.g2d.element.handler.BorderColor;
44 import org.simantics.g2d.element.handler.EdgeVisuals;
45 import org.simantics.g2d.element.handler.ElementHandler;
46 import org.simantics.g2d.element.handler.FillColor;
47 import org.simantics.g2d.element.handler.InternalSize;
48 import org.simantics.g2d.element.handler.SceneGraph;
49 import org.simantics.g2d.element.handler.TerminalTopology;
50 import org.simantics.g2d.element.handler.Text;
51 import org.simantics.g2d.element.handler.TextColor;
52 import org.simantics.g2d.element.handler.Transform;
53 import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
54 import org.simantics.g2d.element.handler.impl.MoveImpl;
55 import org.simantics.g2d.element.handler.impl.proxy.IProxyProvider;
56 import org.simantics.g2d.element.handler.impl.proxy.ProxyHandler;
57 import org.simantics.g2d.element.handler.impl.proxy.ProxyLifeCycle;
58 import org.simantics.g2d.element.impl.Element;
59 import org.simantics.g2d.multileveldiagram.TransitionDiagram.ProxyFadePaint.FadeDir;
60 import org.simantics.g2d.utils.GeometryUtils;
61 import org.simantics.g2d.utils.PathUtils2;
62 import org.simantics.scenegraph.g2d.G2DParentNode;
63 import org.simantics.utils.ObjectUtils;
64 import org.simantics.utils.datastructures.hints.HintContext;
67 * Transition diagram is a diagram that is a transition between two diagrams.
68 * Diagram in transition cannot be edited.
69 * There is always upper and lower diagram.
70 * There are different trasition effects : Morph and blend
72 * TODO monitor upper and lower diagrams for element changes
73 * TODO monitor upper and lower elements for KEY_OBJECT changes
75 * @author Toni Kalajainen
77 public class TransitionDiagram extends AbstractDiagram {
80 super(TRANSITION_DIAGRAM_CLASS, new HintContext());
83 public static final Key KEY_UPPER_DIAGRAM = new KeyOf(IDiagram.class);
84 public static final Key KEY_LOWER_DIAGRAM = new KeyOf(IDiagram.class);
85 public static final Key KEY_TRANSITION_CLASS = new KeyOf(ElementClass.class);
87 /** Element keys refering to elements of source diagram */
88 public static final Key KEY_UPPER_ELEMENT = new KeyOf(IElement.class);
89 public static final Key KEY_LOWER_ELEMENT = new KeyOf(IElement.class);
90 public static final Key KEY_SOURCE_ELEMENT = new KeyOf(IElement.class);
92 /** Diagram hint, transition phase, value between 0..1, 0=upper, 1=lower */
93 public static final Key KEY_PHASE = new KeyOf(Double.class);
95 public static final ElementClass MORPH_ELEMENT_CLASS = ElementClass.compile(MorphElementHandler.INSTANCE, MoveImpl.HANDLER);
97 public static final DiagramClass TRANSITION_DIAGRAM_CLASS = DiagramClass.compile(
98 new PickContextImpl(),
99 new TransactionContextImpl(),
100 new MorphTopologyImpl(),
101 new TransitionDiagramHandler(),
102 new DataElementMapImpl()
105 public static final IDiagram createTransitionDiagram(IDiagram upperDiagram, IDiagram lowerDiagram, ElementClass transitionClass)
107 assert(upperDiagram!=null && lowerDiagram!=null && transitionClass!=null);
108 TransitionDiagram d = new TransitionDiagram();
109 d.setHint(KEY_TRANSITION_CLASS, transitionClass);
110 d.setHint(KEY_UPPER_DIAGRAM, upperDiagram);
111 d.setHint(KEY_LOWER_DIAGRAM, lowerDiagram);
116 IDiagram upperDiagram, lowerDiagram;
119 * Set a new element class to an element
123 * @return new element
125 private static IElement setElementClass(IElement e, ElementClass clazz)
127 IDiagram d = e.getDiagram();
128 if (e.getElementClass().equals(clazz)) return e;
129 Map<Key, Object> hints = e.getHints();
130 int index = d.getElements().indexOf(e);
133 e = Element.spawnNew(clazz);
140 static class TransitionDiagramHandler implements LifeCycle {
142 private static final Key KEY_COMPOSITION_LISTENER =
143 new KeyOf(CompositionListener.class);
146 public void onDiagramCreated(final IDiagram transitionDiagram) {
148 CompositionListener cl = new CompositionListener() {
150 public void onElementAdded(IDiagram diagram, IElement element) {
151 IDiagram upperDiagram = transitionDiagram.getHint(KEY_UPPER_DIAGRAM);
152 IDiagram lowerDiagram = transitionDiagram.getHint(KEY_LOWER_DIAGRAM);
153 boolean isUpper = diagram == upperDiagram;
154 IDiagram oppositeDiagram = isUpper ? lowerDiagram : upperDiagram;
155 // Element has been added to either upper or lower diagram
156 DataElementMap m = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
157 Object data = m.getData(diagram, element);
159 // Check if the opposite diagram has a valid counter part
160 m = oppositeDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
161 IElement counterPart = data==null?null:m.getElement(oppositeDiagram, data);
165 // Element has a counter-part, therefore it can be morphed
166 if (counterPart!=null) {
167 clazz = MORPH_ELEMENT_CLASS;
169 // There is no counterpart, therefore it is a fading element
171 FadeDir dir = isUpper ? FadeDir.Out : FadeDir.In;
172 clazz = getFadeElementClass(element.getElementClass(), dir);
175 // Check if transition element already exists
176 m = transitionDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
177 IElement transitionElement = m.getElement(transitionDiagram, data);
178 if (transitionElement!=null) {
179 setElementClass(transitionElement, clazz);
183 transitionElement = Element.instantiate(clazz, null);
185 // Element has a counter-part, therefore it can be morphed
186 if (counterPart!=null) {
187 transitionElement.setHint(KEY_UPPER_ELEMENT, isUpper?element:counterPart);
188 transitionElement.setHint(KEY_LOWER_ELEMENT, isUpper?counterPart:element);
190 // There is no counterpart, therefore it is a fading element
192 transitionElement.setHint(KEY_SOURCE_ELEMENT, element);
196 transitionElement.setHint(ElementHints.KEY_OBJECT, data);
197 Element.fireCreated(transitionElement);
198 transitionDiagram.addElement(transitionElement);
202 public void onElementRemoved(IDiagram diagram, IElement element) {
203 IDiagram upperDiagram = transitionDiagram.getHint(KEY_UPPER_DIAGRAM);
204 IDiagram lowerDiagram = transitionDiagram.getHint(KEY_LOWER_DIAGRAM);
205 boolean isUpper = diagram == upperDiagram;
206 IDiagram oppositeDiagram = isUpper ? lowerDiagram : upperDiagram;
207 // Element has been added to either upper or lower diagram
208 DataElementMap m = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
209 Object data = m.getData(diagram, element);
211 // Check if the opposite diagram has a valid counter part
212 m = oppositeDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
213 IElement counterPart = data==null?null:m.getElement(oppositeDiagram, data);
215 // Check if transition element already exists
216 m = transitionDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
217 IElement transitionElement = m.getElement(transitionDiagram, data);
218 if (transitionElement==null) {
219 for (IElement e : transitionDiagram.getElements())
220 if (e.getHint(KEY_SOURCE_ELEMENT) == element)
222 transitionElement = e;
226 // There is a mix-up .. not too serious
227 if (transitionElement==null)
230 // if class is morph and the counter part remains, transform transition element to fade element
231 if (transitionElement.getElementClass().equals(MORPH_ELEMENT_CLASS) &&
234 FadeDir dir = isUpper ? FadeDir.Out : FadeDir.In;
235 ElementClass clazz = getFadeElementClass(element.getElementClass(), dir);
236 transitionElement.removeHint(KEY_UPPER_ELEMENT);
237 transitionElement.removeHint(KEY_LOWER_ELEMENT);
238 setElementClass(transitionElement, clazz);
239 transitionElement.setHint(KEY_SOURCE_ELEMENT, counterPart);
241 transitionDiagram.removeElement(transitionElement);
242 transitionElement.destroy();
246 IDiagram upperDiagram = transitionDiagram.getHint(KEY_UPPER_DIAGRAM);
247 IDiagram lowerDiagram = transitionDiagram.getHint(KEY_LOWER_DIAGRAM);
248 upperDiagram.addCompositionListener(cl);
249 lowerDiagram.addCompositionListener(cl);
250 transitionDiagram.setHint(KEY_COMPOSITION_LISTENER, cl);
253 for (IElement e : upperDiagram.getElements())
254 cl.onElementAdded(upperDiagram, e);
255 for (IElement e : lowerDiagram.getElements())
256 cl.onElementAdded(lowerDiagram, e);
260 public void onDiagramDisposed(IDiagram diagram) {
262 CompositionListener cl = diagram.getHint(KEY_COMPOSITION_LISTENER);
263 IDiagram upperDiagram = diagram.getHint(KEY_UPPER_DIAGRAM);
264 IDiagram lowerDiagram = diagram.getHint(KEY_LOWER_DIAGRAM);
265 upperDiagram.removeCompositionListener(cl);
266 lowerDiagram.removeCompositionListener(cl);
267 diagram.removeHint(KEY_COMPOSITION_LISTENER);
271 public void onDiagramDestroyed(IDiagram diagram) {}
273 public void onDiagramLoaded(IDiagram diagram, Collection<IElement> initialElements) {}
277 // TODO REMOVE REDUNDANCY == Transitions to void
278 // In morph element handler there is always 2 counter parts
279 static class MorphElementHandler implements SceneGraph, FillColor, BorderColor, AdditionalColor, TextColor, Transform, InternalSize, EdgeVisuals, BendsHandler, Text {
281 private static final long serialVersionUID = 1907473087657477787L;
283 public static final MorphElementHandler INSTANCE = new MorphElementHandler();
285 /** key for sub-diagram -> element Map */
286 public final static Key KEY_ELEMENT_MAP = new KeyOf(Map.class);
288 static IElement getUpperSourceElement(IElement e)
290 return e.getHint(KEY_UPPER_ELEMENT);
293 static IElement getLowerSourceElement(IElement e)
295 return e.getHint(KEY_LOWER_ELEMENT);
298 /** Returns elements between when diagram is in transition */
299 static Transition getTransition(IElement e)
301 Transition t = new Transition();
302 Double phase = e.getDiagram().getHint(KEY_PHASE);
303 t.le = getLowerSourceElement(e);
304 t.ue = getUpperSourceElement(e);
309 static private class Transition {
310 // Upper Element and Lower Element
316 // public void paint(IElement e, ICanvasContext ctx,
317 // GraphicsContext elementGC, GraphicsContext controlGC) {
318 // Transition t = getTransition(e);
319 // List<Paint> empty = Collections.EMPTY_LIST;
320 // List<Paint> ups = t.ue==null?empty:t.ue.getElementClass().getItemsByClass(Paint.class);
321 // List<Paint> lps = t.le==null?empty:t.le.getElementClass().getItemsByClass(Paint.class);
323 // if (ObjectUtils.equals(ups, lps))
325 // for (Paint lp : lps)
326 // lp.paint(e, ctx, elementGC, controlGC);
330 // if (!lps.isEmpty()) {
331 //// Graphics2D g = elementGC.createClone();
332 //// Graphics2D g2 = controlGC.createClone();
333 //// Composite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float)t.phase);
334 //// g.setComposite(c);
335 //// g2.setComposite(c);
336 // GraphicsContextImpl newCtx = new GraphicsContextImpl(elementGC.getBounds(), elementGC.getNode());
337 // GraphicsContextImpl newCtx2 = new GraphicsContextImpl(controlGC.getBounds(), controlGC.getNode());
338 // for (Paint lp : lps)
340 // lp.paint(t.le, ctx, newCtx, newCtx2);
343 // newCtx2.dispose();
346 // if (!ups.isEmpty()) {
347 //// Graphics2D g = elementGC.createClone();
348 //// Graphics2D g2 = controlGC.createClone();
349 //// Composite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1-(float)t.phase);
350 //// g.setComposite(c);
351 //// g2.setComposite(c);
352 // GraphicsContextImpl newCtx = new GraphicsContextImpl(elementGC.getBounds(), elementGC.getNode());
353 // GraphicsContextImpl newCtx2 = new GraphicsContextImpl(controlGC.getBounds(), controlGC.getNode());
354 // for (Paint up : ups)
356 // up.paint(t.ue, ctx, newCtx, newCtx2);
359 // newCtx2.dispose();
364 public AffineTransform getTransform(IElement e) {
365 Transition t = getTransition(e);
366 Transform ut = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(Transform.class);
367 Transform lt = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(Transform.class);
368 AffineTransform uat = ut==null?null:ut.getTransform(t.ue);
369 AffineTransform lat = lt==null?null:lt.getTransform(t.le);
370 if (uat==null) return lat;
371 if (lat==null) return uat;
373 double um[] = new double[6];
375 double lm[] = new double[6];
377 double rm[] = new double[6];
378 for (int i=0; i<6; i++)
379 rm[i] = um[i]*(1-t.phase) + lm[i]*(t.phase);
380 return new AffineTransform(rm);
384 public void setTransform(IElement e, AffineTransform at) {
390 public Rectangle2D getBounds(IElement e, Rectangle2D size) {
391 Transition t = getTransition(e);
392 InternalSize ub = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(InternalSize.class);
393 InternalSize lb = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(InternalSize.class);
394 Rectangle2D us = ub==null?null:ub.getBounds(t.ue, null);
395 Rectangle2D ls = lb==null?null:lb.getBounds(t.le, null);
396 if (ls==null && us==null) return null;
397 if (size==null) size = new Rectangle2D.Double();
398 if (ls==null && us!=null) {
402 if (us==null && ls!=null) {
407 double minX = us.getMinX() * (1-t.phase) + ls.getMinX() * (t.phase);
408 double minY = us.getMinY() * (1-t.phase) + ls.getMinY() * (t.phase);
409 double maxX = us.getMaxX() * (1-t.phase) + ls.getMaxX() * (t.phase);
410 double maxY = us.getMaxY() * (1-t.phase) + ls.getMaxY() * (t.phase);
412 size.setRect(minX, minY, maxX-minX, maxY-minY);
418 public double getArrowSize(IElement e, EdgeEnd end) {
419 Transition t = getTransition(e);
420 EdgeVisuals uev = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
421 EdgeVisuals lev = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
422 double us = uev==null?0:uev.getArrowSize(t.ue, end);
423 double ls = lev==null?0:lev.getArrowSize(t.le, end);
424 return us*(1-t.phase) + ls*(t.phase);
428 public StrokeType getStrokeType(IElement e) {
429 Transition t = getTransition(e);
430 EdgeVisuals uev = t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
431 EdgeVisuals lev = t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
432 StrokeType ust = uev==null?null:uev.getStrokeType(t.ue);
433 StrokeType lst = lev==null?null:lev.getStrokeType(t.le);
434 return ust==null?lst:ust;
438 public ArrowType getArrowType(IElement e, EdgeEnd end) {
439 Transition t = getTransition(e);
440 EdgeVisuals uev = t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
441 EdgeVisuals lev = t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
442 ArrowType uat = uev==null?null:uev.getArrowType(t.ue, end);
443 ArrowType lat = lev==null?null:lev.getArrowType(t.le, end);
444 return uat==null?lat:uat;
448 public Stroke getStroke(IElement e) {
449 Transition t = getTransition(e);
450 EdgeVisuals uev = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
451 EdgeVisuals lev = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
452 Stroke us = uev==null?null:uev.getStroke(t.ue);
453 Stroke ls = lev==null?null:lev.getStroke(t.le);
454 if (us==null) return ls;
455 if (ls==null) return us;
457 if (!(us instanceof BasicStroke) || !(ls instanceof BasicStroke))
459 BasicStroke bsu = (BasicStroke) us;
460 BasicStroke bsl = (BasicStroke) ls;
461 double width = bsu.getLineWidth() * (1-t.phase) + bsl.getLineWidth() * (t.phase);
463 return new BasicStroke(
473 public void setArrowSize(IElement e, EdgeEnd end, double size) {
477 public void setStrokeType(IElement e, StrokeType arrowType) {
481 public void setArrowType(IElement e, EdgeEnd end, ArrowType arrowType) {
485 public void setStroke(IElement e, Stroke s) {
492 public String getText(IElement e) {
493 Transition t = getTransition(e);
494 Text tu = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(Text.class);
495 Text tl = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(Text.class);
496 String su = tu==null?null:tu.getText(t.ue);
497 String sl = tl==null?null:tl.getText(t.le);
499 return su==null?sl:su;
503 public void setText(IElement e, String text) {
507 public Color getFillColor(IElement e) {
508 Transition t = getTransition(e);
509 Color uc = ElementUtils.getFillColor(t.ue);
510 Color lc = ElementUtils.getFillColor(t.le);
511 if (uc==null) return lc;
512 if (lc==null) return uc;
513 return GeometryUtils.interpolate(uc, lc, t.phase);
516 public void setFillColor(IElement e, Color c) {
519 public Color getBorderColor(IElement e) {
520 Transition t = getTransition(e);
521 Color uc = ElementUtils.getBorderColor(t.ue);
522 Color lc = ElementUtils.getBorderColor(t.le);
523 if (uc==null) return lc;
524 if (lc==null) return uc;
525 return GeometryUtils.interpolate(uc, lc, t.phase);
529 public void setBorderColor(IElement e, Color c) {
533 public Color getAdditionalColor(IElement e) {
534 Transition t = getTransition(e);
535 Color uc = ElementUtils.getAdditionalColor(t.ue);
536 Color lc = ElementUtils.getAdditionalColor(t.le);
537 if (uc==null) return lc;
538 if (lc==null) return uc;
539 return GeometryUtils.interpolate(uc, lc, t.phase);
543 public void setAdditionalColor(IElement e, Color c) {
547 public Color getTextColor(IElement e) {
548 Transition t = getTransition(e);
549 Color uc = ElementUtils.getTextColor(t.ue);
550 Color lc = ElementUtils.getTextColor(t.le);
551 if (uc==null) return lc;
552 if (lc==null) return uc;
553 return GeometryUtils.interpolate(uc, lc, t.phase);
557 public void setTextColor(IElement e, Color c) {
561 public AngleType getAngleType(IElement e) {
562 Transition t = getTransition(e);
563 BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
564 BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
565 if (ueb!=null) return ueb.getAngleType(t.ue);
566 if (leb!=null) return leb.getAngleType(t.le);
570 public void setAngleType(IElement e, AngleType angleType) {
573 public Bend addBend(IElement e, int index, Point2D pos) {
577 public void getBendPosition(IElement e, Bend b, Point2D pos) {
578 // TODO make better later
579 Transition t = getTransition(e);
580 BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
581 BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
582 if (ueb!=null) ueb.getBendPosition(e, b, pos);
583 if (leb!=null) leb.getBendPosition(e, b, pos);
586 public void getBends(IElement e, List<Bend> bends) {
587 // TODO make better later
588 Transition t = getTransition(e);
589 BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
590 BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
591 if (ueb!=null) ueb.getBends(e, bends);
592 if (leb!=null) leb.getBends(e, bends);
595 public boolean removeBend(IElement e, Bend b) {
600 public Path2D getPath(IElement e) {
601 Transition t = getTransition(e);
602 BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
603 BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
604 if (ueb==null && leb==null) return null;
605 if (ueb==null) return leb.getPath(t.le);
606 if (leb==null) return ueb.getPath(t.ue);
607 Path2D up = ueb.getPath(t.ue);
608 Path2D lp = leb.getPath(t.le);
609 // interpolate two paths
610 return PathUtils2.interpolatePaths(up, lp, t.phase);
614 public void setPath(IElement e, Path2D p) {
618 public int getBendsCount(IElement e) {
619 Transition t = getTransition(e);
620 BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
621 BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
622 if (leb!=null) return leb.getBendsCount(t.le);
623 if (ueb!=null) return ueb.getBendsCount(t.ue);
628 public void moveBend(IElement e, Bend b, Point2D pos) {
629 // TODO Auto-generated method stub
634 public void cleanup(IElement e) {
635 // TODO Auto-generated method stub
640 public void init(IElement e, G2DParentNode parent) {
641 Transition t = getTransition(e);
642 List<SceneGraph> empty = Collections.EMPTY_LIST;
643 List<SceneGraph> ups = t.ue==null?empty:t.ue.getElementClass().getItemsByClass(SceneGraph.class);
644 List<SceneGraph> lps = t.le==null?empty:t.le.getElementClass().getItemsByClass(SceneGraph.class);
646 if (ObjectUtils.equals(ups, lps))
648 for (SceneGraph lp : lps)
653 if (!lps.isEmpty()) {
654 for (SceneGraph lp : lps)
656 lp.init(t.le, parent);
660 if (!ups.isEmpty()) {
661 for (SceneGraph up : ups)
663 up.init(t.ue, parent);
671 private static WeakHashMap<ElementClass, ElementClass> FADEIN_CLASSES =
672 new WeakHashMap<ElementClass, ElementClass>();
673 private static WeakHashMap<ElementClass, ElementClass> FADEOUT_CLASSES =
674 new WeakHashMap<ElementClass, ElementClass>();
675 public synchronized static ElementClass getFadeElementClass(ElementClass origClass, FadeDir dir)
679 ElementClass proxyClass = FADEIN_CLASSES.get(origClass);
680 if (proxyClass==null) {
681 proxyClass = createFadeElementClass(origClass, dir);
682 FADEIN_CLASSES.put(origClass, proxyClass);
686 ElementClass proxyClass = FADEOUT_CLASSES.get(origClass);
687 if (proxyClass==null) {
688 proxyClass = createFadeElementClass(origClass, dir);
689 FADEOUT_CLASSES.put(origClass, proxyClass);
695 private static final IProxyProvider PROXY_PROVIDER =
696 new IProxyProvider() {
698 public IElement provide(IElement src) {
699 return src.getHint(KEY_SOURCE_ELEMENT);
703 static ElementClass createFadeElementClass(ElementClass clazz, FadeDir dir)
705 List<ElementHandler> result = new ArrayList<ElementHandler>();
706 List<ElementHandler> lst = new ArrayList<ElementHandler>();
707 for (ElementHandler eh : clazz.getAll())
710 ProxyHandler.addProxyElementHandlers(eh, PROXY_PROVIDER, lst);
711 for (ElementHandler eh2 : lst)
713 if (eh2 instanceof ProxyLifeCycle) continue;
714 if (eh2 instanceof TerminalTopology) continue;
716 if (eh2 instanceof SceneGraph) {
717 result.add( new ProxyFadePaint(dir, (SceneGraph)eh) );
723 return ElementClass.compile(result);
726 static class ProxyFadePaint implements SceneGraph {
730 private static final long serialVersionUID = 3559624682436513231L;
731 static enum FadeDir {In, Out};
734 public ProxyFadePaint(FadeDir dir, SceneGraph orig) {
739 public static IElement getSource(IElement element)
741 return element.getHint(KEY_SOURCE_ELEMENT);
743 public double getPhase(IElement element)
745 Double phase = element.getDiagram().getHint(KEY_PHASE);
746 if (phase==null) phase = 0.0;
747 if (dir == FadeDir.Out) phase = 1-phase;
751 public void cleanup(IElement e) {
752 IElement sourceElement = getSource(e);
753 orig.cleanup(sourceElement);
756 public void init(IElement e, G2DParentNode parent) {
757 IElement sourceElement = getSource(e);
758 orig.init(sourceElement, parent);
762 static class MorphTopologyImpl implements Topology {
765 public void connect(IElement edge, EdgeEnd end, IElement node, Terminal terminal) {
769 public void disconnect(IElement edge, EdgeEnd end, IElement node, Terminal terminal) {
773 public Connection getConnection(IElement edge, EdgeEnd end) {
778 public void getConnections(IElement node, Terminal terminal, Collection<Connection> connections) {