]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - 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
diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/ShowRelatedElements.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/profile/ShowRelatedElements.java
new file mode 100644 (file)
index 0000000..a4e003c
--- /dev/null
@@ -0,0 +1,286 @@
+/*******************************************************************************\r
+ * Copyright (c) 2011 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.diagram.profile;\r
+\r
+import java.awt.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.Stroke;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Line2D;\r
+import java.awt.geom.Point2D;\r
+import java.awt.geom.Rectangle2D;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Statement;\r
+import org.simantics.db.common.utils.OrderedSetUtils;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.diagram.content.ConnectionUtil;\r
+import org.simantics.diagram.flag.FlagUtil;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
+import org.simantics.g2d.connection.handler.ConnectionHandler;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.handler.DataElementMap;\r
+import org.simantics.g2d.diagram.handler.PickRequest.PickFilter;\r
+import org.simantics.g2d.diagram.handler.Relationship;\r
+import org.simantics.g2d.diagram.handler.Topology.Connection;\r
+import org.simantics.g2d.element.ElementUtils;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.g2d.element.handler.BendsHandler;\r
+import org.simantics.g2d.element.handler.EdgeVisuals.EdgeEnd;\r
+import org.simantics.g2d.utils.GeometryUtils;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.scenegraph.INode;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+import org.simantics.scenegraph.g2d.nodes.RelationshipNode2;\r
+import org.simantics.scenegraph.profile.DataNodeMap;\r
+import org.simantics.scenegraph.profile.EvaluationContext;\r
+import org.simantics.scenegraph.profile.common.ProfileVariables;\r
+import org.simantics.utils.datastructures.Pair;\r
+import org.simantics.utils.datastructures.map.Tuple;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class ShowRelatedElements extends StyleBase<Object> {\r
+\r
+    protected Collection<Connection> terminalConnections = new ArrayList<Connection>(4);\r
+\r
+    protected final BasicStroke highlightStroke = new BasicStroke(1.0f,\r
+            BasicStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE, 10.0f,\r
+            new float[] { 4.0f, 6.0f }, 0);\r
+\r
+    protected Line2D line = new Line2D.Double();\r
+\r
+    /**\r
+     * One possible result of\r
+     * {@link ShowRelatedElements#calculateStyle(ReadGraph, Resource, Resource, Variable)}\r
+     */\r
+    public static class Relation extends Tuple {\r
+        public Relation(String relation,\r
+                Resource element, AffineTransform elementTransform,\r
+                Resource otherElement, AffineTransform otherElementTransform)\r
+        {\r
+            super(relation, element, elementTransform, otherElement, otherElementTransform);\r
+        }\r
+        public String getRelation() {\r
+            return (String) getField(0);\r
+        }\r
+        public Resource getElement() {\r
+            return (Resource) getField(1);\r
+        }\r
+        public AffineTransform getTransform() {\r
+            return (AffineTransform) getField(2);\r
+        }\r
+        public Resource getOtherElement() {\r
+            return (Resource) getField(3);\r
+        }\r
+        public AffineTransform getOtherTransform() {\r
+            return (AffineTransform) getField(4);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Calculates a result that is contains the styled element, its parent and\r
+     * transforms of both. This takes care of the style updating the visuals\r
+     * properly every time the related components move.\r
+     */\r
+    @Override\r
+    public Object calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration)\r
+    throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+\r
+        if (graph.isInstanceOf(element, DIA.Monitor)) {\r
+            return calculateFromComponent(graph, runtimeDiagram, element, DIA.HasMonitorComponent);\r
+        }\r
+        if (graph.isInstanceOf(element, DIA.Flag)) {\r
+            return calculateFromFlag(graph, element);\r
+        }\r
+\r
+        // Just return anything, no relationship to visualize.\r
+        return Boolean.TRUE;\r
+    }\r
+\r
+    protected Object calculateFromFlag(ReadGraph graph, Resource flag) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+\r
+        Resource relatedFlag = FlagUtil.getPossibleCounterpart(graph, flag);\r
+        if (relatedFlag != null) {\r
+            Collection<Resource> flagDiagrams = OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram);\r
+            Collection<Resource> relatedDiagrams = OrderedSetUtils.getOwnerLists(graph, relatedFlag, DIA.Diagram);\r
+            if (!Collections.disjoint(flagDiagrams, relatedDiagrams)) {\r
+                AffineTransform flagAt = DiagramGraphUtil.getTransform(graph, flag);\r
+                AffineTransform relatedFlagAt = DiagramGraphUtil.getTransform(graph, relatedFlag);\r
+                return new Relation(Relationship.RELATED_TO.toString(), flag, flagAt, relatedFlag, relatedFlagAt);\r
+            }\r
+        }\r
+\r
+        return Boolean.TRUE;\r
+    }\r
+\r
+    protected Object calculateFromComponent(ReadGraph graph, Resource runtime, Resource element, Resource elementToComponentRelation) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+        ModelingResources MOD = ModelingResources.getInstance(graph);\r
+\r
+        Resource parentComponent = graph.getPossibleObject(element, elementToComponentRelation);\r
+        if (parentComponent != null) {\r
+            Resource parentElement = graph.getPossibleObject(parentComponent, MOD.ComponentToElement);\r
+            if (parentElement != null) {\r
+                AffineTransform at = DiagramGraphUtil.getTransform(graph, element);\r
+                if (graph.isInstanceOf(parentElement, DIA.Connection))\r
+                    return new Relation(Relationship.CHILD_OF.toString(), element, at, parentElement,\r
+                            getConnectionOutputNodePosition(graph, runtime, parentElement));\r
+\r
+                AffineTransform parentAt = DiagramGraphUtil.getTransform(graph, parentElement);\r
+                return new Relation(Relationship.CHILD_OF.toString(), element, at, parentElement, parentAt);\r
+            }\r
+        }\r
+\r
+        return Boolean.TRUE;\r
+    }\r
+\r
+    protected AffineTransform getConnectionOutputNodePosition(ReadGraph graph, Resource runtime, Resource connection) throws DatabaseException {\r
+        Statement toTail = ConnectionUtil.getConnectionTailNodeStatement(graph, connection);\r
+        if (toTail == null)\r
+            return null;\r
+\r
+        AffineTransform at = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, toTail.getObject());\r
+\r
+        Resource connectionPoint = graph.getPossibleInverse(toTail.getPredicate());\r
+        if (connectionPoint == null)\r
+            return at;\r
+\r
+        DiagramResource DIA = DiagramResource.getInstance(graph);\r
+        for (Resource terminal : graph.getObjects(connectionPoint, DIA.HasConnectionPoint_Inverse)) {\r
+            AffineTransform terminalAt = DiagramGraphUtil.getDynamicAffineTransform(graph, runtime, terminal);\r
+            at.concatenate(terminalAt);\r
+        }\r
+\r
+        return at;\r
+    }\r
+\r
+    @Override\r
+    public void applyStyleForItem(EvaluationContext evaluationContext, DataNodeMap map, Object item, Object value) {\r
+        INode node = map.getNode(item);\r
+        if (node == null) {\r
+            evaluationContext.update();\r
+            return;\r
+        }\r
+\r
+        if (!(value instanceof Relation)) {\r
+            cleanupStyleForNode(node);\r
+            return;\r
+        }\r
+\r
+        IDiagram diagram = evaluationContext.getConstant(ProfileKeys.DIAGRAM);\r
+\r
+        Relation r = (Relation) value;\r
+\r
+        DataElementMap emap = diagram.getDiagramClass().getSingleItem(DataElementMap.class);\r
+        IElement element = emap.getElement(diagram, item);\r
+        IElement otherElement = emap.getElement(diagram, r.getOtherElement());\r
+        if (otherElement != null)\r
+            addCorrespondence(r, (G2DParentNode) node, r.getRelation(), element, otherElement, highlightStroke, Color.GRAY);\r
+    }\r
+\r
+    protected void addCorrespondence(Relation r, G2DParentNode p, String id, IElement from, IElement to, Stroke lineStroke, Color lineColor) {\r
+        Pair<Point2D, Rectangle2D> p1 = toPoint(r.getTransform(), from);\r
+        Pair<Point2D, Rectangle2D> p2 = toPoint(r.getOtherTransform(), to);\r
+        if (p1 != null && p2 != null)\r
+            addCorrespondence(p, id, p1, p2, lineStroke, lineColor);\r
+    }\r
+\r
+    /**\r
+     * @param parentTransform\r
+     * @param e \r
+     * @return origin and bounding box of the specified element in canvas\r
+     *         coordinate system\r
+     */\r
+    protected Pair<Point2D, Rectangle2D> toPoint(AffineTransform parentTransform, IElement e) {\r
+        if (PickFilter.FILTER_CONNECTIONS.accept(e)) {\r
+            // For connections select the first found output terminal position as\r
+            // the correspondence visualization point.\r
+\r
+            ConnectionHandler ch = e.getElementClass().getSingleItem(ConnectionHandler.class);\r
+            terminalConnections.clear();\r
+            ch.getTerminalConnections(e, terminalConnections);\r
+            for (Connection c : terminalConnections) {\r
+                if (c.end != EdgeEnd.Begin)\r
+                    continue;\r
+\r
+                BendsHandler bh = c.edge.getElementClass().getAtMostOneItemOfClass(BendsHandler.class);\r
+                if (bh != null) {\r
+                    List<Point2D> points = new ArrayList<Point2D>();\r
+                    GeometryUtils.getPoints(bh.getPath(c.edge), points);\r
+                    if (!points.isEmpty())\r
+                        return Pair.make(points.get(0), null);\r
+                } else {\r
+                    AffineTransform at = parentTransform;\r
+                    Point2D point = new Point2D.Double(at.getTranslateX(), at.getTranslateY());\r
+                    return Pair.make(point, null);\r
+                }\r
+            }\r
+\r
+            // Fall back to the default logic if connection output terminal\r
+            // search fails.\r
+        }\r
+\r
+        // Using element origin prevents the relationship rubber band target\r
+        // from changing every time the content of the node changes, e.g. the\r
+        // text of a monitor.\r
+        AffineTransform at = ElementUtils.getTransform(e);\r
+        Point2D p = new Point2D.Double(at.getTranslateX(), at.getTranslateY());\r
+        Rectangle2D r = ElementUtils.getElementBoundsOnDiagram(e).getBounds2D();\r
+        return Pair.make(p, r);\r
+    }\r
+\r
+    protected void addCorrespondence(G2DParentNode p, String id,\r
+            Pair<Point2D, Rectangle2D> p1,\r
+            Pair<Point2D, Rectangle2D> p2,\r
+            Stroke lineStroke, Color lineColor)\r
+    {\r
+        RelationshipNode2 node = p.getOrCreateNode(id, RelationshipNode2.class);\r
+        node.setZIndex(-10);\r
+\r
+        if (p1.second != null) {\r
+            line.setLine(p1.first, p2.first);\r
+            if (LineUtilities.clipLine(line, p1.second))\r
+                p1.first.setLocation(line.getX2(), line.getY2());\r
+        }\r
+        if (p2.second != null) {\r
+            line.setLine(p1.first, p2.first);\r
+            if (LineUtilities.clipLine(line, p2.second))\r
+                p2.first.setLocation(line.getX1(), line.getY1());\r
+        }\r
+\r
+        node.init(lineStroke, lineColor, p1.first, p2.first);\r
+    }\r
+\r
+    @Override\r
+    protected void cleanupStyleForNode(INode node) {\r
+        ProfileVariables.denyChild(node, "", Relationship.CHILD_OF.toString()); \r
+        //ProfileVariables.denyChild(node, "", Relationship.PARENT_OF.toString()); \r
+        ProfileVariables.denyChild(node, "", Relationship.RELATED_TO.toString()); \r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        return "show related elements";\r
+    }\r
+\r
+}\r