]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
2846a51bc6a0f50256c4df8395e3dccad221b6e6
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2010, 2012, 2014 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.sysdyn.ui.elements.connections;\r
13 \r
14 import java.awt.Color;\r
15 import java.awt.Font;\r
16 import java.io.StringReader;\r
17 import java.util.HashMap;\r
18 import java.util.List;\r
19 import java.util.Set;\r
20 import java.util.concurrent.ConcurrentSkipListMap;\r
21 import java.util.concurrent.atomic.AtomicInteger;\r
22 \r
23 import org.eclipse.jface.preference.PreferenceConverter;\r
24 import org.eclipse.jface.resource.StringConverter;\r
25 import org.eclipse.swt.graphics.FontData;\r
26 import org.eclipse.swt.graphics.RGB;\r
27 import org.simantics.databoard.Bindings;\r
28 import org.simantics.db.AsyncReadGraph;\r
29 import org.simantics.db.ReadGraph;\r
30 import org.simantics.db.Resource;\r
31 import org.simantics.db.Statement;\r
32 import org.simantics.db.common.utils.ListUtils;\r
33 import org.simantics.db.exception.DatabaseException;\r
34 import org.simantics.db.procedure.AsyncMultiProcedure;\r
35 import org.simantics.db.procedure.AsyncProcedure;\r
36 import org.simantics.db.procedure.SyncProcedure;\r
37 import org.simantics.diagram.G2DUtils;\r
38 import org.simantics.diagram.adapter.ElementFactoryAdapter;\r
39 import org.simantics.diagram.stubs.DiagramResource;\r
40 import org.simantics.diagram.stubs.G2DResource;\r
41 import org.simantics.g2d.canvas.ICanvasContext;\r
42 import org.simantics.g2d.diagram.DiagramHints;\r
43 import org.simantics.g2d.diagram.IDiagram;\r
44 import org.simantics.g2d.element.ElementClass;\r
45 import org.simantics.g2d.element.ElementHints;\r
46 import org.simantics.g2d.element.IElement;\r
47 import org.simantics.g2d.element.handler.impl.StaticObjectAdapter;\r
48 import org.simantics.layer0.Layer0;\r
49 import org.simantics.modeling.ModelingResources;\r
50 import org.simantics.sysdyn.SysdynResource;\r
51 import org.simantics.sysdyn.expressionParser.ExpressionParser;\r
52 import org.simantics.sysdyn.ui.editor.routing.DependencyRouter;\r
53 import org.simantics.sysdyn.ui.preferences.SysdynDiagramPreferences;\r
54 import org.simantics.sysdyn.ui.preferences.SysdynDiagramPropertyExternalRead;\r
55 import org.simantics.utils.datastructures.Pair;\r
56 \r
57 /**\r
58  * An element class for single connection entity elements. A connection entity\r
59  * consists of connection edge segments and branch points as its children.\r
60  * \r
61  * @author Tuukka Lehtonen\r
62  * @author Tuomas Miettinen\r
63  */\r
64 public class DependencyConnectionFactory extends ElementFactoryAdapter {\r
65 \r
66     public static final ElementClass CLASS = SysdynConnectionClass.CLASS;\r
67 \r
68     @Override\r
69     public void create(AsyncReadGraph graph, ICanvasContext canvas, IDiagram diagram, Resource elementType, final AsyncProcedure<ElementClass> procedure) {\r
70         procedure.execute(graph, SysdynConnectionClass.CLASS.newClassWith(false, new StaticObjectAdapter(elementType)));\r
71     }\r
72 \r
73     @Override\r
74     protected Resource getElementClassBaseType(AsyncReadGraph graph) {\r
75         return graph.getService(DiagramResource.class).Connection;\r
76     }\r
77 \r
78     @Override\r
79     public void load(AsyncReadGraph graph, ICanvasContext canvas, IDiagram diagram, final Resource elementResource,\r
80             final IElement element, final AsyncProcedure<IElement> procedure) {\r
81 \r
82         final AtomicInteger ready = new AtomicInteger(1);\r
83         final ConcurrentSkipListMap<String, Pair<Resource, Object>> properties = new ConcurrentSkipListMap<String, Pair<Resource, Object>>();\r
84 \r
85         element.setHint(DiagramHints.ROUTE_ALGORITHM, DependencyRouter.INSTANCE);\r
86 \r
87         G2DResource G2D;\r
88         try {\r
89             G2D = G2DResource.getInstance(graph.getSession());\r
90         } catch (DatabaseException e) {\r
91             e.printStackTrace();\r
92             return;\r
93         }\r
94 \r
95         // Find possible font\r
96         graph.forPossibleStatement(elementResource, G2D.HasFont, new SyncProcedure<Statement>() {\r
97 \r
98             @Override\r
99             public void execute(ReadGraph graph, Statement result) throws DatabaseException {\r
100                 if(result != null && !result.isAsserted(elementResource)) {\r
101                     element.setHint(ElementHints.KEY_FONT, G2DUtils.getFont(graph, result.getObject()));\r
102                 } else {\r
103                     String fontdata = graph.syncRequest(new SysdynDiagramPropertyExternalRead(new Pair<Resource, String>(elementResource, SysdynDiagramPreferences.ARROW_FONT)));\r
104                     if(fontdata != null) {\r
105                         FontData[] fdArray = PreferenceConverter.basicGetFontData(fontdata);\r
106                         if(fdArray != null) {\r
107                             if(fdArray.length == 1) {\r
108                                 FontData fd = fdArray[0];\r
109                                 if(fd != null) {\r
110                                     Font font = new Font(fd.getName(), fd.getStyle(), fd.getHeight());\r
111                                     element.setHint(ElementHints.KEY_FONT, font);\r
112                                 }\r
113                             }\r
114                         }\r
115                     }\r
116 \r
117                 }\r
118             }\r
119 \r
120             @Override\r
121             public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {\r
122                 throwable.printStackTrace();\r
123             }\r
124         });\r
125 \r
126         // Find possible color\r
127         graph.forPossibleStatement(elementResource, G2D.HasColor, new SyncProcedure<Statement>() {\r
128 \r
129             @Override\r
130             public void execute(ReadGraph graph, Statement result) throws DatabaseException {\r
131                 if(result != null && !result.isAsserted(elementResource)) {\r
132                     element.setHint(ElementHints.KEY_TEXT_COLOR, G2DUtils.getColor(graph, result.getObject()));\r
133                 } else {\r
134                         String color;\r
135                         if (isForStockInitialOnly(graph, elementResource)) {\r
136                                 color = graph.syncRequest(new SysdynDiagramPropertyExternalRead(new Pair<Resource, String>(elementResource, SysdynDiagramPreferences.ARROW_STOCK_INITIAL_COLOR)));\r
137                         } else {\r
138                                 color = graph.syncRequest(new SysdynDiagramPropertyExternalRead(new Pair<Resource, String>(elementResource, SysdynDiagramPreferences.ARROW_COLOR)));\r
139                         }\r
140                         if(color != null) {\r
141                         RGB rgb = StringConverter.asRGB(color, null);\r
142                         if(rgb != null) {\r
143                             Color c = new Color(rgb.red, rgb.green, rgb.blue);\r
144                             element.setHint(ElementHints.KEY_TEXT_COLOR, c);\r
145                         }\r
146                     }\r
147 \r
148                 }\r
149             }\r
150 \r
151             @Override\r
152             public void exception(ReadGraph graph, Throwable throwable) throws DatabaseException {\r
153                 throwable.printStackTrace();\r
154             }\r
155         });\r
156 \r
157 \r
158         // A complicated-looking procedure for obtaining all HasProperties to properties map\r
159         graph.forEachPredicate(elementResource, new AsyncMultiProcedure<Resource>() {\r
160 \r
161             @Override\r
162             public void exception(AsyncReadGraph graph, Throwable throwable) {\r
163                 throwable.printStackTrace();\r
164             }\r
165 \r
166             @Override\r
167             public void execute(AsyncReadGraph graph, final Resource property) {\r
168 \r
169                 ready.incrementAndGet();\r
170                 Layer0 l0;\r
171                 try {\r
172                     l0 = Layer0.getInstance(graph.getSession());\r
173                 } catch (DatabaseException e) {\r
174                     e.printStackTrace();\r
175                     return;\r
176                 }\r
177 \r
178                 graph.forIsSubrelationOf(property, l0.HasProperty, new AsyncProcedure<Boolean>() {\r
179 \r
180                     @Override\r
181                     public void exception(AsyncReadGraph graph, Throwable throwable) {\r
182                         throwable.printStackTrace();\r
183                     }\r
184 \r
185                     @Override\r
186                     public void execute(AsyncReadGraph graph, final Boolean isProperty) {\r
187 \r
188                         if(isProperty) {\r
189 \r
190                             graph.forPossibleRelatedValue(elementResource, property, new AsyncProcedure<Object>() {\r
191 \r
192                                 @Override\r
193                                 public void exception(AsyncReadGraph graph, Throwable throwable) {\r
194                                     throwable.printStackTrace();\r
195                                 }\r
196 \r
197                                 @Override\r
198                                 public void execute(AsyncReadGraph graph, final Object value) {\r
199 \r
200                                     Layer0 l0;\r
201                                     try {\r
202                                         l0 = Layer0.getInstance(graph.getSession());\r
203                                     } catch (DatabaseException e) {\r
204                                         e.printStackTrace();\r
205                                         return;\r
206                                     }\r
207 \r
208                                     graph.forPossibleRelatedValue(property, l0.HasName, Bindings.STRING, new AsyncProcedure<String>() {\r
209 \r
210                                         @Override\r
211                                         public void exception(AsyncReadGraph graph, Throwable throwable) {\r
212                                             throwable.printStackTrace();\r
213                                         }\r
214 \r
215                                         @Override\r
216                                         public void execute(AsyncReadGraph graph, String name) {\r
217 \r
218                                             properties.put(name, Pair.make(property, value));\r
219                                             if(ready.decrementAndGet() == 0) {\r
220                                                 element.setHint(DiagramHints.PROPERTIES, new HashMap<String, Pair<Resource, Object>>(properties));\r
221                                                 procedure.execute(graph, element);\r
222                                             }\r
223 \r
224                                         }\r
225 \r
226                                     });\r
227 \r
228                                 }\r
229 \r
230                             });\r
231 \r
232 \r
233                         } else {\r
234 \r
235                             if(ready.decrementAndGet() == 0) {\r
236                                 element.setHint(DiagramHints.PROPERTIES, new HashMap<String, Pair<Resource, Object>>(properties));\r
237                                 procedure.execute(graph, element);\r
238                             }\r
239 \r
240                         }\r
241 \r
242                     }\r
243 \r
244                 });\r
245             }\r
246 \r
247             @Override\r
248             public void finished(AsyncReadGraph graph) {\r
249 \r
250                 if(ready.decrementAndGet() == 0) {\r
251                     element.setHint(DiagramHints.PROPERTIES, new HashMap<String, Object>(properties));\r
252                     procedure.execute(graph, element);\r
253                 }\r
254 \r
255             }\r
256 \r
257         });\r
258 \r
259     }\r
260 \r
261         protected static boolean isForStockInitialOnly(ReadGraph graph,\r
262                         Resource elementResource) throws DatabaseException {\r
263                 SysdynResource SR = SysdynResource.getInstance(graph);\r
264         ModelingResources MO = ModelingResources.getInstance(graph);\r
265         Layer0 L0 = Layer0.getInstance(graph);\r
266         Resource connection = graph.getPossibleObject(elementResource, MO.DiagramConnectionToConnection);\r
267         if(connection == null) \r
268                 return false;\r
269         Resource tail = graph.getPossibleObject(connection, SR.Variable_HasTail);\r
270         if (tail == null)\r
271                 return false;\r
272         \r
273         if (graph.isInstanceOf(tail, SR.Shadow))\r
274                 tail = graph.getPossibleObject(tail, SR.Shadow_original);\r
275                 \r
276         Resource head = graph.getPossibleObject(connection, SR.Variable_HasHead);\r
277         if (head == null || !graph.isInstanceOf(head, SR.Stock) || tail == null)\r
278                 return false;\r
279         \r
280         Resource expressionListResource = graph.getPossibleObject(head, SR.Variable_expressionList);\r
281         List<Resource> expressionList = ListUtils.toPossibleList(graph, expressionListResource);\r
282         \r
283         // Keep track on whether at least one initial equation contains the variable\r
284         boolean initialContainsVariable = false;\r
285         // Go through all expressions\r
286         for (Resource expression : expressionList) {\r
287                 if (!graph.isInstanceOf(expression, SR.StockExpression))\r
288                         return false;\r
289                 \r
290                 String tailStr = graph.getPossibleRelatedValue(tail, L0.HasName, Bindings.STRING);\r
291                 String integral = graph.getPossibleRelatedValue(expression, SR.StockExpression_integralEquation, Bindings.STRING);\r
292                 if (equationContainsVariable(graph, integral, tailStr))\r
293                         // At least one integral equation contains the variable\r
294                         return false;\r
295                 String initial = graph.getPossibleRelatedValue(expression, SR.StockExpression_initialEquation, Bindings.STRING);\r
296                 if (!initialContainsVariable && equationContainsVariable(graph, initial, tailStr))\r
297                         // At least one initial equation contains the variable\r
298                         initialContainsVariable = true;\r
299         }\r
300         \r
301         // No integral equation contains the variable.\r
302                 return initialContainsVariable;\r
303         }\r
304 \r
305         private static boolean equationContainsVariable(ReadGraph graph,\r
306                         String equation, String variable) {\r
307                 ExpressionParser parser = new ExpressionParser(new StringReader(equation));\r
308                 try {\r
309                         parser.expr();\r
310                 } catch (Throwable t) {\r
311                         return false;\r
312                 }\r
313                 \r
314                 // Collect references\r
315         Set<String> references = parser.getReferences().keySet();\r
316         \r
317         // See if the equation contains variable\r
318         return references.contains(variable);\r
319         }\r
320 \r
321 }\r