+/*******************************************************************************
+ * 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<ObjectTerminal> 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