]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.diagram/src/org/simantics/diagram/profile/ShowRelatedElements.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / profile / ShowRelatedElements.java
1 /*******************************************************************************\r
2  * Copyright (c) 2011 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.diagram.profile;\r
13 \r
14 import java.awt.BasicStroke;\r
15 import java.awt.Color;\r
16 import java.awt.Stroke;\r
17 import java.awt.geom.AffineTransform;\r
18 import java.awt.geom.Line2D;\r
19 import java.awt.geom.Point2D;\r
20 import java.awt.geom.Rectangle2D;\r
21 import java.util.ArrayList;\r
22 import java.util.Collection;\r
23 import java.util.Collections;\r
24 import java.util.List;\r
25 \r
26 import org.simantics.db.ReadGraph;\r
27 import org.simantics.db.Resource;\r
28 import org.simantics.db.Statement;\r
29 import org.simantics.db.common.utils.OrderedSetUtils;\r
30 import org.simantics.db.exception.DatabaseException;\r
31 import org.simantics.db.layer0.variable.Variable;\r
32 import org.simantics.diagram.content.ConnectionUtil;\r
33 import org.simantics.diagram.flag.FlagUtil;\r
34 import org.simantics.diagram.stubs.DiagramResource;\r
35 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
36 import org.simantics.g2d.connection.handler.ConnectionHandler;\r
37 import org.simantics.g2d.diagram.IDiagram;\r
38 import org.simantics.g2d.diagram.handler.DataElementMap;\r
39 import org.simantics.g2d.diagram.handler.PickRequest.PickFilter;\r
40 import org.simantics.g2d.diagram.handler.Relationship;\r
41 import org.simantics.g2d.diagram.handler.Topology.Connection;\r
42 import org.simantics.g2d.element.ElementUtils;\r
43 import org.simantics.g2d.element.IElement;\r
44 import org.simantics.g2d.element.handler.BendsHandler;\r
45 import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;\r
46 import org.simantics.g2d.utils.GeometryUtils;\r
47 import org.simantics.modeling.ModelingResources;\r
48 import org.simantics.scenegraph.INode;\r
49 import org.simantics.scenegraph.g2d.G2DParentNode;\r
50 import org.simantics.scenegraph.g2d.nodes.RelationshipNode2;\r
51 import org.simantics.scenegraph.profile.DataNodeMap;\r
52 import org.simantics.scenegraph.profile.EvaluationContext;\r
53 import org.simantics.scenegraph.profile.common.ProfileVariables;\r
54 import org.simantics.utils.datastructures.Pair;\r
55 import org.simantics.utils.datastructures.map.Tuple;\r
56 \r
57 /**\r
58  * @author Tuukka Lehtonen\r
59  */\r
60 public class ShowRelatedElements extends StyleBase<Object> {\r
61 \r
62     protected Collection<Connection> terminalConnections = new ArrayList<Connection>(4);\r
63 \r
64     protected final BasicStroke highlightStroke = new BasicStroke(1.0f,\r
65             BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE, 10.0f,\r
66             new float[] { 4.0f, 6.0f }, 0);\r
67 \r
68     protected Line2D line = new Line2D.Double();\r
69 \r
70     /**\r
71      * One possible result of\r
72      * {@link ShowRelatedElements#calculateStyle(ReadGraph, Resource, Resource, Variable)}\r
73      */\r
74     public static class Relation extends Tuple {\r
75         public Relation(String relation,\r
76                 Resource element, AffineTransform elementTransform,\r
77                 Resource otherElement, AffineTransform otherElementTransform)\r
78         {\r
79             super(relation, element, elementTransform, otherElement, otherElementTransform);\r
80         }\r
81         public String getRelation() {\r
82             return (String) getField(0);\r
83         }\r
84         public Resource getElement() {\r
85             return (Resource) getField(1);\r
86         }\r
87         public AffineTransform getTransform() {\r
88             return (AffineTransform) getField(2);\r
89         }\r
90         public Resource getOtherElement() {\r
91             return (Resource) getField(3);\r
92         }\r
93         public AffineTransform getOtherTransform() {\r
94             return (AffineTransform) getField(4);\r
95         }\r
96     }\r
97 \r
98     /**\r
99      * Calculates a result that is contains the styled element, its parent and\r
100      * transforms of both. This takes care of the style updating the visuals\r
101      * properly every time the related components move.\r
102      */\r
103     @Override\r
104     public Object calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration)\r
105     throws DatabaseException {\r
106         DiagramResource DIA = DiagramResource.getInstance(graph);\r
107 \r
108         if (graph.isInstanceOf(element, DIA.Monitor)) {\r
109             return calculateFromComponent(graph, runtimeDiagram, element, DIA.HasMonitorComponent);\r
110         }\r
111         if (graph.isInstanceOf(element, DIA.Flag)) {\r
112             return calculateFromFlag(graph, element);\r
113         }\r
114 \r
115         // Just return anything, no relationship to visualize.\r
116         return Boolean.TRUE;\r
117     }\r
118 \r
119     protected Object calculateFromFlag(ReadGraph graph, Resource flag) throws DatabaseException {\r
120         DiagramResource DIA = DiagramResource.getInstance(graph);\r
121 \r
122         Resource relatedFlag = FlagUtil.getPossibleCounterpart(graph, flag);\r
123         if (relatedFlag != null) {\r
124             Collection<Resource> flagDiagrams = OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram);\r
125             Collection<Resource> relatedDiagrams = OrderedSetUtils.getOwnerLists(graph, relatedFlag, DIA.Diagram);\r
126             if (!Collections.disjoint(flagDiagrams, relatedDiagrams)) {\r
127                 AffineTransform flagAt = DiagramGraphUtil.getTransform(graph, flag);\r
128                 AffineTransform relatedFlagAt = DiagramGraphUtil.getTransform(graph, relatedFlag);\r
129                 return new Relation(Relationship.RELATED_TO.toString(), flag, flagAt, relatedFlag, relatedFlagAt);\r
130             }\r
131         }\r
132 \r
133         return Boolean.TRUE;\r
134     }\r
135 \r
136     protected Object calculateFromComponent(ReadGraph graph, Resource runtime, Resource element, Resource elementToComponentRelation) throws DatabaseException {\r
137         DiagramResource DIA = DiagramResource.getInstance(graph);\r
138         ModelingResources MOD = ModelingResources.getInstance(graph);\r
139 \r
140         Resource parentComponent = graph.getPossibleObject(element, elementToComponentRelation);\r
141         if (parentComponent != null) {\r
142             Resource parentElement = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);\r
143             if (parentElement != null) {\r
144                 AffineTransform at = DiagramGraphUtil.getTransform(graph, element);\r
145                 if (graph.isInstanceOf(parentElement, DIA.Connection))\r
146                     return new Relation(Relationship.CHILD_OF.toString(), element, at, parentElement,\r
147                             getConnectionOutputNodePosition(graph, runtime, parentElement));\r
148 \r
149                 AffineTransform parentAt = DiagramGraphUtil.getTransform(graph, parentElement);\r
150                 return new Relation(Relationship.CHILD_OF.toString(), element, at, parentElement, parentAt);\r
151             }\r
152         }\r
153 \r
154         return Boolean.TRUE;\r
155     }\r
156 \r
157     protected AffineTransform getConnectionOutputNodePosition(ReadGraph graph, Resource runtime, Resource connection) throws DatabaseException {\r
158         Statement toTail = ConnectionUtil.getConnectionTailNodeStatement(graph, connection);\r
159         if (toTail == null)\r
160             return null;\r
161 \r
162         AffineTransform at = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, toTail.getObject());\r
163 \r
164         Resource connectionPoint = graph.getPossibleInverse(toTail.getPredicate());\r
165         if (connectionPoint == null)\r
166             return at;\r
167 \r
168         DiagramResource DIA = DiagramResource.getInstance(graph);\r
169         for (Resource terminal : graph.getObjects(connectionPoint, DIA.HasConnectionPoint_Inverse)) {\r
170             AffineTransform terminalAt = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, terminal);\r
171             at.concatenate(terminalAt);\r
172         }\r
173 \r
174         return at;\r
175     }\r
176 \r
177     @Override\r
178     public void applyStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item, Object value) {\r
179         INode node = map.getNode(item);\r
180         if (node == null) {\r
181             evaluationContext.update();\r
182             return;\r
183         }\r
184 \r
185         if (!(value instanceof Relation)) {\r
186             cleanupStyleForNode(node);\r
187             return;\r
188         }\r
189 \r
190         IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);\r
191 \r
192         Relation r = (Relation) value;\r
193 \r
194         DataElementMap emap = diagram.getDiagramClass().getSingleItem(DataElementMap.class);\r
195         IElement element = emap.getElement(diagram, item);\r
196         IElement otherElement = emap.getElement(diagram, r.getOtherElement());\r
197         if (otherElement != null)\r
198             addCorrespondence(r, (G2DParentNode) node, r.getRelation(), element, otherElement, highlightStroke, Color.GRAY);\r
199     }\r
200 \r
201     protected void addCorrespondence(Relation r, G2DParentNode p, String id, IElement from, IElement to, Stroke lineStroke, Color lineColor) {\r
202         Pair<Point2D, Rectangle2D> p1 = toPoint(r.getTransform(), from);\r
203         Pair<Point2D, Rectangle2D> p2 = toPoint(r.getOtherTransform(), to);\r
204         if (p1 != null && p2 != null)\r
205             addCorrespondence(p, id, p1, p2, lineStroke, lineColor);\r
206     }\r
207 \r
208     /**\r
209      * @param parentTransform\r
210      * @param e \r
211      * @return origin and bounding box of the specified element in canvas\r
212      *         coordinate system\r
213      */\r
214     protected Pair<Point2D, Rectangle2D> toPoint(AffineTransform parentTransform, IElement e) {\r
215         if (PickFilter.FILTER_CONNECTIONS.accept(e)) {\r
216             // For connections select the first found output terminal position as\r
217             // the correspondence visualization point.\r
218 \r
219             ConnectionHandler ch = e.getElementClass().getSingleItem(ConnectionHandler.class);\r
220             terminalConnections.clear();\r
221             ch.getTerminalConnections(e, terminalConnections);\r
222             for (Connection c : terminalConnections) {\r
223                 if (c.end != EdgeEnd.Begin)\r
224                     continue;\r
225 \r
226                 BendsHandler bh = c.edge.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);\r
227                 if (bh != null) {\r
228                     List<Point2D> points = new ArrayList<Point2D>();\r
229                     GeometryUtils.getPoints(bh.getPath(c.edge), points);\r
230                     if (!points.isEmpty())\r
231                         return Pair.make(points.get(0), null);\r
232                 } else {\r
233                     AffineTransform at = parentTransform;\r
234                     Point2D point = new Point2D.Double(at.getTranslateX(), at.getTranslateY());\r
235                     return Pair.make(point, null);\r
236                 }\r
237             }\r
238 \r
239             // Fall back to the default logic if connection output terminal\r
240             // search fails.\r
241         }\r
242 \r
243         // Using element origin prevents the relationship rubber band target\r
244         // from changing every time the content of the node changes, e.g. the\r
245         // text of a monitor.\r
246         AffineTransform at = ElementUtils.getTransform(e);\r
247         Point2D p = new Point2D.Double(at.getTranslateX(), at.getTranslateY());\r
248         Rectangle2D r = ElementUtils.getElementBoundsOnDiagram(e).getBounds2D();\r
249         return Pair.make(p, r);\r
250     }\r
251 \r
252     protected void addCorrespondence(G2DParentNode p, String id,\r
253             Pair<Point2D, Rectangle2D> p1,\r
254             Pair<Point2D, Rectangle2D> p2,\r
255             Stroke lineStroke, Color lineColor)\r
256     {\r
257         RelationshipNode2 node = p.getOrCreateNode(id, RelationshipNode2.class);\r
258         node.setZIndex(-10);\r
259 \r
260         if (p1.second != null) {\r
261             line.setLine(p1.first, p2.first);\r
262             if (LineUtilities.clipLine(line, p1.second))\r
263                 p1.first.setLocation(line.getX2(), line.getY2());\r
264         }\r
265         if (p2.second != null) {\r
266             line.setLine(p1.first, p2.first);\r
267             if (LineUtilities.clipLine(line, p2.second))\r
268                 p2.first.setLocation(line.getX1(), line.getY1());\r
269         }\r
270 \r
271         node.init(lineStroke, lineColor, p1.first, p2.first);\r
272     }\r
273 \r
274     @Override\r
275     protected void cleanupStyleForNode(INode node) {\r
276         ProfileVariables.denyChild(node, "", Relationship.CHILD_OF.toString()); \r
277         //ProfileVariables.denyChild(node, "", Relationship.PARENT_OF.toString()); \r
278         ProfileVariables.denyChild(node, "", Relationship.RELATED_TO.toString()); \r
279     }\r
280 \r
281     @Override\r
282     public String toString() {\r
283         return "show related elements";\r
284     }\r
285 \r
286 }\r