]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/monitor/MonitorListener.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagram / monitor / MonitorListener.java
diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/monitor/MonitorListener.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/monitor/MonitorListener.java
new file mode 100644 (file)
index 0000000..fe5e5c2
--- /dev/null
@@ -0,0 +1,173 @@
+/*******************************************************************************\r
+ * Copyright (c) 2012 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.modeling.ui.diagram.monitor;\r
+\r
+import java.util.Map;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
+import java.util.concurrent.atomic.AtomicReference;\r
+\r
+import org.simantics.db.Disposable;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.procedure.Listener;\r
+import org.simantics.diagram.elements.MonitorClass;\r
+import org.simantics.g2d.canvas.Hints;\r
+import org.simantics.g2d.canvas.ICanvasContext;\r
+import org.simantics.g2d.diagram.IDiagram;\r
+import org.simantics.g2d.element.ElementUtils;\r
+import org.simantics.g2d.element.IElement;\r
+import org.simantics.utils.threads.ThreadUtils;\r
+import org.simantics.utils.ui.ErrorLogger;\r
+\r
+/**\r
+ * @author Tuukka Lehtonen\r
+ */\r
+public class MonitorListener implements Listener<MonitorVariableValue>, Runnable, Disposable {\r
+\r
+    private final Resource                                  element;\r
+    private ICanvasContext                                  canvas;\r
+    private IDiagram                                        diagram;\r
+    private final Map<String, String>                       substitutions;\r
+\r
+    private transient AtomicReference<MonitorVariableValue> lastScheduledUpdate   = null;\r
+    private transient AtomicBoolean                         inUpdate = null;\r
+\r
+    public MonitorListener(Resource element, ICanvasContext canvas, IDiagram diagram, Map<String, String> substitutions) {\r
+        if (element == null)\r
+            throw new NullPointerException("null element");\r
+        if (canvas == null)\r
+            throw new NullPointerException("null canvas");\r
+        if (diagram == null)\r
+            throw new NullPointerException("null diagram");\r
+        if (substitutions == null)\r
+            throw new NullPointerException("null substitutions");\r
+        this.element = element;\r
+        this.canvas = canvas;\r
+        this.diagram = diagram;\r
+        this.substitutions = substitutions;\r
+    }\r
+\r
+    @Override\r
+    public void dispose() {\r
+        canvas = null;\r
+        diagram = null;\r
+    }\r
+\r
+    @Override\r
+    public void execute(MonitorVariableValue result) {\r
+        // Implement some kind of throttling for AWT thread element\r
+        // update scheduling to keep the amount of AWT scheduling\r
+        // down to a minimum.\r
+        if (inUpdate == null)\r
+            inUpdate = new AtomicBoolean(false);\r
+        if (lastScheduledUpdate == null)\r
+            lastScheduledUpdate = new AtomicReference<MonitorVariableValue>();\r
+\r
+        lastScheduledUpdate.set(result);\r
+\r
+        // Don't schedule update if there was already one in the pipe.\r
+        synchronized (inUpdate) {\r
+            if (!inUpdate.compareAndSet(false, true))\r
+                return;\r
+        }\r
+\r
+        //System.out.println(this + ".execute(" + result + "+")");\r
+        scheduleUpdate();\r
+    }\r
+\r
+    @Override\r
+    public void run() {\r
+        if (isDisposed())\r
+            return;\r
+\r
+        IElement el = ElementUtils.getByData(diagram, element);\r
+        if (el == null)\r
+            return;\r
+\r
+        try {\r
+            performUpdate(el);\r
+        } finally {\r
+            // Mark null to allow new update scheduling to commence.\r
+            synchronized (inUpdate) {\r
+                if (lastScheduledUpdate.get() != null)\r
+                    scheduleUpdate();\r
+                else\r
+                    inUpdate.set(false);\r
+            }\r
+        }\r
+    }\r
+\r
+    private void scheduleUpdate() {\r
+        ICanvasContext canvas = this.canvas;\r
+        if (!isDisposed())\r
+            ThreadUtils.asyncExec(canvas.getThreadAccess(), this);\r
+    }\r
+\r
+    private void performUpdate(IElement el) {\r
+        // Get the last updated monitor value but don't yet\r
+        // mark the container null to keep the outer code\r
+        // from scheduling new updates until this one is\r
+        // finished.\r
+        MonitorVariableValue result = lastScheduledUpdate.getAndSet(null);\r
+\r
+        String value = "<no variable>";\r
+        if (result != null) {\r
+            if (result.getValue() != null) {\r
+                value = result.getValue();//ValueFormatUtil.valueStr(result.getValue(), format);\r
+            } else {\r
+                value = "<no value>";\r
+            }\r
+            el.setHint(MonitorClass.KEY_MONITOR_COMPONENT, result.getMonitorVariable().getMonitorComponent());\r
+            ElementUtils.setOrRemoveHint(el, MonitorClass.KEY_MONITOR_IS_EXTERNAL, result.getMonitorVariable().isExternal());\r
+        } else {\r
+            el.removeHint(MonitorClass.KEY_MONITOR_COMPONENT);\r
+            el.removeHint(MonitorClass.KEY_MONITOR_IS_EXTERNAL);\r
+        }\r
+\r
+        substitutions.put("#v1", value);\r
+\r
+        final Map<String, String> subs = el.getHint(MonitorClass.KEY_MONITOR_SUBSTITUTIONS);\r
+        if (substitutions != subs)\r
+            el.setHint(MonitorClass.KEY_MONITOR_SUBSTITUTIONS, substitutions);\r
+\r
+        //System.out.println("REPLACING #v1: " + substitutions.get("#v1"));\r
+\r
+        el.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DELAYED_UPDATE);\r
+    }\r
+\r
+    @Override\r
+    public void exception(Throwable t) {\r
+        ErrorLogger.defaultLogError(t);\r
+    }\r
+\r
+    @Override\r
+    public boolean isDisposed() {\r
+        return canvas == null || diagram == null || canvas.isDisposed();\r
+    }\r
+\r
+    @Override\r
+    public int hashCode() {\r
+        return element.hashCode();\r
+    }\r
+\r
+    @Override\r
+    public boolean equals(Object obj) {\r
+        if (this == obj)\r
+            return true;\r
+        if (obj == null)\r
+            return false;\r
+        if (getClass() != obj.getClass())\r
+            return false;\r
+        MonitorListener other = (MonitorListener) obj;\r
+        return element.equals(other.element);\r
+    }\r
+\r
+}
\ No newline at end of file