Dynamic terminals and connections
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / adapter / DefinedElementTerminals.java
1 /*******************************************************************************
2  * Copyright (c) 2017 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     Semantum Oy - #7119 initial API and implementation
11  *******************************************************************************/
12 package org.simantics.diagram.adapter;
13
14 import java.awt.Shape;
15 import java.awt.geom.AffineTransform;
16 import java.util.Collection;
17
18 import org.simantics.diagram.content.ResourceTerminal;
19 import org.simantics.g2d.diagram.handler.Topology.Terminal;
20 import org.simantics.g2d.element.IElement;
21 import org.simantics.g2d.element.handler.TerminalLayout;
22 import org.simantics.g2d.element.handler.TerminalTopology;
23 import org.simantics.g2d.element.handler.impl.ObjectTerminal;
24 import org.simantics.g2d.element.handler.impl.Terminals;
25 import org.simantics.scenegraph.g2d.IG2DNode;
26 import org.simantics.scenegraph.g2d.nodes.SingleElementNode;
27 import org.simantics.scenegraph.utils.NodeUtil;
28
29 /**
30  * A {@link TerminalTopology} and more specifically a {@link TerminalLayout}
31  * implementation that relies primarily on the scene graph and only secondarily
32  * on its internal datastructures to resolve terminal locations. This implementation
33  * is used to support dynamic terminals.
34  * 
35  * @author Antti Villberg
36  * @since 1.29.0
37  */
38 public class DefinedElementTerminals extends Terminals {
39
40     private static final long serialVersionUID = -726490868093887444L;
41
42     public DefinedElementTerminals(Collection<ObjectTerminal> ts) {
43         super(ts);
44     }
45
46     private IG2DNode findResourceTerminalNode(IG2DNode node, ResourceTerminal rt) {
47         return (IG2DNode) NodeUtil.forChildrenDeep(node, SingleElementNode.class, n -> {
48             Object key = n.getKey();
49             if (rt.getResource().equals(key)) {
50                 IG2DNode[] children = n.getSortedNodes();
51                 if (children.length > 0)
52                     return children[0];
53                 return n;
54             }
55             return null;
56         });
57     }
58
59     @Override
60     public AffineTransform getTerminalPosition(IElement e, Terminal t) {
61         if (t instanceof ResourceTerminal) {
62             ResourceTerminal rt = (ResourceTerminal) t;
63             IG2DNode node = e.getHint(DefinedElementHandler.KEY_SG_NODE);
64             if (node != null) {
65                 IG2DNode n = findResourceTerminalNode(node, rt);
66                 if (n != null) {
67                     return n.getTransform();
68                 }
69             }
70         }
71
72         ObjectTerminal ti = terminalMap.get(t);
73         if (ti == null)
74             return null;
75         return ti.getTransform();
76     }
77     
78     @Override
79     public Shape getTerminalShape(IElement e, Terminal t) {
80         if (t instanceof ResourceTerminal) {
81             ResourceTerminal rt = (ResourceTerminal) t;
82             IG2DNode node = e.getHint(DefinedElementHandler.KEY_SG_NODE);
83             if (node != null) {
84                 IG2DNode n = findResourceTerminalNode(node, rt);
85                 if (n != null) {
86                     return n.getBoundsInLocal();
87                 }
88             }
89         }
90         return super.getTerminalShape(e, t);
91     }
92
93 }