]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/monitor/MonitorClassFactory2.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagram / monitor / MonitorClassFactory2.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in 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.awt.geom.AffineTransform;\r
15 import java.awt.geom.Rectangle2D;\r
16 import java.util.HashMap;\r
17 import java.util.Map;\r
18 import java.util.concurrent.atomic.AtomicReference;\r
19 \r
20 import org.simantics.browsing.ui.common.ErrorLogger;\r
21 import org.simantics.common.color.Color;\r
22 import org.simantics.databoard.Bindings;\r
23 import org.simantics.db.AsyncReadGraph;\r
24 import org.simantics.db.ReadGraph;\r
25 import org.simantics.db.Resource;\r
26 import org.simantics.db.Session;\r
27 import org.simantics.db.exception.DatabaseException;\r
28 import org.simantics.db.layer0.util.EvaluatingListener;\r
29 import org.simantics.db.layer0.util.EvaluatingListener.Evaluation;\r
30 import org.simantics.db.layer0.variable.RVI;\r
31 import org.simantics.db.layer0.variable.Variables;\r
32 import org.simantics.db.procedure.AsyncProcedure;\r
33 import org.simantics.diagram.adapter.SyncElementFactory;\r
34 import org.simantics.diagram.content.ConnectionUtil;\r
35 import org.simantics.diagram.elements.MonitorClass;\r
36 import org.simantics.diagram.stubs.DiagramResource;\r
37 import org.simantics.diagram.stubs.G2DResource;\r
38 import org.simantics.diagram.synchronization.CompositeHintSynchronizer;\r
39 import org.simantics.diagram.synchronization.IHintSynchronizer;\r
40 import org.simantics.diagram.synchronization.SynchronizationHints;\r
41 import org.simantics.diagram.synchronization.graph.DiagramGraphUtil;\r
42 import org.simantics.diagram.synchronization.graph.ElementLoader;\r
43 import org.simantics.diagram.synchronization.graph.MonitorSynchronizer;\r
44 import org.simantics.diagram.synchronization.graph.TransformSynchronizer;\r
45 import org.simantics.diagram.ui.DiagramModelHints;\r
46 import org.simantics.g2d.canvas.ICanvasContext;\r
47 import org.simantics.g2d.diagram.IDiagram;\r
48 import org.simantics.g2d.diagram.handler.DataElementMap;\r
49 import org.simantics.g2d.diagram.handler.Relationship;\r
50 import org.simantics.g2d.diagram.handler.RelationshipHandler;\r
51 import org.simantics.g2d.element.ElementClass;\r
52 import org.simantics.g2d.element.ElementHints;\r
53 import org.simantics.g2d.element.ElementUtils;\r
54 import org.simantics.g2d.element.IElement;\r
55 import org.simantics.g2d.element.handler.TextEditor;\r
56 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;\r
57 import org.simantics.layer0.Layer0;\r
58 import org.simantics.modeling.ModelingResources;\r
59 import org.simantics.scl.runtime.function.Function1;\r
60 import org.simantics.ui.colors.Colors;\r
61 import org.simantics.ui.fonts.FontDescriptor;\r
62 import org.simantics.ui.fonts.Fonts;\r
63 import org.simantics.utils.datastructures.Callback;\r
64 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
65 import org.simantics.utils.datastructures.hints.IHintContext.KeyOf;\r
66 \r
67 /**\r
68  * TODO: recognize experiment disposal and reset monitor contents at that point\r
69  * FIXME: monitor does not handle editing properly, and tries to include physical unit as part of numeric value\r
70  */\r
71 public class MonitorClassFactory2 extends SyncElementFactory {\r
72 \r
73     private static final Key               KEY_VARIABLE_LISTENER = new KeyOf(MonitorListener.class,\r
74                                                                          "MONITOR_VARIABLE_LISTENER");\r
75 \r
76     private static final String            CLASS_ID          = "Monitor";\r
77 \r
78     private static final IHintSynchronizer HINT_SYNCHRONIZER = new CompositeHintSynchronizer(\r
79             MonitorSynchronizer.INSTANCE,\r
80             TransformSynchronizer.INSTANCE);\r
81 \r
82     public static ElementClass createMonitorClass(Resource elementType) {\r
83         // set "default scale" to no scaling, 1.0, 1.0\r
84         return MonitorClass.create(1.0, 1.0, new StaticObjectAdapter(elementType)).setId(CLASS_ID);\r
85     }\r
86 \r
87     // staticScale{X,Y} define the scale of the static monitor image\r
88     public static ElementClass createMonitorClass(Resource elementType, IElement parentElement, HashMap<String, String> substitutions, Object component, String suffix, double staticScaleX, double staticScaleY) {\r
89         return MonitorClass.create(parentElement, substitutions, component, suffix, staticScaleX, staticScaleY, new StaticObjectAdapter(elementType)).setId(CLASS_ID);\r
90     }\r
91 \r
92     @Override\r
93     public void create(AsyncReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType,\r
94             AsyncProcedure<ElementClass> procedure) {\r
95         procedure.execute(graph, createMonitorClass(elementType));\r
96     }\r
97 \r
98     @Override\r
99     public void load(ReadGraph graph, final ICanvasContext canvas, final IDiagram diagram, final Resource element, final IElement e) throws DatabaseException {\r
100         if (!graph.hasStatement(element))\r
101             return;\r
102 \r
103         final Layer0 L0 = Layer0.getInstance(graph);\r
104         final G2DResource G2D = G2DResource.getInstance(graph);\r
105         final DiagramResource DIA = DiagramResource.getInstance(graph);\r
106 \r
107         // Must be done here to allow for the relationship manager to work properly.\r
108         e.setHint(ElementHints.KEY_OBJECT, element);\r
109         e.setHint(SynchronizationHints.HINT_SYNCHRONIZER, HINT_SYNCHRONIZER);\r
110 \r
111         AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, element);\r
112         ElementUtils.setTransform(e, at);\r
113 \r
114         // Load alignments\r
115         Resource hAlign = graph.getPossibleObject(element, G2D.HasHorizontalAlignment);\r
116         Resource vAlign = graph.getPossibleObject(element, G2D.HasVerticalAlignment);\r
117 \r
118         final Double borderWidth = graph.getPossibleRelatedValue(element, G2D.HasStrokeWidth);\r
119         Double direction = graph.getPossibleRelatedValue(element, DIA.HasDirection);\r
120         double bounds[] = DiagramGraphUtil.getPossibleRelatedDoubleArray(graph, element, G2D.HasBounds);\r
121         if (bounds != null) {\r
122             e.setHint(ElementHints.KEY_BOUNDS, new Rectangle2D.Double(bounds[0], bounds[1], bounds[2], bounds[3]));\r
123         }\r
124 \r
125         if (hAlign != null)\r
126             e.setHint(ElementHints.KEY_HORIZONTAL_ALIGN, DiagramGraphUtil.toAlignment(hAlign, G2D, MonitorClass.DEFAULT_HORIZONTAL_ALIGN));\r
127         if (vAlign != null)\r
128             e.setHint(ElementHints.KEY_VERTICAL_ALIGN, DiagramGraphUtil.toVerticalAlignment(vAlign, G2D, MonitorClass.DEFAULT_VERTICAL_ALIGN));\r
129         if (direction != null)\r
130             e.setHint(MonitorClass.KEY_DIRECTION, direction);\r
131         if (borderWidth != null)\r
132             e.setHint(MonitorClass.KEY_BORDER_WIDTH, borderWidth);\r
133 \r
134         String suffix = graph.getPossibleRelatedValue(element, DIA.HasMonitorSuffix, Bindings.STRING);\r
135         if (suffix != null) e.setHint(MonitorClass.KEY_MONITOR_SUFFIX, suffix);\r
136 \r
137         String label = graph.getPossibleRelatedValue(element, L0.HasLabel);\r
138         ElementUtils.setText(e, label);\r
139 \r
140         FontDescriptor fd = graph.getPossibleRelatedAdapter(element, DIA.HasFont, FontDescriptor.class);\r
141         if(fd != null) ElementUtils.setTextFont(e, Fonts.awt(fd));\r
142         Color color = graph.getPossibleRelatedAdapter(element, DIA.HasColor, Color.class);\r
143         if(color != null) ElementUtils.setTextColor(e, Colors.awt(color));\r
144 \r
145         loadParentRelationships(graph, element, e);\r
146 \r
147         final Map<String, String> substitutions = new HashMap<String, String>();\r
148         substitutions.put("#v1", "");\r
149 \r
150         final Resource diagramRuntime = diagram.getHint(DiagramModelHints.KEY_DIAGRAM_RUNTIME_RESOURCE);\r
151         if (diagramRuntime != null) {\r
152             final Session session = graph.getSession();\r
153 \r
154             // Resolve validator for monitor input if possible.\r
155             final AtomicReference<Function1<String, String>> validator = new AtomicReference<Function1<String, String>>();\r
156             MonitorVariable monitorVariable = graph.syncRequest(new ResolveMonitorVariable(diagramRuntime, element));\r
157             boolean readOnly = true;\r
158             if (monitorVariable != null) {\r
159                 Function1<String, String> func = monitorVariable.getVariable().getPossiblePropertyValue(graph, Variables.INPUT_VALIDATOR); \r
160                 validator.set( func );\r
161                 if (func != null)\r
162                     e.setHint(MonitorClass.KEY_INPUT_VALIDATOR, func);\r
163                 RVI rvi = monitorVariable.getRVI();\r
164                 if (rvi != null)\r
165                     e.setHint(MonitorClass.KEY_RVI, rvi);\r
166                 readOnly = Boolean.TRUE.equals(\r
167                         monitorVariable.getVariable().getPossiblePropertyValue(graph, Variables.READONLY, Bindings.BOOLEAN));\r
168             }\r
169 \r
170             TextEditor ed = null;\r
171             if (!readOnly &&\r
172                     (ed = e.getElementClass().getAtMostOneItemOfClass(TextEditor.class)) != null) {\r
173                 ed.setModifier(e, new TextEditor.Modifier() {\r
174                     @Override\r
175                     public String getValue(IElement e) {\r
176                         return MonitorClass.editText(e);\r
177                     }\r
178 \r
179                     @Override\r
180                     public String isValid(IElement e, String text) {\r
181                         if (validator.get() != null)\r
182                             return validator.get().apply(text);\r
183                         return null;\r
184                     }\r
185 \r
186                     @Override\r
187                     public void modify(final IElement e, final String text) {\r
188                         session.asyncRequest(new ResolveMonitorVariable(diagramRuntime, element),\r
189                                 new EvaluatingListener<MonitorVariable>(\r
190                                         new EvaluatingListener.Criterion<MonitorVariable>() {\r
191                             @Override\r
192                             public Evaluation evaluate(MonitorVariable result) {\r
193                                 return result != null ? Evaluation.ACCEPT : Evaluation.IGNORE;\r
194                             }\r
195                         }) {\r
196                             @Override\r
197                             public void accepted(MonitorVariable var) {\r
198                                 session.asyncRequest(new MonitorVariableWrite(var.getVariable(), text), new Callback<DatabaseException>() {\r
199                                     @Override\r
200                                     public void run(DatabaseException e) {\r
201                                         if (e != null)\r
202                                             ErrorLogger.defaultLogError(e);\r
203                                     }\r
204                                 });\r
205                             }\r
206                             @Override\r
207                             public void exception(Throwable t) {\r
208                                 ErrorLogger.defaultLogError(t);\r
209                             }\r
210                         });\r
211                     }\r
212 \r
213                 });\r
214             }\r
215 \r
216             IElement mappedElement = diagram.getDiagramClass().getSingleItem(DataElementMap.class).getElement(diagram, element);\r
217             MonitorListener monitorListener = new MonitorListener(element, canvas, diagram, substitutions);\r
218             if (mappedElement != null) {\r
219                 MonitorListener oldListener = mappedElement.getHint(KEY_VARIABLE_LISTENER);\r
220                 if (oldListener != null)\r
221                     oldListener.dispose();\r
222                 mappedElement.setHint(KEY_VARIABLE_LISTENER, monitorListener);\r
223             }\r
224 \r
225             if(monitorVariable != null)\r
226                 graph.asyncRequest(new MonitorVariableValueRequest(diagramRuntime, element), monitorListener);\r
227             \r
228         }\r
229     }\r
230 \r
231     private void loadParentRelationships(ReadGraph graph, Resource element, IElement e) throws DatabaseException {\r
232         DiagramResource DIA = DiagramResource.getInstance(graph);\r
233         ModelingResources MOD = ModelingResources.getInstance(graph);\r
234 \r
235         Resource monitorComponent = graph.getPossibleObject(element, DIA.HasMonitorComponent);\r
236         Resource parentDiagramElement = null;\r
237         if (monitorComponent != null)\r
238             parentDiagramElement = graph.getPossibleObject(monitorComponent, MOD.ComponentToElement);\r
239 \r
240         // Load parent relationship after all elements have been loaded.\r
241         if (parentDiagramElement != null) {\r
242             final Resource pde = parentDiagramElement;\r
243             e.setHint(DiagramModelHints.KEY_ELEMENT_LOADER, new ElementLoader() {\r
244                 @Override\r
245                 public void load(ReadGraph g, IDiagram diagram, IElement element) throws DatabaseException {\r
246                     loadParentRelationship(g, diagram, element, pde);\r
247                 }\r
248             });\r
249         }\r
250     }\r
251 \r
252     boolean loadParentRelationship(ReadGraph g, IDiagram diagram, IElement element, Resource parentElementResource)\r
253             throws DatabaseException {\r
254         // If no relationship handler is available, stop loading.\r
255         RelationshipHandler rh = diagram.getDiagramClass().getAtMostOneItemOfClass(RelationshipHandler.class);\r
256         if (rh == null)\r
257             return true;\r
258 \r
259         DiagramResource DIA = DiagramResource.getInstance(g);\r
260         DataElementMap map = diagram.getDiagramClass().getSingleItem(DataElementMap.class);\r
261         IElement parentElement = map.getElement(diagram, parentElementResource);\r
262 \r
263         if (parentElement != null) {\r
264             element.setHint(ElementHints.KEY_PARENT_ELEMENT, parentElement);\r
265             rh.claim(diagram, element, Relationship.CHILD_OF, parentElement);\r
266 \r
267             Resource tailNode = null;\r
268             if (g.isInstanceOf(parentElementResource, DIA.Connection)) {\r
269                 tailNode = ConnectionUtil.getConnectionTailNode(g, parentElementResource);\r
270             }\r
271 \r
272             if (tailNode != null) {\r
273                 IElement tailNodeElement = map.getElement(diagram, tailNode);\r
274                 if (parentElement != null) {\r
275                     element.setHint(ElementHints.KEY_PARENT_ELEMENT, tailNodeElement);\r
276                     rh.claim(diagram, element, Relationship.CHILD_OF, tailNodeElement);\r
277                 }\r
278             }\r
279 \r
280             return true;\r
281         }\r
282 \r
283         return false;\r
284     }\r
285 \r
286 }