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