]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/style/TypicalInheritanceStyle.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagram / style / TypicalInheritanceStyle.java
diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/style/TypicalInheritanceStyle.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/style/TypicalInheritanceStyle.java
new file mode 100644 (file)
index 0000000..c0de412
--- /dev/null
@@ -0,0 +1,250 @@
+package org.simantics.modeling.ui.diagram.style;\r
+\r
+import java.awt.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.Paint;\r
+import java.awt.Shape;\r
+import java.awt.Stroke;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Path2D;\r
+import java.awt.geom.Rectangle2D;\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.request.PossibleTypedParent;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.diagram.connection.RouteGraph;\r
+import org.simantics.diagram.connection.RouteGraphConnectionClass;\r
+import org.simantics.diagram.connection.RouteTerminal;\r
+import org.simantics.diagram.content.ConnectionUtil;\r
+import org.simantics.diagram.handler.Paster;\r
+import org.simantics.diagram.handler.Paster.RouteLine;\r
+import org.simantics.diagram.profile.ProfileKeys;\r
+import org.simantics.diagram.profile.StyleBase;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.diagram.handler.DataElementMap;\r
+import org.simantics.g2d.element.ElementUtils;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.g2d.element.handler.SelectionOutline;\r
+import org.simantics.g2d.element.handler.impl.ConnectionSelectionOutline;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.scenegraph.INode;\r
+import org.simantics.scenegraph.ParentNode;\r
+import org.simantics.scenegraph.g2d.IdentityAffineTransform;\r
+import org.simantics.scenegraph.g2d.nodes.ConnectionNode;\r
+import org.simantics.scenegraph.g2d.nodes.DecorationShapeNode;\r
+import org.simantics.scenegraph.g2d.nodes.ShapeNode;\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.scenegraph.utils.GeometryUtils;\r
+import org.simantics.scl.runtime.tuple.Tuple5;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+\r
+import gnu.trove.set.TLongSet;\r
+import gnu.trove.set.hash.TLongHashSet;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class TypicalInheritanceStyle extends StyleBase<TypicalInheritanceResult> {\r
+\r
+    private static final TypicalInheritanceResult NOT_INHERITED = new TypicalInheritanceResult(Boolean.FALSE, null, null, Boolean.FALSE, null);\r
+\r
+    private static final Paint PAINT = new Color(128, 128, 128, 64);\r
+    private static final Paint PAINT_WITHOUT_SOURCE = new Color(255, 128, 128, 64);\r
+    private static final Stroke STROKE = new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);\r
+\r
+    @Override\r
+    public TypicalInheritanceResult calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException {\r
+        DiagramResource DIA = DiagramResource.getInstance(graph); \r
+        ModelingResources MOD = ModelingResources.getInstance(graph);\r
+        StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+\r
+        boolean templatized = graph.hasStatement(element, MOD.IsTemplatized);\r
+        boolean hasElementSource = graph.hasStatement(element, MOD.HasElementSource);\r
+        if (templatized) {\r
+            if (graph.isInstanceOf(element, DIA.RouteGraphConnection)) {\r
+                Collection<Resource> connectors = graph.getObjects(element, DIA.HasConnector);\r
+                Collection<Resource> routeNodes = graph.getObjects(element, DIA.HasInteriorRouteNode);\r
+                TLongHashSet nonTemplatizedConnectors = null;\r
+\r
+                // This is needed to make this query result change every time the underlying element changes visually.\r
+                Set<Object> identifier = new HashSet<Object>(connectors.size() + routeNodes.size());\r
+\r
+                for (Resource connector : connectors) {\r
+                    for (Resource connectedTo : graph.getObjects(connector, STR.Connects)) {\r
+                        if (!connectedTo.equals(element)) {\r
+                            AffineTransform at = DiagramGraphUtil.getDynamicAffineTransform(graph, runtimeDiagram, connectedTo, DIA.HasDynamicTransform, false);\r
+                            identifier.add(at);\r
+\r
+                            boolean connectedToTemplatized = graph.hasStatement(connectedTo, MOD.IsTemplatized);\r
+                            if (!connectedToTemplatized) {\r
+                                if (nonTemplatizedConnectors == null)\r
+                                    nonTemplatizedConnectors = new TLongHashSet();\r
+                                nonTemplatizedConnectors.add(connector.getResourceId());\r
+                            }\r
+                            break;\r
+                        }\r
+                    }\r
+                }\r
+                if (!routeNodes.isEmpty()) {\r
+                    for (Resource routeLine : routeNodes) {\r
+                        RouteLine rl = Paster.readRouteLine(graph, routeLine);\r
+                        identifier.add(rl);\r
+                    }\r
+                }\r
+                return new TypicalInheritanceResult(templatized, nonTemplatizedConnectors, IdentityAffineTransform.INSTANCE, hasElementSource, identifier);\r
+            } else if (graph.isInstanceOf(element, DIA.Monitor)) {\r
+                AffineTransform worldTransform = DiagramGraphUtil.getWorldTransform(graph, element);\r
+                Resource monitoredComponent = graph.getPossibleObject(element, DIA.HasMonitorComponent);\r
+\r
+                if (monitoredComponent != null) {\r
+                    Resource monitoredElement = graph.getPossibleObject(monitoredComponent, MOD.ComponentToElement);\r
+                    if (graph.isInstanceOf(monitoredElement, DIA.Connection)) {\r
+                        Resource tailNode = ConnectionUtil.getConnectionTailNode(graph, monitoredElement);\r
+                        if (tailNode != null) {\r
+                            monitoredElement = tailNode;\r
+                        }\r
+                    }\r
+\r
+                    if (monitoredElement != null) {\r
+                        Resource diagram = graph.syncRequest(new PossibleTypedParent(element, DIA.Diagram));\r
+                        if (diagram != null) {\r
+                            Resource monitoredDiagram = graph.syncRequest(new PossibleTypedParent(monitoredElement, DIA.Diagram));\r
+                            if (diagram.equals(monitoredDiagram)) {\r
+                                AffineTransform monitoredElementWorldTransform = DiagramGraphUtil.getWorldTransform(graph, monitoredElement);\r
+                                worldTransform.preConcatenate(monitoredElementWorldTransform);\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+\r
+                return new TypicalInheritanceResult(templatized, null, worldTransform, hasElementSource, null);\r
+            }\r
+\r
+            AffineTransform worldTransform = DiagramGraphUtil.getWorldTransform(graph, element);\r
+            return new TypicalInheritanceResult(templatized, null, worldTransform, hasElementSource, null);\r
+        }\r
+\r
+        return NOT_INHERITED;\r
+    }\r
+\r
+    public void applyStyleForItem(EvaluationContext context, DataNodeMap map, Object item, TypicalInheritanceResult result) {\r
+        final INode _node = map.getNode(item);\r
+\r
+        if (result != null && Boolean.TRUE.equals(result.isTemplatized())) {\r
+            boolean fill = true;\r
+            Stroke stroke = null;\r
+            ShapeNode node = null;\r
+\r
+            if (_node instanceof ParentNode<?>) {\r
+                node = ProfileVariables.claimChild(_node, "", "typical", DecorationShapeNode.class, context);\r
+            } else {\r
+                // Ignore, cannot create decoration.\r
+                return;\r
+            }\r
+\r
+            if (_node instanceof ConnectionNode) {\r
+                fill = false;\r
+                stroke = STROKE;\r
+            }\r
+\r
+            Shape shape = null;\r
+            IDiagram diagram = context.getConstant(ProfileKeys.DIAGRAM);\r
+            if (diagram != null) {\r
+                DataElementMap dem = diagram.getDiagramClass().getAtMostOneItemOfClass(DataElementMap.class);\r
+                if (dem != null) {\r
+                    IElement element = dem.getElement(diagram, item);\r
+                    if (element != null) {\r
+                        SelectionOutline so = element.getElementClass().getAtMostOneItemOfClass(SelectionOutline.class);\r
+                        if (so != null) {\r
+                            RouteGraph rg = element.getHint(RouteGraphConnectionClass.KEY_ROUTEGRAPH);\r
+                            if (rg != null) {\r
+                                RouteGraph rgc = rg;\r
+                                TLongSet nonTemplatizedConnectors = result.getNonTemplatizedConnectors();\r
+                                if (nonTemplatizedConnectors != null) {\r
+                                    rgc = rg.copy();\r
+                                    // Must copy the RouteTerminal to an array before\r
+                                    // invoking rgc.remove(RouteTerminal), otherwise\r
+                                    // ConcurrentModificationExceptions will arise.\r
+                                    Collection<RouteTerminal> rtc = rgc.getTerminals();\r
+                                    if (nonTemplatizedConnectors.size() > (rtc.size() - 2)) {\r
+                                        // Cannot make a RouteGraph any simpler\r
+                                        // than a simple connection between two\r
+                                        // terminals.\r
+                                        // Fall back to highlighting the whole\r
+                                        // connection.\r
+                                    } else {\r
+                                        RouteTerminal[] rts = rtc.toArray(new RouteTerminal[rtc.size()]);\r
+                                        for (RouteTerminal rt : rts) {\r
+                                            Object data = rt.getData();\r
+                                            if (data instanceof Long) {\r
+                                                if (nonTemplatizedConnectors.contains(((Long) data).longValue()))\r
+                                                    rgc.remove(rt);\r
+                                            }\r
+                                        }\r
+                                    }\r
+                                }\r
+\r
+                                Path2D path = rgc.getPath2D();\r
+                                Stroke connectionStroke = ConnectionSelectionOutline.INSTANCE.resolveStroke(element, ConnectionSelectionOutline.defaultStroke);\r
+                                shape = connectionStroke.createStrokedShape(path);\r
+                            } else {\r
+                                shape = so.getSelectionShape(element);\r
+                            }\r
+                        } else {\r
+                            Rectangle2D rect = ElementUtils.getElementBounds(element);\r
+                            shape = GeometryUtils.expandRectangle( rect, 0.5 );\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+\r
+            AffineTransform at = result.getWorldTransform();\r
+            if (at != null)\r
+                node.setTransform(at);\r
+\r
+            node.setZIndex(-1000);\r
+            node.setColor(result.hasElementSource() ? PAINT : PAINT_WITHOUT_SOURCE);\r
+            node.setFill(fill);\r
+            node.setScaleStroke(false);\r
+            node.setScaleShape(false);\r
+            node.setStroke(stroke);\r
+            node.setShape(shape);\r
+        } else {\r
+            cleanupStyleForNode(context, _node);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    protected void cleanupStyleForNode(EvaluationContext context, INode node) {\r
+        ProfileVariables.denyChild(node, "*", "typical");\r
+        ProfileVariables.denyChild(node, "", "typical");\r
+    }\r
+\r
+}\r
+\r
+class TypicalInheritanceResult extends Tuple5 {\r
+    public TypicalInheritanceResult(Boolean templatized, TLongSet nonTemplatizedConnectors, AffineTransform worldTransform, Boolean hasElementSource, Set<Object> queryIdentifier) {\r
+        super(templatized, nonTemplatizedConnectors, worldTransform, hasElementSource, queryIdentifier);\r
+    }\r
+    public boolean isTemplatized() {\r
+        return (Boolean) get(0);\r
+    }\r
+    public TLongSet getNonTemplatizedConnectors() {\r
+        return (TLongSet) get(1);\r
+    }\r
+    public AffineTransform getWorldTransform() {\r
+       return (AffineTransform) get(2);\r
+    }\r
+    public boolean hasElementSource() {\r
+        return (Boolean) get(3);\r
+    }\r
+}\r