X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Fmultileveldiagram%2FTransitionDiagram.java;h=90186e8003efbe97ece066dc4cb38a7156924e7b;hb=refs%2Fchanges%2F38%2F238%2F2;hp=517aadbe22033e1008e25499d44ae830fcf5cb45;hpb=24e2b34260f219f0d1644ca7a138894980e25b14;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) { + } + + } + +}