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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.modeling.ui.diagram.monitor;
\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
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
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
71 public class MonitorClassFactory2 extends SyncElementFactory {
\r
73 private static final Key KEY_VARIABLE_LISTENER = new KeyOf(MonitorListener.class,
\r
74 "MONITOR_VARIABLE_LISTENER");
\r
76 private static final String CLASS_ID = "Monitor";
\r
78 private static final IHintSynchronizer HINT_SYNCHRONIZER = new CompositeHintSynchronizer(
\r
79 MonitorSynchronizer.INSTANCE,
\r
80 TransformSynchronizer.INSTANCE);
\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
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
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
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
103 final Layer0 L0 = Layer0.getInstance(graph);
\r
104 final G2DResource G2D = G2DResource.getInstance(graph);
\r
105 final DiagramResource DIA = DiagramResource.getInstance(graph);
\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
111 AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, element);
\r
112 ElementUtils.setTransform(e, at);
\r
115 Resource hAlign = graph.getPossibleObject(element, G2D.HasHorizontalAlignment);
\r
116 Resource vAlign = graph.getPossibleObject(element, G2D.HasVerticalAlignment);
\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
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
134 String suffix = graph.getPossibleRelatedValue(element, DIA.HasMonitorSuffix, Bindings.STRING);
\r
135 if (suffix != null) e.setHint(MonitorClass.KEY_MONITOR_SUFFIX, suffix);
\r
137 String label = graph.getPossibleRelatedValue(element, L0.HasLabel);
\r
138 ElementUtils.setText(e, label);
\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
145 loadParentRelationships(graph, element, e);
\r
147 final Map<String, String> substitutions = new HashMap<String, String>();
\r
148 substitutions.put("#v1", "");
\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
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
162 e.setHint(MonitorClass.KEY_INPUT_VALIDATOR, func);
\r
163 RVI rvi = monitorVariable.getRVI();
\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
170 TextEditor ed = null;
\r
172 (ed = e.getElementClass().getAtMostOneItemOfClass(TextEditor.class)) != null) {
\r
173 ed.setModifier(e, new TextEditor.Modifier() {
\r
175 public String getValue(IElement e) {
\r
176 return MonitorClass.editText(e);
\r
180 public String isValid(IElement e, String text) {
\r
181 if (validator.get() != null)
\r
182 return validator.get().apply(text);
\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
192 public Evaluation evaluate(MonitorVariable result) {
\r
193 return result != null ? Evaluation.ACCEPT : Evaluation.IGNORE;
\r
197 public void accepted(MonitorVariable var) {
\r
198 session.asyncRequest(new MonitorVariableWrite(var.getVariable(), text), new Callback<DatabaseException>() {
\r
200 public void run(DatabaseException e) {
\r
202 ErrorLogger.defaultLogError(e);
\r
207 public void exception(Throwable t) {
\r
208 ErrorLogger.defaultLogError(t);
\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
225 if(monitorVariable != null)
\r
226 graph.asyncRequest(new MonitorVariableValueRequest(diagramRuntime, element), monitorListener);
\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
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
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
245 public void load(ReadGraph g, IDiagram diagram, IElement element) throws DatabaseException {
\r
246 loadParentRelationship(g, diagram, element, pde);
\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
259 DiagramResource DIA = DiagramResource.getInstance(g);
\r
260 DataElementMap map = diagram.getDiagramClass().getSingleItem(DataElementMap.class);
\r
261 IElement parentElement = map.getElement(diagram, parentElementResource);
\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
267 Resource tailNode = null;
\r
268 if (g.isInstanceOf(parentElementResource, DIA.Connection)) {
\r
269 tailNode = ConnectionUtil.getConnectionTailNode(g, parentElementResource);
\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