]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 /*******************************************************************************\r
2  * Copyright (c) 2012 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.modeling.ui.diagram.monitor;\r
13 \r
14 import java.util.Map;\r
15 import java.util.concurrent.atomic.AtomicBoolean;\r
16 import java.util.concurrent.atomic.AtomicReference;\r
17 \r
18 import org.simantics.db.Disposable;\r
19 import org.simantics.db.Resource;\r
20 import org.simantics.db.procedure.Listener;\r
21 import org.simantics.diagram.elements.MonitorClass;\r
22 import org.simantics.g2d.canvas.Hints;\r
23 import org.simantics.g2d.canvas.ICanvasContext;\r
24 import org.simantics.g2d.diagram.IDiagram;\r
25 import org.simantics.g2d.element.ElementUtils;\r
26 import org.simantics.g2d.element.IElement;\r
27 import org.simantics.utils.threads.ThreadUtils;\r
28 import org.simantics.utils.ui.ErrorLogger;\r
29 \r
30 /**\r
31  * @author Tuukka Lehtonen\r
32  */\r
33 public class MonitorListener implements Listener<MonitorVariableValue>, Runnable, Disposable {\r
34 \r
35     private final Resource                                  element;\r
36     private ICanvasContext                                  canvas;\r
37     private IDiagram                                        diagram;\r
38     private final Map<String, String>                       substitutions;\r
39 \r
40     private transient AtomicReference<MonitorVariableValue> lastScheduledUpdate   = null;\r
41     private transient AtomicBoolean                         inUpdate = null;\r
42 \r
43     public MonitorListener(Resource element, ICanvasContext canvas, IDiagram diagram, Map<String, String> substitutions) {\r
44         if (element == null)\r
45             throw new NullPointerException("null element");\r
46         if (canvas == null)\r
47             throw new NullPointerException("null canvas");\r
48         if (diagram == null)\r
49             throw new NullPointerException("null diagram");\r
50         if (substitutions == null)\r
51             throw new NullPointerException("null substitutions");\r
52         this.element = element;\r
53         this.canvas = canvas;\r
54         this.diagram = diagram;\r
55         this.substitutions = substitutions;\r
56     }\r
57 \r
58     @Override\r
59     public void dispose() {\r
60         canvas = null;\r
61         diagram = null;\r
62     }\r
63 \r
64     @Override\r
65     public void execute(MonitorVariableValue result) {\r
66         // Implement some kind of throttling for AWT thread element\r
67         // update scheduling to keep the amount of AWT scheduling\r
68         // down to a minimum.\r
69         if (inUpdate == null)\r
70             inUpdate = new AtomicBoolean(false);\r
71         if (lastScheduledUpdate == null)\r
72             lastScheduledUpdate = new AtomicReference<MonitorVariableValue>();\r
73 \r
74         lastScheduledUpdate.set(result);\r
75 \r
76         // Don't schedule update if there was already one in the pipe.\r
77         synchronized (inUpdate) {\r
78             if (!inUpdate.compareAndSet(false, true))\r
79                 return;\r
80         }\r
81 \r
82         //System.out.println(this + ".execute(" + result + "+")");\r
83         scheduleUpdate();\r
84     }\r
85 \r
86     @Override\r
87     public void run() {\r
88         if (isDisposed())\r
89             return;\r
90 \r
91         IElement el = ElementUtils.getByData(diagram, element);\r
92         if (el == null)\r
93             return;\r
94 \r
95         try {\r
96             performUpdate(el);\r
97         } finally {\r
98             // Mark null to allow new update scheduling to commence.\r
99             synchronized (inUpdate) {\r
100                 if (lastScheduledUpdate.get() != null)\r
101                     scheduleUpdate();\r
102                 else\r
103                     inUpdate.set(false);\r
104             }\r
105         }\r
106     }\r
107 \r
108     private void scheduleUpdate() {\r
109         ICanvasContext canvas = this.canvas;\r
110         if (!isDisposed())\r
111             ThreadUtils.asyncExec(canvas.getThreadAccess(), this);\r
112     }\r
113 \r
114     private void performUpdate(IElement el) {\r
115         // Get the last updated monitor value but don't yet\r
116         // mark the container null to keep the outer code\r
117         // from scheduling new updates until this one is\r
118         // finished.\r
119         MonitorVariableValue result = lastScheduledUpdate.getAndSet(null);\r
120 \r
121         String value = "<no variable>";\r
122         if (result != null) {\r
123             if (result.getValue() != null) {\r
124                 value = result.getValue();//ValueFormatUtil.valueStr(result.getValue(), format);\r
125             } else {\r
126                 value = "<no value>";\r
127             }\r
128             el.setHint(MonitorClass.KEY_MONITOR_COMPONENT, result.getMonitorVariable().getMonitorComponent());\r
129             ElementUtils.setOrRemoveHint(el, MonitorClass.KEY_MONITOR_IS_EXTERNAL, result.getMonitorVariable().isExternal());\r
130         } else {\r
131             el.removeHint(MonitorClass.KEY_MONITOR_COMPONENT);\r
132             el.removeHint(MonitorClass.KEY_MONITOR_IS_EXTERNAL);\r
133         }\r
134 \r
135         substitutions.put("#v1", value);\r
136 \r
137         final Map<String, String> subs = el.getHint(MonitorClass.KEY_MONITOR_SUBSTITUTIONS);\r
138         if (substitutions != subs)\r
139             el.setHint(MonitorClass.KEY_MONITOR_SUBSTITUTIONS, substitutions);\r
140 \r
141         //System.out.println("REPLACING #v1: " + substitutions.get("#v1"));\r
142 \r
143         el.setHint(Hints.KEY_DIRTY, Hints.VALUE_SG_DELAYED_UPDATE);\r
144     }\r
145 \r
146     @Override\r
147     public void exception(Throwable t) {\r
148         ErrorLogger.defaultLogError(t);\r
149     }\r
150 \r
151     @Override\r
152     public boolean isDisposed() {\r
153         return canvas == null || diagram == null || canvas.isDisposed();\r
154     }\r
155 \r
156     @Override\r
157     public int hashCode() {\r
158         return element.hashCode();\r
159     }\r
160 \r
161     @Override\r
162     public boolean equals(Object obj) {\r
163         if (this == obj)\r
164             return true;\r
165         if (obj == null)\r
166             return false;\r
167         if (getClass() != obj.getClass())\r
168             return false;\r
169         MonitorListener other = (MonitorListener) obj;\r
170         return element.equals(other.element);\r
171     }\r
172 \r
173 }