X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fmultileveldiagram%2FTransitionDiagram.java;h=90186e8003efbe97ece066dc4cb38a7156924e7b;hb=31000619;hp=517aadbe22033e1008e25499d44ae830fcf5cb45;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git
diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/multileveldiagram/TransitionDiagram.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/multileveldiagram/TransitionDiagram.java
index 517aadbe2..90186e800 100644
--- a/bundles/org.simantics.g2d/src/org/simantics/g2d/multileveldiagram/TransitionDiagram.java
+++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/multileveldiagram/TransitionDiagram.java
@@ -1,783 +1,783 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management
- * in Industry THTH ry.
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * VTT Technical Research Centre of Finland - initial API and implementation
- *******************************************************************************/
-package org.simantics.g2d.multileveldiagram;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Stroke;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Path2D;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import org.simantics.g2d.diagram.DiagramClass;
-import org.simantics.g2d.diagram.IDiagram;
-import org.simantics.g2d.diagram.handler.DataElementMap;
-import org.simantics.g2d.diagram.handler.LifeCycle;
-import org.simantics.g2d.diagram.handler.Topology;
-import org.simantics.g2d.diagram.handler.impl.DataElementMapImpl;
-import org.simantics.g2d.diagram.handler.impl.PickContextImpl;
-import org.simantics.g2d.diagram.handler.impl.TransactionContextImpl;
-import org.simantics.g2d.diagram.impl.AbstractDiagram;
-import org.simantics.g2d.element.ElementClass;
-import org.simantics.g2d.element.ElementHints;
-import org.simantics.g2d.element.ElementUtils;
-import org.simantics.g2d.element.IElement;
-import org.simantics.g2d.element.handler.AdditionalColor;
-import org.simantics.g2d.element.handler.BendsHandler;
-import org.simantics.g2d.element.handler.BorderColor;
-import org.simantics.g2d.element.handler.EdgeVisuals;
-import org.simantics.g2d.element.handler.ElementHandler;
-import org.simantics.g2d.element.handler.FillColor;
-import org.simantics.g2d.element.handler.InternalSize;
-import org.simantics.g2d.element.handler.SceneGraph;
-import org.simantics.g2d.element.handler.TerminalTopology;
-import org.simantics.g2d.element.handler.Text;
-import org.simantics.g2d.element.handler.TextColor;
-import org.simantics.g2d.element.handler.Transform;
-import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
-import org.simantics.g2d.element.handler.impl.MoveImpl;
-import org.simantics.g2d.element.handler.impl.proxy.IProxyProvider;
-import org.simantics.g2d.element.handler.impl.proxy.ProxyHandler;
-import org.simantics.g2d.element.handler.impl.proxy.ProxyLifeCycle;
-import org.simantics.g2d.element.impl.Element;
-import org.simantics.g2d.multileveldiagram.TransitionDiagram.ProxyFadePaint.FadeDir;
-import org.simantics.g2d.utils.GeometryUtils;
-import org.simantics.g2d.utils.PathUtils2;
-import org.simantics.scenegraph.g2d.G2DParentNode;
-import org.simantics.utils.ObjectUtils;
-import org.simantics.utils.datastructures.hints.HintContext;
-
-/**
- * Transition diagram is a diagram that is a transition between two diagrams.
- * Diagram in transition cannot be edited.
- * There is always upper and lower diagram.
- * There are different trasition effects : Morph and blend
- *
- * TODO monitor upper and lower diagrams for element changes
- * TODO monitor upper and lower elements for KEY_OBJECT changes
- *
- * @author Toni Kalajainen
- */
-public class TransitionDiagram extends AbstractDiagram {
-
- TransitionDiagram() {
- super(TRANSITION_DIAGRAM_CLASS, new HintContext());
- }
-
- public static final Key KEY_UPPER_DIAGRAM = new KeyOf(IDiagram.class);
- public static final Key KEY_LOWER_DIAGRAM = new KeyOf(IDiagram.class);
- public static final Key KEY_TRANSITION_CLASS = new KeyOf(ElementClass.class);
-
- /** Element keys refering to elements of source diagram */
- public static final Key KEY_UPPER_ELEMENT = new KeyOf(IElement.class);
- public static final Key KEY_LOWER_ELEMENT = new KeyOf(IElement.class);
- public static final Key KEY_SOURCE_ELEMENT = new KeyOf(IElement.class);
-
- /** Diagram hint, transition phase, value between 0..1, 0=upper, 1=lower */
- public static final Key KEY_PHASE = new KeyOf(Double.class);
-
- public static final ElementClass MORPH_ELEMENT_CLASS = ElementClass.compile(MorphElementHandler.INSTANCE, MoveImpl.HANDLER);
-
- public static final DiagramClass TRANSITION_DIAGRAM_CLASS = DiagramClass.compile(
- new PickContextImpl(),
- new TransactionContextImpl(),
- new MorphTopologyImpl(),
- new TransitionDiagramHandler(),
- new DataElementMapImpl()
- );
-
- public static final IDiagram createTransitionDiagram(IDiagram upperDiagram, IDiagram lowerDiagram, ElementClass transitionClass)
- {
- assert(upperDiagram!=null && lowerDiagram!=null && transitionClass!=null);
- TransitionDiagram d = new TransitionDiagram();
- d.setHint(KEY_TRANSITION_CLASS, transitionClass);
- d.setHint(KEY_UPPER_DIAGRAM, upperDiagram);
- d.setHint(KEY_LOWER_DIAGRAM, lowerDiagram);
- d.fireCreated();
- return d;
- }
-
- IDiagram upperDiagram, lowerDiagram;
-
- /**
- * Set a new element class to an element
- * @param d
- * @param e
- * @param clazz
- * @return new element
- */
- private static IElement setElementClass(IElement e, ElementClass clazz)
- {
- IDiagram d = e.getDiagram();
- if (e.getElementClass().equals(clazz)) return e;
- Map hints = e.getHints();
- int index = d.getElements().indexOf(e);
- d.removeElement(e);
- e.destroy();
- e = Element.spawnNew(clazz);
- e.setHints(hints);
- d.addElement(e);
- d.moveTo(e, index);
- return e;
- }
-
- static class TransitionDiagramHandler implements LifeCycle {
-
- private static final Key KEY_COMPOSITION_LISTENER =
- new KeyOf(CompositionListener.class);
-
- @Override
- public void onDiagramCreated(final IDiagram transitionDiagram) {
- // 1. listen to
- CompositionListener cl = new CompositionListener() {
- @Override
- public void onElementAdded(IDiagram diagram, IElement element) {
- IDiagram upperDiagram = transitionDiagram.getHint(KEY_UPPER_DIAGRAM);
- IDiagram lowerDiagram = transitionDiagram.getHint(KEY_LOWER_DIAGRAM);
- boolean isUpper = diagram == upperDiagram;
- IDiagram oppositeDiagram = isUpper ? lowerDiagram : upperDiagram;
- // Element has been added to either upper or lower diagram
- DataElementMap m = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
- Object data = m.getData(diagram, element);
-
- // Check if the opposite diagram has a valid counter part
- m = oppositeDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
- IElement counterPart = data==null?null:m.getElement(oppositeDiagram, data);
-
-
- ElementClass clazz;
- // Element has a counter-part, therefore it can be morphed
- if (counterPart!=null) {
- clazz = MORPH_ELEMENT_CLASS;
- } else
- // There is no counterpart, therefore it is a fading element
- {
- FadeDir dir = isUpper ? FadeDir.Out : FadeDir.In;
- clazz = getFadeElementClass(element.getElementClass(), dir);
- }
-
- // Check if transition element already exists
- m = transitionDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
- IElement transitionElement = m.getElement(transitionDiagram, data);
- if (transitionElement!=null) {
- setElementClass(transitionElement, clazz);
- return;
- }
-
- transitionElement = Element.instantiate(clazz, null);
-
- // Element has a counter-part, therefore it can be morphed
- if (counterPart!=null) {
- transitionElement.setHint(KEY_UPPER_ELEMENT, isUpper?element:counterPart);
- transitionElement.setHint(KEY_LOWER_ELEMENT, isUpper?counterPart:element);
- } else
- // There is no counterpart, therefore it is a fading element
- {
- transitionElement.setHint(KEY_SOURCE_ELEMENT, element);
- }
-
- if (data!=null)
- transitionElement.setHint(ElementHints.KEY_OBJECT, data);
- Element.fireCreated(transitionElement);
- transitionDiagram.addElement(transitionElement);
-
- }
- @Override
- public void onElementRemoved(IDiagram diagram, IElement element) {
- IDiagram upperDiagram = transitionDiagram.getHint(KEY_UPPER_DIAGRAM);
- IDiagram lowerDiagram = transitionDiagram.getHint(KEY_LOWER_DIAGRAM);
- boolean isUpper = diagram == upperDiagram;
- IDiagram oppositeDiagram = isUpper ? lowerDiagram : upperDiagram;
- // Element has been added to either upper or lower diagram
- DataElementMap m = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
- Object data = m.getData(diagram, element);
-
- // Check if the opposite diagram has a valid counter part
- m = oppositeDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
- IElement counterPart = data==null?null:m.getElement(oppositeDiagram, data);
-
- // Check if transition element already exists
- m = transitionDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
- IElement transitionElement = m.getElement(transitionDiagram, data);
- if (transitionElement==null) {
- for (IElement e : transitionDiagram.getElements())
- if (e.getHint(KEY_SOURCE_ELEMENT) == element)
- {
- transitionElement = e;
- break;
- }
- }
- // There is a mix-up .. not too serious
- if (transitionElement==null)
- return;
-
- // if class is morph and the counter part remains, transform transition element to fade element
- if (transitionElement.getElementClass().equals(MORPH_ELEMENT_CLASS) &&
- counterPart != null)
- {
- FadeDir dir = isUpper ? FadeDir.Out : FadeDir.In;
- ElementClass clazz = getFadeElementClass(element.getElementClass(), dir);
- transitionElement.removeHint(KEY_UPPER_ELEMENT);
- transitionElement.removeHint(KEY_LOWER_ELEMENT);
- setElementClass(transitionElement, clazz);
- transitionElement.setHint(KEY_SOURCE_ELEMENT, counterPart);
- } else {
- transitionDiagram.removeElement(transitionElement);
- transitionElement.destroy();
- }
- }
- };
- IDiagram upperDiagram = transitionDiagram.getHint(KEY_UPPER_DIAGRAM);
- IDiagram lowerDiagram = transitionDiagram.getHint(KEY_LOWER_DIAGRAM);
- upperDiagram.addCompositionListener(cl);
- lowerDiagram.addCompositionListener(cl);
- transitionDiagram.setHint(KEY_COMPOSITION_LISTENER, cl);
-
- // Add elements
- for (IElement e : upperDiagram.getElements())
- cl.onElementAdded(upperDiagram, e);
- for (IElement e : lowerDiagram.getElements())
- cl.onElementAdded(lowerDiagram, e);
- }
-
- @Override
- public void onDiagramDisposed(IDiagram diagram) {
- // Remove listener
- CompositionListener cl = diagram.getHint(KEY_COMPOSITION_LISTENER);
- IDiagram upperDiagram = diagram.getHint(KEY_UPPER_DIAGRAM);
- IDiagram lowerDiagram = diagram.getHint(KEY_LOWER_DIAGRAM);
- upperDiagram.removeCompositionListener(cl);
- lowerDiagram.removeCompositionListener(cl);
- diagram.removeHint(KEY_COMPOSITION_LISTENER);
- }
-
- @Override
- public void onDiagramDestroyed(IDiagram diagram) {}
- @Override
- public void onDiagramLoaded(IDiagram diagram, Collection initialElements) {}
-
- }
-
- // TODO REMOVE REDUNDANCY == Transitions to void
- // In morph element handler there is always 2 counter parts
- static class MorphElementHandler implements SceneGraph, FillColor, BorderColor, AdditionalColor, TextColor, Transform, InternalSize, EdgeVisuals, BendsHandler, Text {
-
- private static final long serialVersionUID = 1907473087657477787L;
-
- public static final MorphElementHandler INSTANCE = new MorphElementHandler();
-
- /** key for sub-diagram -> element Map */
- public final static Key KEY_ELEMENT_MAP = new KeyOf(Map.class);
-
- static IElement getUpperSourceElement(IElement e)
- {
- return e.getHint(KEY_UPPER_ELEMENT);
- }
-
- static IElement getLowerSourceElement(IElement e)
- {
- return e.getHint(KEY_LOWER_ELEMENT);
- }
-
- /** Returns elements between when diagram is in transition */
- static Transition getTransition(IElement e)
- {
- Transition t = new Transition();
- Double phase = e.getDiagram().getHint(KEY_PHASE);
- t.le = getLowerSourceElement(e);
- t.ue = getUpperSourceElement(e);
- t.phase = phase;
- return t;
- }
-
- static private class Transition {
- // Upper Element and Lower Element
- IElement ue, le;
- double phase;
- }
-
-// @Override
-// public void paint(IElement e, ICanvasContext ctx,
-// GraphicsContext elementGC, GraphicsContext controlGC) {
-// Transition t = getTransition(e);
-// List empty = Collections.EMPTY_LIST;
-// List ups = t.ue==null?empty:t.ue.getElementClass().getItemsByClass(Paint.class);
-// List lps = t.le==null?empty:t.le.getElementClass().getItemsByClass(Paint.class);
-//
-// if (ObjectUtils.equals(ups, lps))
-// {
-// for (Paint lp : lps)
-// lp.paint(e, ctx, elementGC, controlGC);
-// return;
-// }
-//
-// if (!lps.isEmpty()) {
-//// Graphics2D g = elementGC.createClone();
-//// Graphics2D g2 = controlGC.createClone();
-//// Composite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float)t.phase);
-//// g.setComposite(c);
-//// g2.setComposite(c);
-// GraphicsContextImpl newCtx = new GraphicsContextImpl(elementGC.getBounds(), elementGC.getNode());
-// GraphicsContextImpl newCtx2 = new GraphicsContextImpl(controlGC.getBounds(), controlGC.getNode());
-// for (Paint lp : lps)
-// {
-// lp.paint(t.le, ctx, newCtx, newCtx2);
-// }
-// newCtx.dispose();
-// newCtx2.dispose();
-// }
-//
-// if (!ups.isEmpty()) {
-//// Graphics2D g = elementGC.createClone();
-//// Graphics2D g2 = controlGC.createClone();
-//// Composite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1-(float)t.phase);
-//// g.setComposite(c);
-//// g2.setComposite(c);
-// GraphicsContextImpl newCtx = new GraphicsContextImpl(elementGC.getBounds(), elementGC.getNode());
-// GraphicsContextImpl newCtx2 = new GraphicsContextImpl(controlGC.getBounds(), controlGC.getNode());
-// for (Paint up : ups)
-// {
-// up.paint(t.ue, ctx, newCtx, newCtx2);
-// }
-// newCtx.dispose();
-// newCtx2.dispose();
-// }
-// }
-
- @Override
- public AffineTransform getTransform(IElement e) {
- Transition t = getTransition(e);
- Transform ut = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(Transform.class);
- Transform lt = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(Transform.class);
- AffineTransform uat = ut==null?null:ut.getTransform(t.ue);
- AffineTransform lat = lt==null?null:lt.getTransform(t.le);
- if (uat==null) return lat;
- if (lat==null) return uat;
- // interpolate
- double um[] = new double[6];
- uat.getMatrix(um);
- double lm[] = new double[6];
- lat.getMatrix(lm);
- double rm[] = new double[6];
- for (int i=0; i<6; i++)
- rm[i] = um[i]*(1-t.phase) + lm[i]*(t.phase);
- return new AffineTransform(rm);
- }
-
- @Override
- public void setTransform(IElement e, AffineTransform at) {
- }
-
- // Bounds
-
- @Override
- public Rectangle2D getBounds(IElement e, Rectangle2D size) {
- Transition t = getTransition(e);
- InternalSize ub = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(InternalSize.class);
- InternalSize lb = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(InternalSize.class);
- Rectangle2D us = ub==null?null:ub.getBounds(t.ue, null);
- Rectangle2D ls = lb==null?null:lb.getBounds(t.le, null);
- if (ls==null && us==null) return null;
- if (size==null) size = new Rectangle2D.Double();
- if (ls==null && us!=null) {
- size.setRect(us);
- return size;
- }
- if (us==null && ls!=null) {
- size.setRect(ls);
- return size;
- }
- // interpolate
- double minX = us.getMinX() * (1-t.phase) + ls.getMinX() * (t.phase);
- double minY = us.getMinY() * (1-t.phase) + ls.getMinY() * (t.phase);
- double maxX = us.getMaxX() * (1-t.phase) + ls.getMaxX() * (t.phase);
- double maxY = us.getMaxY() * (1-t.phase) + ls.getMaxY() * (t.phase);
-
- size.setRect(minX, minY, maxX-minX, maxY-minY);
- return size;
- }
-
-
- @Override
- public double getArrowSize(IElement e, EdgeEnd end) {
- Transition t = getTransition(e);
- EdgeVisuals uev = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
- EdgeVisuals lev = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
- double us = uev==null?0:uev.getArrowSize(t.ue, end);
- double ls = lev==null?0:lev.getArrowSize(t.le, end);
- return us*(1-t.phase) + ls*(t.phase);
- }
-
- @Override
- public StrokeType getStrokeType(IElement e) {
- Transition t = getTransition(e);
- EdgeVisuals uev = t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
- EdgeVisuals lev = t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
- StrokeType ust = uev==null?null:uev.getStrokeType(t.ue);
- StrokeType lst = lev==null?null:lev.getStrokeType(t.le);
- return ust==null?lst:ust;
- }
-
- @Override
- public ArrowType getArrowType(IElement e, EdgeEnd end) {
- Transition t = getTransition(e);
- EdgeVisuals uev = t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
- EdgeVisuals lev = t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
- ArrowType uat = uev==null?null:uev.getArrowType(t.ue, end);
- ArrowType lat = lev==null?null:lev.getArrowType(t.le, end);
- return uat==null?lat:uat;
- }
-
- @Override
- public Stroke getStroke(IElement e) {
- Transition t = getTransition(e);
- EdgeVisuals uev = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
- EdgeVisuals lev = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
- Stroke us = uev==null?null:uev.getStroke(t.ue);
- Stroke ls = lev==null?null:lev.getStroke(t.le);
- if (us==null) return ls;
- if (ls==null) return us;
- // interpolate width
- if (!(us instanceof BasicStroke) || !(ls instanceof BasicStroke))
- return us;
- BasicStroke bsu = (BasicStroke) us;
- BasicStroke bsl = (BasicStroke) ls;
- double width = bsu.getLineWidth() * (1-t.phase) + bsl.getLineWidth() * (t.phase);
-
- return new BasicStroke(
- (float)width,
- bsu.getEndCap(),
- bsu.getLineJoin(),
- bsu.getMiterLimit(),
- bsu.getDashArray(),
- bsu.getDashPhase());
- }
-
- @Override
- public void setArrowSize(IElement e, EdgeEnd end, double size) {
- }
-
- @Override
- public void setStrokeType(IElement e, StrokeType arrowType) {
- }
-
- @Override
- public void setArrowType(IElement e, EdgeEnd end, ArrowType arrowType) {
- }
-
- @Override
- public void setStroke(IElement e, Stroke s) {
- }
-
-
-
-
- @Override
- public String getText(IElement e) {
- Transition t = getTransition(e);
- Text tu = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(Text.class);
- Text tl = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(Text.class);
- String su = tu==null?null:tu.getText(t.ue);
- String sl = tl==null?null:tl.getText(t.le);
-
- return su==null?sl:su;
- }
-
- @Override
- public void setText(IElement e, String text) {
- }
-
- @Override
- public Color getFillColor(IElement e) {
- Transition t = getTransition(e);
- Color uc = ElementUtils.getFillColor(t.ue);
- Color lc = ElementUtils.getFillColor(t.le);
- if (uc==null) return lc;
- if (lc==null) return uc;
- return GeometryUtils.interpolate(uc, lc, t.phase);
- }
- @Override
- public void setFillColor(IElement e, Color c) {
- }
- @Override
- public Color getBorderColor(IElement e) {
- Transition t = getTransition(e);
- Color uc = ElementUtils.getBorderColor(t.ue);
- Color lc = ElementUtils.getBorderColor(t.le);
- if (uc==null) return lc;
- if (lc==null) return uc;
- return GeometryUtils.interpolate(uc, lc, t.phase);
- }
-
- @Override
- public void setBorderColor(IElement e, Color c) {
- }
-
- @Override
- public Color getAdditionalColor(IElement e) {
- Transition t = getTransition(e);
- Color uc = ElementUtils.getAdditionalColor(t.ue);
- Color lc = ElementUtils.getAdditionalColor(t.le);
- if (uc==null) return lc;
- if (lc==null) return uc;
- return GeometryUtils.interpolate(uc, lc, t.phase);
- }
-
- @Override
- public void setAdditionalColor(IElement e, Color c) {
- }
-
- @Override
- public Color getTextColor(IElement e) {
- Transition t = getTransition(e);
- Color uc = ElementUtils.getTextColor(t.ue);
- Color lc = ElementUtils.getTextColor(t.le);
- if (uc==null) return lc;
- if (lc==null) return uc;
- return GeometryUtils.interpolate(uc, lc, t.phase);
- }
-
- @Override
- public void setTextColor(IElement e, Color c) {
- }
-
- @Override
- public AngleType getAngleType(IElement e) {
- Transition t = getTransition(e);
- BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- if (ueb!=null) return ueb.getAngleType(t.ue);
- if (leb!=null) return leb.getAngleType(t.le);
- return null;
- }
- @Override
- public void setAngleType(IElement e, AngleType angleType) {
- }
- @Override
- public Bend addBend(IElement e, int index, Point2D pos) {
- return null;
- }
- @Override
- public void getBendPosition(IElement e, Bend b, Point2D pos) {
- // TODO make better later
- Transition t = getTransition(e);
- BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- if (ueb!=null) ueb.getBendPosition(e, b, pos);
- if (leb!=null) leb.getBendPosition(e, b, pos);
- }
- @Override
- public void getBends(IElement e, List bends) {
- // TODO make better later
- Transition t = getTransition(e);
- BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- if (ueb!=null) ueb.getBends(e, bends);
- if (leb!=null) leb.getBends(e, bends);
- }
- @Override
- public boolean removeBend(IElement e, Bend b) {
- return false;
- }
-
- @Override
- public Path2D getPath(IElement e) {
- Transition t = getTransition(e);
- BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- if (ueb==null && leb==null) return null;
- if (ueb==null) return leb.getPath(t.le);
- if (leb==null) return ueb.getPath(t.ue);
- Path2D up = ueb.getPath(t.ue);
- Path2D lp = leb.getPath(t.le);
- // interpolate two paths
- return PathUtils2.interpolatePaths(up, lp, t.phase);
- }
-
- @Override
- public void setPath(IElement e, Path2D p) {
- }
-
- @Override
- public int getBendsCount(IElement e) {
- Transition t = getTransition(e);
- BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
- if (leb!=null) return leb.getBendsCount(t.le);
- if (ueb!=null) return ueb.getBendsCount(t.ue);
- return 0;
- }
-
- @Override
- public void moveBend(IElement e, Bend b, Point2D pos) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void cleanup(IElement e) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void init(IElement e, G2DParentNode parent) {
- Transition t = getTransition(e);
- List empty = Collections.EMPTY_LIST;
- List ups = t.ue==null?empty:t.ue.getElementClass().getItemsByClass(SceneGraph.class);
- List lps = t.le==null?empty:t.le.getElementClass().getItemsByClass(SceneGraph.class);
-
- if (ObjectUtils.equals(ups, lps))
- {
- for (SceneGraph lp : lps)
- lp.init(e, parent);
- return;
- }
-
- if (!lps.isEmpty()) {
- for (SceneGraph lp : lps)
- {
- lp.init(t.le, parent);
- }
- }
-
- if (!ups.isEmpty()) {
- for (SceneGraph up : ups)
- {
- up.init(t.ue, parent);
- }
- }
- }
-
- }
-
-
- private static WeakHashMap FADEIN_CLASSES =
- new WeakHashMap();
- private static WeakHashMap FADEOUT_CLASSES =
- new WeakHashMap();
- public synchronized static ElementClass getFadeElementClass(ElementClass origClass, FadeDir dir)
- {
- if (dir==FadeDir.In)
- {
- ElementClass proxyClass = FADEIN_CLASSES.get(origClass);
- if (proxyClass==null) {
- proxyClass = createFadeElementClass(origClass, dir);
- FADEIN_CLASSES.put(origClass, proxyClass);
- }
- return proxyClass;
- } else {
- ElementClass proxyClass = FADEOUT_CLASSES.get(origClass);
- if (proxyClass==null) {
- proxyClass = createFadeElementClass(origClass, dir);
- FADEOUT_CLASSES.put(origClass, proxyClass);
- }
- return proxyClass;
- }
- }
-
- private static final IProxyProvider PROXY_PROVIDER =
- new IProxyProvider() {
- @Override
- public IElement provide(IElement src) {
- return src.getHint(KEY_SOURCE_ELEMENT);
- }
- };
-
- static ElementClass createFadeElementClass(ElementClass clazz, FadeDir dir)
- {
- List result = new ArrayList();
- List lst = new ArrayList();
- for (ElementHandler eh : clazz.getAll())
- {
- lst.clear();
- ProxyHandler.addProxyElementHandlers(eh, PROXY_PROVIDER, lst);
- for (ElementHandler eh2 : lst)
- {
- if (eh2 instanceof ProxyLifeCycle) continue;
- if (eh2 instanceof TerminalTopology) continue;
-
- if (eh2 instanceof SceneGraph) {
- result.add( new ProxyFadePaint(dir, (SceneGraph)eh) );
- } else {
- result.add(eh2);
- }
- }
- }
- return ElementClass.compile(result);
- }
-
- static class ProxyFadePaint implements SceneGraph {
- /**
- *
- */
- private static final long serialVersionUID = 3559624682436513231L;
- static enum FadeDir {In, Out};
- FadeDir dir;
- SceneGraph orig;
- public ProxyFadePaint(FadeDir dir, SceneGraph orig) {
- this.dir = dir;
- this.orig = orig;
- assert(orig!=null);
- }
- public static IElement getSource(IElement element)
- {
- return element.getHint(KEY_SOURCE_ELEMENT);
- }
- public double getPhase(IElement element)
- {
- Double phase = element.getDiagram().getHint(KEY_PHASE);
- if (phase==null) phase = 0.0;
- if (dir == FadeDir.Out) phase = 1-phase;
- return phase;
- }
- @Override
- public void cleanup(IElement e) {
- IElement sourceElement = getSource(e);
- orig.cleanup(sourceElement);
- }
- @Override
- public void init(IElement e, G2DParentNode parent) {
- IElement sourceElement = getSource(e);
- orig.init(sourceElement, parent);
- }
- }
-
- static class MorphTopologyImpl implements Topology {
-
- @Override
- public void connect(IElement edge, EdgeEnd end, IElement node, Terminal terminal) {
- }
-
- @Override
- public void disconnect(IElement edge, EdgeEnd end, IElement node, Terminal terminal) {
- }
-
- @Override
- public Connection getConnection(IElement edge, EdgeEnd end) {
- return null;
- }
-
- @Override
- public void getConnections(IElement node, Terminal terminal, Collection connections) {
- }
-
- }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.g2d.multileveldiagram;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Stroke;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import org.simantics.g2d.diagram.DiagramClass;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.DataElementMap;
+import org.simantics.g2d.diagram.handler.LifeCycle;
+import org.simantics.g2d.diagram.handler.Topology;
+import org.simantics.g2d.diagram.handler.impl.DataElementMapImpl;
+import org.simantics.g2d.diagram.handler.impl.PickContextImpl;
+import org.simantics.g2d.diagram.handler.impl.TransactionContextImpl;
+import org.simantics.g2d.diagram.impl.AbstractDiagram;
+import org.simantics.g2d.element.ElementClass;
+import org.simantics.g2d.element.ElementHints;
+import org.simantics.g2d.element.ElementUtils;
+import org.simantics.g2d.element.IElement;
+import org.simantics.g2d.element.handler.AdditionalColor;
+import org.simantics.g2d.element.handler.BendsHandler;
+import org.simantics.g2d.element.handler.BorderColor;
+import org.simantics.g2d.element.handler.EdgeVisuals;
+import org.simantics.g2d.element.handler.ElementHandler;
+import org.simantics.g2d.element.handler.FillColor;
+import org.simantics.g2d.element.handler.InternalSize;
+import org.simantics.g2d.element.handler.SceneGraph;
+import org.simantics.g2d.element.handler.TerminalTopology;
+import org.simantics.g2d.element.handler.Text;
+import org.simantics.g2d.element.handler.TextColor;
+import org.simantics.g2d.element.handler.Transform;
+import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;
+import org.simantics.g2d.element.handler.impl.MoveImpl;
+import org.simantics.g2d.element.handler.impl.proxy.IProxyProvider;
+import org.simantics.g2d.element.handler.impl.proxy.ProxyHandler;
+import org.simantics.g2d.element.handler.impl.proxy.ProxyLifeCycle;
+import org.simantics.g2d.element.impl.Element;
+import org.simantics.g2d.multileveldiagram.TransitionDiagram.ProxyFadePaint.FadeDir;
+import org.simantics.g2d.utils.GeometryUtils;
+import org.simantics.g2d.utils.PathUtils2;
+import org.simantics.scenegraph.g2d.G2DParentNode;
+import org.simantics.utils.ObjectUtils;
+import org.simantics.utils.datastructures.hints.HintContext;
+
+/**
+ * Transition diagram is a diagram that is a transition between two diagrams.
+ * Diagram in transition cannot be edited.
+ * There is always upper and lower diagram.
+ * There are different trasition effects : Morph and blend
+ *
+ * TODO monitor upper and lower diagrams for element changes
+ * TODO monitor upper and lower elements for KEY_OBJECT changes
+ *
+ * @author Toni Kalajainen
+ */
+public class TransitionDiagram extends AbstractDiagram {
+
+ TransitionDiagram() {
+ super(TRANSITION_DIAGRAM_CLASS, new HintContext());
+ }
+
+ public static final Key KEY_UPPER_DIAGRAM = new KeyOf(IDiagram.class);
+ public static final Key KEY_LOWER_DIAGRAM = new KeyOf(IDiagram.class);
+ public static final Key KEY_TRANSITION_CLASS = new KeyOf(ElementClass.class);
+
+ /** Element keys refering to elements of source diagram */
+ public static final Key KEY_UPPER_ELEMENT = new KeyOf(IElement.class);
+ public static final Key KEY_LOWER_ELEMENT = new KeyOf(IElement.class);
+ public static final Key KEY_SOURCE_ELEMENT = new KeyOf(IElement.class);
+
+ /** Diagram hint, transition phase, value between 0..1, 0=upper, 1=lower */
+ public static final Key KEY_PHASE = new KeyOf(Double.class);
+
+ public static final ElementClass MORPH_ELEMENT_CLASS = ElementClass.compile(MorphElementHandler.INSTANCE, MoveImpl.HANDLER);
+
+ public static final DiagramClass TRANSITION_DIAGRAM_CLASS = DiagramClass.compile(
+ new PickContextImpl(),
+ new TransactionContextImpl(),
+ new MorphTopologyImpl(),
+ new TransitionDiagramHandler(),
+ new DataElementMapImpl()
+ );
+
+ public static final IDiagram createTransitionDiagram(IDiagram upperDiagram, IDiagram lowerDiagram, ElementClass transitionClass)
+ {
+ assert(upperDiagram!=null && lowerDiagram!=null && transitionClass!=null);
+ TransitionDiagram d = new TransitionDiagram();
+ d.setHint(KEY_TRANSITION_CLASS, transitionClass);
+ d.setHint(KEY_UPPER_DIAGRAM, upperDiagram);
+ d.setHint(KEY_LOWER_DIAGRAM, lowerDiagram);
+ d.fireCreated();
+ return d;
+ }
+
+ IDiagram upperDiagram, lowerDiagram;
+
+ /**
+ * Set a new element class to an element
+ * @param d
+ * @param e
+ * @param clazz
+ * @return new element
+ */
+ private static IElement setElementClass(IElement e, ElementClass clazz)
+ {
+ IDiagram d = e.getDiagram();
+ if (e.getElementClass().equals(clazz)) return e;
+ Map hints = e.getHints();
+ int index = d.getElements().indexOf(e);
+ d.removeElement(e);
+ e.destroy();
+ e = Element.spawnNew(clazz);
+ e.setHints(hints);
+ d.addElement(e);
+ d.moveTo(e, index);
+ return e;
+ }
+
+ static class TransitionDiagramHandler implements LifeCycle {
+
+ private static final Key KEY_COMPOSITION_LISTENER =
+ new KeyOf(CompositionListener.class);
+
+ @Override
+ public void onDiagramCreated(final IDiagram transitionDiagram) {
+ // 1. listen to
+ CompositionListener cl = new CompositionListener() {
+ @Override
+ public void onElementAdded(IDiagram diagram, IElement element) {
+ IDiagram upperDiagram = transitionDiagram.getHint(KEY_UPPER_DIAGRAM);
+ IDiagram lowerDiagram = transitionDiagram.getHint(KEY_LOWER_DIAGRAM);
+ boolean isUpper = diagram == upperDiagram;
+ IDiagram oppositeDiagram = isUpper ? lowerDiagram : upperDiagram;
+ // Element has been added to either upper or lower diagram
+ DataElementMap m = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
+ Object data = m.getData(diagram, element);
+
+ // Check if the opposite diagram has a valid counter part
+ m = oppositeDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
+ IElement counterPart = data==null?null:m.getElement(oppositeDiagram, data);
+
+
+ ElementClass clazz;
+ // Element has a counter-part, therefore it can be morphed
+ if (counterPart!=null) {
+ clazz = MORPH_ELEMENT_CLASS;
+ } else
+ // There is no counterpart, therefore it is a fading element
+ {
+ FadeDir dir = isUpper ? FadeDir.Out : FadeDir.In;
+ clazz = getFadeElementClass(element.getElementClass(), dir);
+ }
+
+ // Check if transition element already exists
+ m = transitionDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
+ IElement transitionElement = m.getElement(transitionDiagram, data);
+ if (transitionElement!=null) {
+ setElementClass(transitionElement, clazz);
+ return;
+ }
+
+ transitionElement = Element.instantiate(clazz, null);
+
+ // Element has a counter-part, therefore it can be morphed
+ if (counterPart!=null) {
+ transitionElement.setHint(KEY_UPPER_ELEMENT, isUpper?element:counterPart);
+ transitionElement.setHint(KEY_LOWER_ELEMENT, isUpper?counterPart:element);
+ } else
+ // There is no counterpart, therefore it is a fading element
+ {
+ transitionElement.setHint(KEY_SOURCE_ELEMENT, element);
+ }
+
+ if (data!=null)
+ transitionElement.setHint(ElementHints.KEY_OBJECT, data);
+ Element.fireCreated(transitionElement);
+ transitionDiagram.addElement(transitionElement);
+
+ }
+ @Override
+ public void onElementRemoved(IDiagram diagram, IElement element) {
+ IDiagram upperDiagram = transitionDiagram.getHint(KEY_UPPER_DIAGRAM);
+ IDiagram lowerDiagram = transitionDiagram.getHint(KEY_LOWER_DIAGRAM);
+ boolean isUpper = diagram == upperDiagram;
+ IDiagram oppositeDiagram = isUpper ? lowerDiagram : upperDiagram;
+ // Element has been added to either upper or lower diagram
+ DataElementMap m = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
+ Object data = m.getData(diagram, element);
+
+ // Check if the opposite diagram has a valid counter part
+ m = oppositeDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
+ IElement counterPart = data==null?null:m.getElement(oppositeDiagram, data);
+
+ // Check if transition element already exists
+ m = transitionDiagram.getDiagramClass().getSingleItem(DataElementMap.class);
+ IElement transitionElement = m.getElement(transitionDiagram, data);
+ if (transitionElement==null) {
+ for (IElement e : transitionDiagram.getElements())
+ if (e.getHint(KEY_SOURCE_ELEMENT) == element)
+ {
+ transitionElement = e;
+ break;
+ }
+ }
+ // There is a mix-up .. not too serious
+ if (transitionElement==null)
+ return;
+
+ // if class is morph and the counter part remains, transform transition element to fade element
+ if (transitionElement.getElementClass().equals(MORPH_ELEMENT_CLASS) &&
+ counterPart != null)
+ {
+ FadeDir dir = isUpper ? FadeDir.Out : FadeDir.In;
+ ElementClass clazz = getFadeElementClass(element.getElementClass(), dir);
+ transitionElement.removeHint(KEY_UPPER_ELEMENT);
+ transitionElement.removeHint(KEY_LOWER_ELEMENT);
+ setElementClass(transitionElement, clazz);
+ transitionElement.setHint(KEY_SOURCE_ELEMENT, counterPart);
+ } else {
+ transitionDiagram.removeElement(transitionElement);
+ transitionElement.destroy();
+ }
+ }
+ };
+ IDiagram upperDiagram = transitionDiagram.getHint(KEY_UPPER_DIAGRAM);
+ IDiagram lowerDiagram = transitionDiagram.getHint(KEY_LOWER_DIAGRAM);
+ upperDiagram.addCompositionListener(cl);
+ lowerDiagram.addCompositionListener(cl);
+ transitionDiagram.setHint(KEY_COMPOSITION_LISTENER, cl);
+
+ // Add elements
+ for (IElement e : upperDiagram.getElements())
+ cl.onElementAdded(upperDiagram, e);
+ for (IElement e : lowerDiagram.getElements())
+ cl.onElementAdded(lowerDiagram, e);
+ }
+
+ @Override
+ public void onDiagramDisposed(IDiagram diagram) {
+ // Remove listener
+ CompositionListener cl = diagram.getHint(KEY_COMPOSITION_LISTENER);
+ IDiagram upperDiagram = diagram.getHint(KEY_UPPER_DIAGRAM);
+ IDiagram lowerDiagram = diagram.getHint(KEY_LOWER_DIAGRAM);
+ upperDiagram.removeCompositionListener(cl);
+ lowerDiagram.removeCompositionListener(cl);
+ diagram.removeHint(KEY_COMPOSITION_LISTENER);
+ }
+
+ @Override
+ public void onDiagramDestroyed(IDiagram diagram) {}
+ @Override
+ public void onDiagramLoaded(IDiagram diagram, Collection initialElements) {}
+
+ }
+
+ // TODO REMOVE REDUNDANCY == Transitions to void
+ // In morph element handler there is always 2 counter parts
+ static class MorphElementHandler implements SceneGraph, FillColor, BorderColor, AdditionalColor, TextColor, Transform, InternalSize, EdgeVisuals, BendsHandler, Text {
+
+ private static final long serialVersionUID = 1907473087657477787L;
+
+ public static final MorphElementHandler INSTANCE = new MorphElementHandler();
+
+ /** key for sub-diagram -> element Map */
+ public final static Key KEY_ELEMENT_MAP = new KeyOf(Map.class);
+
+ static IElement getUpperSourceElement(IElement e)
+ {
+ return e.getHint(KEY_UPPER_ELEMENT);
+ }
+
+ static IElement getLowerSourceElement(IElement e)
+ {
+ return e.getHint(KEY_LOWER_ELEMENT);
+ }
+
+ /** Returns elements between when diagram is in transition */
+ static Transition getTransition(IElement e)
+ {
+ Transition t = new Transition();
+ Double phase = e.getDiagram().getHint(KEY_PHASE);
+ t.le = getLowerSourceElement(e);
+ t.ue = getUpperSourceElement(e);
+ t.phase = phase;
+ return t;
+ }
+
+ static private class Transition {
+ // Upper Element and Lower Element
+ IElement ue, le;
+ double phase;
+ }
+
+// @Override
+// public void paint(IElement e, ICanvasContext ctx,
+// GraphicsContext elementGC, GraphicsContext controlGC) {
+// Transition t = getTransition(e);
+// List empty = Collections.EMPTY_LIST;
+// List ups = t.ue==null?empty:t.ue.getElementClass().getItemsByClass(Paint.class);
+// List lps = t.le==null?empty:t.le.getElementClass().getItemsByClass(Paint.class);
+//
+// if (ObjectUtils.equals(ups, lps))
+// {
+// for (Paint lp : lps)
+// lp.paint(e, ctx, elementGC, controlGC);
+// return;
+// }
+//
+// if (!lps.isEmpty()) {
+//// Graphics2D g = elementGC.createClone();
+//// Graphics2D g2 = controlGC.createClone();
+//// Composite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float)t.phase);
+//// g.setComposite(c);
+//// g2.setComposite(c);
+// GraphicsContextImpl newCtx = new GraphicsContextImpl(elementGC.getBounds(), elementGC.getNode());
+// GraphicsContextImpl newCtx2 = new GraphicsContextImpl(controlGC.getBounds(), controlGC.getNode());
+// for (Paint lp : lps)
+// {
+// lp.paint(t.le, ctx, newCtx, newCtx2);
+// }
+// newCtx.dispose();
+// newCtx2.dispose();
+// }
+//
+// if (!ups.isEmpty()) {
+//// Graphics2D g = elementGC.createClone();
+//// Graphics2D g2 = controlGC.createClone();
+//// Composite c = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1-(float)t.phase);
+//// g.setComposite(c);
+//// g2.setComposite(c);
+// GraphicsContextImpl newCtx = new GraphicsContextImpl(elementGC.getBounds(), elementGC.getNode());
+// GraphicsContextImpl newCtx2 = new GraphicsContextImpl(controlGC.getBounds(), controlGC.getNode());
+// for (Paint up : ups)
+// {
+// up.paint(t.ue, ctx, newCtx, newCtx2);
+// }
+// newCtx.dispose();
+// newCtx2.dispose();
+// }
+// }
+
+ @Override
+ public AffineTransform getTransform(IElement e) {
+ Transition t = getTransition(e);
+ Transform ut = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(Transform.class);
+ Transform lt = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(Transform.class);
+ AffineTransform uat = ut==null?null:ut.getTransform(t.ue);
+ AffineTransform lat = lt==null?null:lt.getTransform(t.le);
+ if (uat==null) return lat;
+ if (lat==null) return uat;
+ // interpolate
+ double um[] = new double[6];
+ uat.getMatrix(um);
+ double lm[] = new double[6];
+ lat.getMatrix(lm);
+ double rm[] = new double[6];
+ for (int i=0; i<6; i++)
+ rm[i] = um[i]*(1-t.phase) + lm[i]*(t.phase);
+ return new AffineTransform(rm);
+ }
+
+ @Override
+ public void setTransform(IElement e, AffineTransform at) {
+ }
+
+ // Bounds
+
+ @Override
+ public Rectangle2D getBounds(IElement e, Rectangle2D size) {
+ Transition t = getTransition(e);
+ InternalSize ub = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(InternalSize.class);
+ InternalSize lb = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(InternalSize.class);
+ Rectangle2D us = ub==null?null:ub.getBounds(t.ue, null);
+ Rectangle2D ls = lb==null?null:lb.getBounds(t.le, null);
+ if (ls==null && us==null) return null;
+ if (size==null) size = new Rectangle2D.Double();
+ if (ls==null && us!=null) {
+ size.setRect(us);
+ return size;
+ }
+ if (us==null && ls!=null) {
+ size.setRect(ls);
+ return size;
+ }
+ // interpolate
+ double minX = us.getMinX() * (1-t.phase) + ls.getMinX() * (t.phase);
+ double minY = us.getMinY() * (1-t.phase) + ls.getMinY() * (t.phase);
+ double maxX = us.getMaxX() * (1-t.phase) + ls.getMaxX() * (t.phase);
+ double maxY = us.getMaxY() * (1-t.phase) + ls.getMaxY() * (t.phase);
+
+ size.setRect(minX, minY, maxX-minX, maxY-minY);
+ return size;
+ }
+
+
+ @Override
+ public double getArrowSize(IElement e, EdgeEnd end) {
+ Transition t = getTransition(e);
+ EdgeVisuals uev = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
+ EdgeVisuals lev = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
+ double us = uev==null?0:uev.getArrowSize(t.ue, end);
+ double ls = lev==null?0:lev.getArrowSize(t.le, end);
+ return us*(1-t.phase) + ls*(t.phase);
+ }
+
+ @Override
+ public StrokeType getStrokeType(IElement e) {
+ Transition t = getTransition(e);
+ EdgeVisuals uev = t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
+ EdgeVisuals lev = t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
+ StrokeType ust = uev==null?null:uev.getStrokeType(t.ue);
+ StrokeType lst = lev==null?null:lev.getStrokeType(t.le);
+ return ust==null?lst:ust;
+ }
+
+ @Override
+ public ArrowType getArrowType(IElement e, EdgeEnd end) {
+ Transition t = getTransition(e);
+ EdgeVisuals uev = t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
+ EdgeVisuals lev = t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
+ ArrowType uat = uev==null?null:uev.getArrowType(t.ue, end);
+ ArrowType lat = lev==null?null:lev.getArrowType(t.le, end);
+ return uat==null?lat:uat;
+ }
+
+ @Override
+ public Stroke getStroke(IElement e) {
+ Transition t = getTransition(e);
+ EdgeVisuals uev = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
+ EdgeVisuals lev = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(EdgeVisuals.class);
+ Stroke us = uev==null?null:uev.getStroke(t.ue);
+ Stroke ls = lev==null?null:lev.getStroke(t.le);
+ if (us==null) return ls;
+ if (ls==null) return us;
+ // interpolate width
+ if (!(us instanceof BasicStroke) || !(ls instanceof BasicStroke))
+ return us;
+ BasicStroke bsu = (BasicStroke) us;
+ BasicStroke bsl = (BasicStroke) ls;
+ double width = bsu.getLineWidth() * (1-t.phase) + bsl.getLineWidth() * (t.phase);
+
+ return new BasicStroke(
+ (float)width,
+ bsu.getEndCap(),
+ bsu.getLineJoin(),
+ bsu.getMiterLimit(),
+ bsu.getDashArray(),
+ bsu.getDashPhase());
+ }
+
+ @Override
+ public void setArrowSize(IElement e, EdgeEnd end, double size) {
+ }
+
+ @Override
+ public void setStrokeType(IElement e, StrokeType arrowType) {
+ }
+
+ @Override
+ public void setArrowType(IElement e, EdgeEnd end, ArrowType arrowType) {
+ }
+
+ @Override
+ public void setStroke(IElement e, Stroke s) {
+ }
+
+
+
+
+ @Override
+ public String getText(IElement e) {
+ Transition t = getTransition(e);
+ Text tu = t.ue==null?null:t.ue.getElementClass().getAtMostOneItemOfClass(Text.class);
+ Text tl = t.le==null?null:t.le.getElementClass().getAtMostOneItemOfClass(Text.class);
+ String su = tu==null?null:tu.getText(t.ue);
+ String sl = tl==null?null:tl.getText(t.le);
+
+ return su==null?sl:su;
+ }
+
+ @Override
+ public void setText(IElement e, String text) {
+ }
+
+ @Override
+ public Color getFillColor(IElement e) {
+ Transition t = getTransition(e);
+ Color uc = ElementUtils.getFillColor(t.ue);
+ Color lc = ElementUtils.getFillColor(t.le);
+ if (uc==null) return lc;
+ if (lc==null) return uc;
+ return GeometryUtils.interpolate(uc, lc, t.phase);
+ }
+ @Override
+ public void setFillColor(IElement e, Color c) {
+ }
+ @Override
+ public Color getBorderColor(IElement e) {
+ Transition t = getTransition(e);
+ Color uc = ElementUtils.getBorderColor(t.ue);
+ Color lc = ElementUtils.getBorderColor(t.le);
+ if (uc==null) return lc;
+ if (lc==null) return uc;
+ return GeometryUtils.interpolate(uc, lc, t.phase);
+ }
+
+ @Override
+ public void setBorderColor(IElement e, Color c) {
+ }
+
+ @Override
+ public Color getAdditionalColor(IElement e) {
+ Transition t = getTransition(e);
+ Color uc = ElementUtils.getAdditionalColor(t.ue);
+ Color lc = ElementUtils.getAdditionalColor(t.le);
+ if (uc==null) return lc;
+ if (lc==null) return uc;
+ return GeometryUtils.interpolate(uc, lc, t.phase);
+ }
+
+ @Override
+ public void setAdditionalColor(IElement e, Color c) {
+ }
+
+ @Override
+ public Color getTextColor(IElement e) {
+ Transition t = getTransition(e);
+ Color uc = ElementUtils.getTextColor(t.ue);
+ Color lc = ElementUtils.getTextColor(t.le);
+ if (uc==null) return lc;
+ if (lc==null) return uc;
+ return GeometryUtils.interpolate(uc, lc, t.phase);
+ }
+
+ @Override
+ public void setTextColor(IElement e, Color c) {
+ }
+
+ @Override
+ public AngleType getAngleType(IElement e) {
+ Transition t = getTransition(e);
+ BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ if (ueb!=null) return ueb.getAngleType(t.ue);
+ if (leb!=null) return leb.getAngleType(t.le);
+ return null;
+ }
+ @Override
+ public void setAngleType(IElement e, AngleType angleType) {
+ }
+ @Override
+ public Bend addBend(IElement e, int index, Point2D pos) {
+ return null;
+ }
+ @Override
+ public void getBendPosition(IElement e, Bend b, Point2D pos) {
+ // TODO make better later
+ Transition t = getTransition(e);
+ BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ if (ueb!=null) ueb.getBendPosition(e, b, pos);
+ if (leb!=null) leb.getBendPosition(e, b, pos);
+ }
+ @Override
+ public void getBends(IElement e, List bends) {
+ // TODO make better later
+ Transition t = getTransition(e);
+ BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ if (ueb!=null) ueb.getBends(e, bends);
+ if (leb!=null) leb.getBends(e, bends);
+ }
+ @Override
+ public boolean removeBend(IElement e, Bend b) {
+ return false;
+ }
+
+ @Override
+ public Path2D getPath(IElement e) {
+ Transition t = getTransition(e);
+ BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ if (ueb==null && leb==null) return null;
+ if (ueb==null) return leb.getPath(t.le);
+ if (leb==null) return ueb.getPath(t.ue);
+ Path2D up = ueb.getPath(t.ue);
+ Path2D lp = leb.getPath(t.le);
+ // interpolate two paths
+ return PathUtils2.interpolatePaths(up, lp, t.phase);
+ }
+
+ @Override
+ public void setPath(IElement e, Path2D p) {
+ }
+
+ @Override
+ public int getBendsCount(IElement e) {
+ Transition t = getTransition(e);
+ BendsHandler ueb = t.ue.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ BendsHandler leb = t.le.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);
+ if (leb!=null) return leb.getBendsCount(t.le);
+ if (ueb!=null) return ueb.getBendsCount(t.ue);
+ return 0;
+ }
+
+ @Override
+ public void moveBend(IElement e, Bend b, Point2D pos) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void cleanup(IElement e) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void init(IElement e, G2DParentNode parent) {
+ Transition t = getTransition(e);
+ List empty = Collections.EMPTY_LIST;
+ List ups = t.ue==null?empty:t.ue.getElementClass().getItemsByClass(SceneGraph.class);
+ List lps = t.le==null?empty:t.le.getElementClass().getItemsByClass(SceneGraph.class);
+
+ if (ObjectUtils.equals(ups, lps))
+ {
+ for (SceneGraph lp : lps)
+ lp.init(e, parent);
+ return;
+ }
+
+ if (!lps.isEmpty()) {
+ for (SceneGraph lp : lps)
+ {
+ lp.init(t.le, parent);
+ }
+ }
+
+ if (!ups.isEmpty()) {
+ for (SceneGraph up : ups)
+ {
+ up.init(t.ue, parent);
+ }
+ }
+ }
+
+ }
+
+
+ private static WeakHashMap FADEIN_CLASSES =
+ new WeakHashMap();
+ private static WeakHashMap FADEOUT_CLASSES =
+ new WeakHashMap();
+ public synchronized static ElementClass getFadeElementClass(ElementClass origClass, FadeDir dir)
+ {
+ if (dir==FadeDir.In)
+ {
+ ElementClass proxyClass = FADEIN_CLASSES.get(origClass);
+ if (proxyClass==null) {
+ proxyClass = createFadeElementClass(origClass, dir);
+ FADEIN_CLASSES.put(origClass, proxyClass);
+ }
+ return proxyClass;
+ } else {
+ ElementClass proxyClass = FADEOUT_CLASSES.get(origClass);
+ if (proxyClass==null) {
+ proxyClass = createFadeElementClass(origClass, dir);
+ FADEOUT_CLASSES.put(origClass, proxyClass);
+ }
+ return proxyClass;
+ }
+ }
+
+ private static final IProxyProvider PROXY_PROVIDER =
+ new IProxyProvider() {
+ @Override
+ public IElement provide(IElement src) {
+ return src.getHint(KEY_SOURCE_ELEMENT);
+ }
+ };
+
+ static ElementClass createFadeElementClass(ElementClass clazz, FadeDir dir)
+ {
+ List result = new ArrayList();
+ List lst = new ArrayList();
+ for (ElementHandler eh : clazz.getAll())
+ {
+ lst.clear();
+ ProxyHandler.addProxyElementHandlers(eh, PROXY_PROVIDER, lst);
+ for (ElementHandler eh2 : lst)
+ {
+ if (eh2 instanceof ProxyLifeCycle) continue;
+ if (eh2 instanceof TerminalTopology) continue;
+
+ if (eh2 instanceof SceneGraph) {
+ result.add( new ProxyFadePaint(dir, (SceneGraph)eh) );
+ } else {
+ result.add(eh2);
+ }
+ }
+ }
+ return ElementClass.compile(result);
+ }
+
+ static class ProxyFadePaint implements SceneGraph {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3559624682436513231L;
+ static enum FadeDir {In, Out};
+ FadeDir dir;
+ SceneGraph orig;
+ public ProxyFadePaint(FadeDir dir, SceneGraph orig) {
+ this.dir = dir;
+ this.orig = orig;
+ assert(orig!=null);
+ }
+ public static IElement getSource(IElement element)
+ {
+ return element.getHint(KEY_SOURCE_ELEMENT);
+ }
+ public double getPhase(IElement element)
+ {
+ Double phase = element.getDiagram().getHint(KEY_PHASE);
+ if (phase==null) phase = 0.0;
+ if (dir == FadeDir.Out) phase = 1-phase;
+ return phase;
+ }
+ @Override
+ public void cleanup(IElement e) {
+ IElement sourceElement = getSource(e);
+ orig.cleanup(sourceElement);
+ }
+ @Override
+ public void init(IElement e, G2DParentNode parent) {
+ IElement sourceElement = getSource(e);
+ orig.init(sourceElement, parent);
+ }
+ }
+
+ static class MorphTopologyImpl implements Topology {
+
+ @Override
+ public void connect(IElement edge, EdgeEnd end, IElement node, Terminal terminal) {
+ }
+
+ @Override
+ public void disconnect(IElement edge, EdgeEnd end, IElement node, Terminal terminal) {
+ }
+
+ @Override
+ public Connection getConnection(IElement edge, EdgeEnd end) {
+ return null;
+ }
+
+ @Override
+ public void getConnections(IElement node, Terminal terminal, Collection connections) {
+ }
+
+ }
+
+}