]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.diagram/src/org/simantics/diagram/participant/DiagramModelActivityTracker.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.diagram / src / org / simantics / diagram / participant / DiagramModelActivityTracker.java
diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/DiagramModelActivityTracker.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/participant/DiagramModelActivityTracker.java
new file mode 100644 (file)
index 0000000..a12043f
--- /dev/null
@@ -0,0 +1,245 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in 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.participant;\r
+\r
+import java.awt.Color;\r
+import java.awt.Font;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Rectangle2D;\r
+\r
+import org.simantics.Simantics;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.common.request.PossibleIndexRoot;\r
+import org.simantics.db.common.request.UnaryRead;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.adapter.Instances;\r
+import org.simantics.db.layer0.request.IsActive;\r
+import org.simantics.db.layer0.util.Layer0Utils;\r
+import org.simantics.db.procedure.Listener;\r
+import org.simantics.diagram.elements.TextNode;\r
+import org.simantics.diagram.stubs.DiagramResource;\r
+import org.simantics.g2d.canvas.Hints;\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.canvas.SGDesignation;\r
+import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant;\r
+import org.simantics.g2d.canvas.impl.HintReflection.HintListener;\r
+import org.simantics.g2d.canvas.impl.SGNodeReflection.SGCleanup;\r
+import org.simantics.g2d.canvas.impl.SGNodeReflection.SGInit;\r
+import org.simantics.g2d.utils.Alignment;\r
+import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
+import org.simantics.scenegraph.g2d.G2DParentNode;\r
+import org.simantics.structural.stubs.StructuralResource2;\r
+import org.simantics.utils.datastructures.hints.IHintContext;\r
+import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
+import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
+import org.simantics.utils.datastructures.hints.IHintObservable;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+\r
+/**\r
+ * DiagramModelActivityTracker tracks whether or not the specified input\r
+ * resource is part of the diagram model or not and modifies the canvas\r
+ * background color accordingly. If the diagram is not in an active model, an\r
+ * <b>INACTIVE MODEL</b> banner is also shown in the background using\r
+ * {@link TextNode}.\r
+ * \r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class DiagramModelActivityTracker extends AbstractCanvasParticipant {\r
+\r
+    public static final Key    KEY_IN_ACTIVE_MODEL         = new KeyOf(String.class, "IN_ACTIVE_MODEL");\r
+    public static final Key    KEY_ACTIVE_BACKGROUND       = new KeyOf(Color.class, "ACTIVE_BACKGROUND");\r
+    public static final Key    KEY_INACTIVE_BACKGROUND     = new KeyOf(Color.class, "INACTIVE_BACKGROUND");\r
+\r
+    private static final Color DEFAULT_ACTIVE_BACKGROUND   = Color.WHITE;\r
+    private static final Color DEFAULT_INACTIVE_BACKGROUND = new Color(242, 242, 242);\r
+\r
+    Resource                   input;\r
+    IsInActiveModelListener    listener;\r
+    TextNode                   bannerNode;\r
+\r
+    public DiagramModelActivityTracker(Resource input) {\r
+        if (input == null)\r
+            throw new NullPointerException("null input");\r
+        this.input = input;\r
+    }\r
+\r
+    @HintListener(Class=Hints.class, Field="KEY_CONTROL_BOUNDS")\r
+    public void controlBoundsChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
+        if (bannerNode == null)\r
+            return;\r
+        if (newValue != null) {\r
+            Rectangle2D bounds = (Rectangle2D) newValue;\r
+            AffineTransform at = new AffineTransform();\r
+            at.translate(5,5);\r
+//            at.translate(bounds.getWidth() / 2, bounds.getHeight() / 2);\r
+//            at.scale(2, 2);\r
+//            at.rotate(-Math.PI/6);\r
+//            at.translate(bounds.getWidth() - 150, bounds.getHeight() - 30);\r
+//            at.scale(1, 1);\r
+            bannerNode.setTransform(at);\r
+        } else {\r
+            // Disable rendering\r
+            bannerNode.setColor(null);\r
+        }\r
+    }\r
+\r
+    @HintListener(Class=DiagramModelActivityTracker.class, Field="KEY_IN_ACTIVE_MODEL")\r
+    public void containingModelActivityChanged(IHintObservable sender, Key key, Object oldValue, Object _newValue) {\r
+       String newValue = (String)_newValue;\r
+        if (bannerNode == null)\r
+            return;\r
+        if (newValue == null) {\r
+               bannerNode.setText("");\r
+        } else {\r
+               bannerNode.setText(newValue);\r
+            //bannerNode.setColor(new Color(192, 32, 32, 128));\r
+            //bannerNode.setColor(new Color(192, 32, 32, 32));\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void addedToContext(ICanvasContext ctx) {\r
+        super.addedToContext(ctx);\r
+\r
+        listener = new IsInActiveModelListener(ctx);\r
+        Simantics.getSession().async(new IsActiveDiagram(input), listener);\r
+\r
+        if (!ctx.getHintStack().containsHint(KEY_ACTIVE_BACKGROUND))\r
+            ctx.getDefaultHintContext().setHint(KEY_ACTIVE_BACKGROUND, DEFAULT_ACTIVE_BACKGROUND);\r
+        if (!ctx.getHintStack().containsHint(KEY_INACTIVE_BACKGROUND))\r
+            ctx.getDefaultHintContext().setHint(KEY_INACTIVE_BACKGROUND, DEFAULT_INACTIVE_BACKGROUND);\r
+    }\r
+\r
+    @Override\r
+    public void removedFromContext(ICanvasContext ctx) {\r
+        if (listener != null) {\r
+            listener.dispose();\r
+            listener = null;\r
+        }\r
+        super.removedFromContext(ctx);\r
+    }\r
+\r
+    @SGInit(designation = SGDesignation.CONTROL)\r
+    public void initSG(G2DParentNode parent) {\r
+        bannerNode = parent.addNode("inactivity-banner", TextNode.class);\r
+        bannerNode.setZIndex(Integer.MIN_VALUE / 4);\r
+        //bannerNode.setZIndex(Integer.MAX_VALUE / 4);\r
+        bannerNode.setHorizontalAlignment((byte) Alignment.LEADING.ordinal());\r
+        bannerNode.setVerticalAlignment((byte) Alignment.LEADING.ordinal());\r
+        //bannerNode.setText("Model is not active.");\r
+        bannerNode.setText("");\r
+        bannerNode.setFont(Font.decode("Arial 16"));\r
+        //bannerNode.setBackgroundColor(new Color(192, 192, 192, 128));\r
+        bannerNode.setPadding(10, 10);\r
+        bannerNode.setBorderColor(Color.GRAY);\r
+        bannerNode.setBorderWidth(0);\r
+        bannerNode.setEditable(false);\r
+    }\r
+\r
+    @SGCleanup\r
+    public void cleanupSG() {\r
+        if (bannerNode != null) {\r
+            bannerNode.remove();\r
+            bannerNode = null;\r
+        }\r
+    }\r
+\r
+    static class IsActiveDiagram extends UnaryRead<Resource, String> {\r
+        public IsActiveDiagram(Resource parameter) {\r
+            super(parameter);\r
+        }\r
+        @Override\r
+        public String perform(ReadGraph graph) throws DatabaseException {\r
+               \r
+            Resource indexRoot = graph.syncRequest( new PossibleIndexRoot(parameter) );\r
+            if (indexRoot == null) {\r
+                return "This diagram is not part of any model or shared library";\r
+            }\r
+               Layer0 L0 = Layer0.getInstance(graph);\r
+               StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
+               ModelingResources MOD = ModelingResources.getInstance(graph);\r
+               Resource composite = graph.getPossibleObject(parameter, MOD.DiagramToComposite);\r
+               if(composite == null)\r
+                return "This diagram does not have a corresponding configuration";\r
+               \r
+               Resource componentType = graph.getPossibleObject(composite, STR.Defines);\r
+               if(componentType != null) {\r
+                       // This is a component type\r
+                       boolean published = Layer0Utils.isPublished(graph, componentType);\r
+                       if(published)\r
+                    return "This diagram defines a published (read-only) user component";\r
+               }\r
+               \r
+               if(graph.isInstanceOf(indexRoot, L0.SharedOntology)) {\r
+                       return "";\r
+               }\r
+               \r
+               boolean activeModel = graph.syncRequest( new IsActive(indexRoot) );\r
+               if(!activeModel)\r
+                return "The model of this diagram is not active";\r
+               \r
+               DiagramResource DIA = DiagramResource.getInstance(graph);\r
+               Instances query = graph.adapt(DIA.DiagramActivityCondition, Instances.class);\r
+\r
+               for(Resource condition : query.find(graph, indexRoot)) {\r
+                String value = Simantics.tryInvokeSCL(graph, condition, DIA.DiagramActivityCondition_test, parameter);\r
+                if(value != null && !value.isEmpty()) return value;\r
+               }\r
+               \r
+            return "";\r
+            \r
+        }\r
+    }\r
+\r
+    static class IsInActiveModelListener implements Listener<String> {\r
+        ICanvasContext context;\r
+        public IsInActiveModelListener(ICanvasContext context) {\r
+            this.context = context;\r
+        }\r
+        @Override\r
+        public void execute(final String result) {\r
+            final Color color = (result.isEmpty())\r
+                    ? context.getHintStack().<Color>getHint(KEY_ACTIVE_BACKGROUND)\r
+                    : context.getHintStack().<Color>getHint(KEY_INACTIVE_BACKGROUND);\r
+\r
+            context.getThreadAccess().asyncExec(new Runnable() {\r
+                @Override\r
+                public void run() {\r
+                    ICanvasContext ctx = context;\r
+                    if (ctx == null)\r
+                        return;\r
+                    if (ctx.isDisposed())\r
+                        return;\r
+                    IHintContext hints = ctx.getDefaultHintContext();\r
+                    if (color != null)\r
+                        hints.setHint(Hints.KEY_BACKGROUND_COLOR, color);\r
+                    hints.setHint(KEY_IN_ACTIVE_MODEL, result);\r
+                }\r
+            });\r
+        }\r
+        public void dispose() {\r
+            context = null;\r
+        }\r
+        @Override\r
+        public boolean isDisposed() {\r
+            ICanvasContext context = this.context;\r
+            return context == null || context.isDisposed();\r
+        }\r
+        @Override\r
+        public void exception(Throwable t) {\r
+            ErrorLogger.defaultLogError(t);\r
+        }\r
+    }\r
+\r
+}\r