From 74776fa0c613daf38465901c248433bec99d2c72 Mon Sep 17 00:00:00 2001 From: Antti Villberg Date: Mon, 3 Apr 2017 10:21:16 +0300 Subject: [PATCH] Dynamic positioning of terminals in G2D refs #7119 Change-Id: Ib0585c71c94ddca77ce41311cdce4916d033afba --- .../adapter/DefinedElementFactory.java | 2 +- .../adapter/DefinedElementTerminals.java | 78 +++++++++++++++++++ .../g2d/element/handler/impl/Terminals.java | 9 ++- .../simantics/scenegraph/utils/NodeUtil.java | 43 ++++++++++ 4 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DefinedElementTerminals.java diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DefinedElementFactory.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DefinedElementFactory.java index 6d5b30237..e7bb472e4 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DefinedElementFactory.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DefinedElementFactory.java @@ -231,7 +231,7 @@ public class DefinedElementFactory extends ElementFactoryAdapter { StaticSymbolImageInitializer.INSTANCE, new StaticSymbolImpl(img), DefinedElementHandler.INSTANCE, - new Terminals(terminals), + new DefinedElementTerminals(terminals), SimpleElementLayers.INSTANCE, PlainElementPropertySetter.INSTANCE ).setId(id)); diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DefinedElementTerminals.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DefinedElementTerminals.java new file mode 100644 index 000000000..6f83954e0 --- /dev/null +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/DefinedElementTerminals.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2017 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: + * Semantum Oy - #7119 initial API and implementation + *******************************************************************************/ +package org.simantics.diagram.adapter; + +import java.awt.geom.AffineTransform; +import java.util.Collection; + +import org.simantics.diagram.content.ResourceTerminal; +import org.simantics.g2d.diagram.handler.Topology.Terminal; +import org.simantics.g2d.element.IElement; +import org.simantics.g2d.element.handler.TerminalLayout; +import org.simantics.g2d.element.handler.TerminalTopology; +import org.simantics.g2d.element.handler.impl.ObjectTerminal; +import org.simantics.g2d.element.handler.impl.Terminals; +import org.simantics.scenegraph.INode; +import org.simantics.scenegraph.g2d.IG2DNode; +import org.simantics.scenegraph.g2d.nodes.SingleElementNode; +import org.simantics.scenegraph.utils.NodeUtil; + +/** + * A {@link TerminalTopology} and more specifically a {@link TerminalLayout} + * implementation that relies primarily on the scene graph and only secondarily + * on its internal datastructures to resolve terminal locations. This implementation + * is used to support dynamic terminals. + * + * @author Antti Villberg + * @since 1.29.0 + */ +public class DefinedElementTerminals extends Terminals { + + private static final long serialVersionUID = -726490868093887444L; + + public DefinedElementTerminals(Collection ts) { + super(ts); + } + + private IG2DNode findResourceTerminalNode(IG2DNode node, ResourceTerminal rt) { + return (IG2DNode) NodeUtil.forChildrenDeep(node, SingleElementNode.class, n -> { + Object key = n.getKey(); + if (rt.getResource().equals(key)) { + IG2DNode[] children = n.getSortedNodes(); + if (children.length > 0) + return children[0]; + return n; + } + return null; + }); + } + + @Override + public AffineTransform getTerminalPosition(IElement e, Terminal t) { + if (t instanceof ResourceTerminal) { + ResourceTerminal rt = (ResourceTerminal) t; + IG2DNode node = e.getHint(DefinedElementHandler.KEY_SG_NODE); + if (node != null) { + IG2DNode n = findResourceTerminalNode(node, rt); + if (n != null) { + return n.getTransform(); + } + } + } + + ObjectTerminal ti = terminalMap.get(t); + if (ti == null) + return null; + return new AffineTransform(ti.getTransform()); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/Terminals.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/Terminals.java index ca8518e6c..f38e0a6c5 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/Terminals.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/element/handler/impl/Terminals.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2017 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 @@ -8,6 +8,7 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - #7119 refactoring *******************************************************************************/ package org.simantics.g2d.element.handler.impl; @@ -30,10 +31,10 @@ import org.simantics.g2d.utils.geom.DirectionSet; */ public class Terminals implements TerminalLayout, TerminalTopology { - private static final long serialVersionUID = -6532093690907028016L; + private static final long serialVersionUID = -6532093690907028016L; - private final Map terminalMap = new THashMap(); - private final ArrayList terminals = new ArrayList(); + protected final Map terminalMap = new THashMap<>(); + protected final ArrayList terminals = new ArrayList<>(); public Terminals(Collection ts) { for (ObjectTerminal ti : ts) { diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/NodeUtil.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/NodeUtil.java index c3bb21441..615899a59 100644 --- a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/NodeUtil.java +++ b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/utils/NodeUtil.java @@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Function; import org.simantics.scenegraph.IDynamicSelectionPainterNode; import org.simantics.scenegraph.ILookupService; @@ -276,6 +277,7 @@ public final class NodeUtil { printSceneGraph(System.out, 0, node); } + @FunctionalInterface public static interface NodeProcedure { T execute(INode node, String id); } @@ -324,6 +326,47 @@ public final class NodeUtil { return result; } + /** + * Recursively iterates through all child nodes of the specified node and + * for those nodes that are of class ofClass, invokes + * consumer. + * + * @param node + * @param ofClass + * @param consumer + */ + @SuppressWarnings("unchecked") + public static INode forChildrenDeep(INode node, Class ofClass, Function func) { + return forChildrenDeep(node, n -> ofClass.isInstance(n) ? func.apply((T) n) : null); + } + + public static INode forChildrenDeep(INode node, Function func) { + INode ret = func.apply(node); + if (ret != null) + return ret; + + if (node instanceof ParentNode) { + if (node instanceof G2DParentNode) { + G2DParentNode g2dpn = (G2DParentNode) node; + for (IG2DNode n : g2dpn.getSortedNodes()) { + INode r = forChildrenDeep(n, func); + if (r != null) { + return r; + } + } + } else { + for (INode n : ((ParentNode) node).getNodes()) { + INode r = forChildrenDeep(n, func); + if (r != null) { + return r; + } + } + } + } + + return null; + } + public static final int countTreeNodes(INode node) { int result = 1; if (node instanceof ParentNode) { -- 2.43.2