]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
f64b138d5c824c89be6b0d3884d6c2cfd4b19462
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 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.properties.widgets.expressions;\r
13 \r
14 import java.util.Arrays;\r
15 import java.util.List;\r
16 import java.util.Map;\r
17 \r
18 import org.eclipse.jface.layout.GridDataFactory;\r
19 import org.eclipse.jface.layout.GridLayoutFactory;\r
20 import org.eclipse.jface.text.BadLocationException;\r
21 import org.eclipse.jface.text.IDocument;\r
22 import org.eclipse.jface.text.IUndoManager;\r
23 import org.eclipse.jface.text.TextViewerUndoManager;\r
24 import org.eclipse.swt.SWT;\r
25 import org.eclipse.swt.custom.VerifyKeyListener;\r
26 import org.eclipse.swt.events.FocusAdapter;\r
27 import org.eclipse.swt.events.FocusEvent;\r
28 import org.eclipse.swt.events.FocusListener;\r
29 import org.eclipse.swt.events.KeyListener;\r
30 import org.eclipse.swt.events.ModifyListener;\r
31 import org.eclipse.swt.graphics.Point;\r
32 import org.eclipse.swt.widgets.Button;\r
33 import org.eclipse.swt.widgets.Composite;\r
34 import org.eclipse.swt.widgets.Event;\r
35 import org.eclipse.swt.widgets.Label;\r
36 import org.eclipse.swt.widgets.Listener;\r
37 import org.eclipse.swt.widgets.Table;\r
38 import org.simantics.Simantics;\r
39 import org.simantics.databoard.Bindings;\r
40 import org.simantics.db.ReadGraph;\r
41 import org.simantics.db.Resource;\r
42 import org.simantics.db.WriteGraph;\r
43 import org.simantics.db.common.CommentMetadata;\r
44 import org.simantics.db.common.request.ReadRequest;\r
45 import org.simantics.db.common.request.ResourceRead;\r
46 import org.simantics.db.common.request.WriteRequest;\r
47 import org.simantics.db.common.utils.ListUtils;\r
48 import org.simantics.db.exception.DatabaseException;\r
49 import org.simantics.db.layer0.util.Layer0Utils;\r
50 import org.simantics.db.layer0.util.RemoverUtil;\r
51 import org.simantics.db.request.Read;\r
52 import org.simantics.layer0.Layer0;\r
53 import org.simantics.sysdyn.SysdynResource;\r
54 import org.simantics.sysdyn.manager.SysdynModel;\r
55 import org.simantics.sysdyn.manager.SysdynModelManager;\r
56 import org.simantics.sysdyn.representation.Stock;\r
57 import org.simantics.sysdyn.representation.Valve;\r
58 import org.simantics.sysdyn.ui.properties.EquationTab;\r
59 import org.simantics.utils.datastructures.Pair;\r
60 import org.simantics.utils.datastructures.Triple;\r
61 import org.slf4j.Logger;\r
62 import org.slf4j.LoggerFactory;\r
63 \r
64 public class StockExpression implements IExpression {\r
65 \r
66         private static final Logger LOGGER = LoggerFactory.getLogger(StockExpression.class);\r
67         private final ExpressionWidgetInput input;\r
68         private ExpressionField integralExpression, initialExpression;\r
69         private ExpressionField lastSelectedText;\r
70         private TextViewerUndoManager undoManager;\r
71 \r
72         public StockExpression(ExpressionWidgetInput input) {\r
73                 this.input = input;\r
74         }\r
75 \r
76         @Override\r
77         public void createExpressionFields(Composite parent, Map<String, Object> data, Table allowedVariables) {\r
78                 GridLayoutFactory.fillDefaults().numColumns(2).applyTo(parent);\r
79                 String initialEquation = data.get("initialEquation") != null ? (String)data.get("initialEquation") : "";\r
80                 String integralEquation = data.get("integral") != null ? (String)data.get("integral") : getDefaultIntegral(input.expression);\r
81 \r
82 \r
83                 Label label = new Label(parent, SWT.NONE);\r
84                 label.setText("Integral");\r
85 \r
86                 Composite integralComposite = new Composite(parent, SWT.NONE);\r
87                 GridDataFactory.fillDefaults().grab(true, true).applyTo(integralComposite);\r
88                 GridLayoutFactory.fillDefaults().numColumns(2).applyTo(integralComposite);\r
89 \r
90                 integralExpression = new ExpressionField(integralComposite, SWT.BORDER, allowedVariables, true, input);\r
91                 integralExpression.setExpression(integralEquation);\r
92                 GridDataFactory.fillDefaults().grab(true, true).applyTo(integralExpression);\r
93                 integralExpression.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() {\r
94 \r
95                         @Override\r
96                         public void focusLost(FocusEvent e) {\r
97                                 lastSelectedText = integralExpression;\r
98                         }\r
99                 });\r
100 \r
101                 undoManager = new TextViewerUndoManager(100);\r
102                 integralExpression.getSourceViewer().setUndoManager(undoManager);\r
103                 undoManager.connect(integralExpression.getSourceViewer());\r
104 \r
105                 Button defaultButton = new Button(integralComposite, SWT.PUSH);\r
106                 defaultButton.setText("Use default");\r
107                 defaultButton.addListener(SWT.Selection, new Listener() {\r
108 \r
109                         @Override\r
110                         public void handleEvent(Event event) {\r
111                                 switch (event.type) {\r
112                                 case SWT.Selection:\r
113                                         StockExpression.this.integralExpression.setExpression(getDefaultIntegral(input.expression));\r
114                                         Simantics.getSession().asyncRequest(new WriteRequest() {\r
115 \r
116                                                 @Override\r
117                                                 public void perform(WriteGraph graph)\r
118                                                                 throws DatabaseException {\r
119                                                         // Delete the possible integral expression from the database to note \r
120                                                         // that we are in the "default" mode.\r
121                                                         graph.markUndoPoint();\r
122                                                         SysdynResource sr = SysdynResource.getInstance(graph);\r
123                                                         graph.deny(input.expression, sr.StockExpression_useCustomIntegral);\r
124                                                         graph.claimLiteral(input.expression, sr.StockExpression_integralEquation, getDefaultIntegral(graph, input.expression));\r
125 \r
126                                                         CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
127                                                         graph.addMetadata(cm.add("Use default"));\r
128 \r
129                                                 }\r
130                                         });\r
131                                         break;\r
132                                 }\r
133                         }\r
134 \r
135                 });\r
136 \r
137                 label = new Label(parent, SWT.NONE);\r
138                 label.setText("Initial\nValue");\r
139 \r
140                 initialExpression = new ExpressionField(parent, SWT.BORDER, allowedVariables, true, input);\r
141                 initialExpression.setExpression(initialEquation);\r
142                 GridDataFactory.fillDefaults().grab(true, true).applyTo(initialExpression);\r
143                 initialExpression.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() {\r
144 \r
145                         @Override\r
146                         public void focusLost(FocusEvent e) {\r
147                                 lastSelectedText = initialExpression;\r
148                         }\r
149                 });\r
150 \r
151                 lastSelectedText = initialExpression;\r
152         }\r
153 \r
154         @Override\r
155         public void focus() {\r
156                 this.lastSelectedText.focus();\r
157         }\r
158 \r
159         @Override\r
160         public List<ExpressionField> getExpressionFields() {\r
161                 return Arrays.asList(this.integralExpression, this.initialExpression);\r
162         }\r
163 \r
164         @Override\r
165         public void readData(final Resource expression, final Map<String, Object> data) {\r
166                 if(expression == null) {\r
167                         LOGGER.warn("StockExpression is null");\r
168                         return;\r
169                 }\r
170                 if(!expression.equals(data.get("expression"))) {\r
171                         data.clear();\r
172                 }\r
173 \r
174                 Object getInitialEquation = data.get("initialEquation");\r
175                 Object integralEquation = data.get("integral");\r
176                 Boolean useCustomIntegral = (Boolean) data.get("useCustomIntegral");\r
177                 if (getInitialEquation == null || integralEquation == null || useCustomIntegral == null) {\r
178                         try {\r
179                                 Triple<String, String, Boolean> equations = Simantics.getSession().syncRequest(new ResourceRead<Triple<String, String, Boolean>>(expression) {\r
180 \r
181                                         @Override\r
182                                         public Triple<String, String, Boolean> perform(ReadGraph graph) throws DatabaseException {\r
183                                                 SysdynResource sr = SysdynResource.getInstance(graph);\r
184                                                 boolean useCustomIntegral = graph.hasStatement(resource, sr.StockExpression_useCustomIntegral);\r
185                                                 if (graph.isInstanceOf(expression, sr.StockExpression)) {\r
186                                                         String initialEquation = graph.getPossibleRelatedValue(expression, sr.StockExpression_initialEquation);\r
187                                                         String integralEquation = graph.getPossibleRelatedValue(expression, sr.StockExpression_integralEquation);\r
188                                                         initialEquation = (initialEquation != null) ? initialEquation : "";\r
189                                                         return new Triple<String, String, Boolean>(integralEquation, initialEquation, useCustomIntegral);\r
190                                                 } else {\r
191                                                         return new Triple<String, String, Boolean>(null, "", useCustomIntegral);\r
192                                                 }\r
193                                         }\r
194                                 });\r
195                                 data.put("integral", equations.first);\r
196                                 data.put("initialEquation", equations.second);\r
197                                 data.put("useCustomIntegral", equations.third);\r
198                                 integralEquation = equations.first;\r
199                                 getInitialEquation = equations.second;\r
200                                 useCustomIntegral = equations.third;\r
201                         } catch (DatabaseException e1) {\r
202                                 e1.printStackTrace();\r
203                         }\r
204                 }\r
205                 if (integralEquation == null) {\r
206                         try {\r
207                                 Simantics.getSession().syncRequest(new WriteRequest() {\r
208 \r
209                                         @Override\r
210                                         public void perform(WriteGraph graph) throws DatabaseException {\r
211                                                 SysdynResource sr = SysdynResource.getInstance(graph);\r
212                                                 graph.claimLiteral(input.expression, sr.StockExpression_integralEquation, getDefaultIntegral(graph, input.expression));\r
213                                                 graph.markUndoPoint();\r
214                                                 CommentMetadata cm = graph.getMetadata(CommentMetadata.class);\r
215                                                 graph.addMetadata(cm.add("Set expression"));\r
216                                         }\r
217                                 });\r
218                         } catch (DatabaseException e) {\r
219                                 // TODO Auto-generated catch block\r
220                                 e.printStackTrace();\r
221                         }\r
222 \r
223                         data.put("integral", getDefaultIntegral(expression));\r
224                 } else if(!useCustomIntegral) {\r
225                         data.put("integral", getDefaultIntegral(expression));\r
226                 }\r
227                 /*\r
228 \r
229                 try {\r
230                         final String integral = equations.first;\r
231                                 Simantics.getSession().syncRequest(new ReadRequest() {\r
232 \r
233                                         @Override\r
234                                         public void run(ReadGraph graph) throws DatabaseException {\r
235                                                 SysdynResource sr = SysdynResource.getInstance(graph);\r
236                                         if (graph.hasStatement(input.expression, sr.StockExpression_useCustomIntegral)) {\r
237                                                 data.put("integral", integral);\r
238                                         } else {\r
239                                                 data.put("integral", getDefaultIntegral(graph, expression));\r
240                                         }\r
241                                         }\r
242 \r
243                                 });\r
244                         } catch (DatabaseException e) {\r
245                                 data.put("integral", equations.first);\r
246                                 e.printStackTrace();\r
247                         }\r
248                  */\r
249                 data.put("expression", expression);\r
250         }\r
251 \r
252         @Override\r
253         public void replaceSelection(String var) {\r
254                 if(lastSelectedText != null) {\r
255                         IDocument doc = lastSelectedText.getDocument();\r
256                         try {\r
257                                 Point selection = lastSelectedText.getSelection();\r
258                                 doc.replace(selection.x, selection.y, var);\r
259                                 lastSelectedText.setSelection(selection.x + var.length());\r
260                         } catch (BadLocationException e) {\r
261                                 e.printStackTrace();\r
262                         }\r
263                 }\r
264         }\r
265 \r
266         @Override\r
267         public void save(final Resource expression, final Map<String, Object> data) {\r
268                 final String currentInitial = this.initialExpression.getExpression();\r
269                 final String currentIntegral = this.integralExpression.getExpression();\r
270                 if (currentIntegral == null) {\r
271                         this.integralExpression.setExpression(getDefaultIntegral(expression));\r
272                 }\r
273                 if(!currentInitial.equals(data.get("initialEquation"))\r
274                                 || currentIntegral == null\r
275                                 || !currentIntegral.equals(data.get("integral"))) {\r
276                         Simantics.getSession().asyncRequest(new WriteRequest() {\r
277 \r
278                                 @Override\r
279                                 public void perform(WriteGraph g)\r
280                                                 throws DatabaseException {\r
281                                         SysdynResource sr = SysdynResource.getInstance(g);\r
282                                         Layer0 l0 = Layer0.getInstance(g);\r
283 \r
284                                         if(!g.isInstanceOf(expression, sr.StockExpression)) {\r
285                                                 Resource variable = g.getPossibleObject(expression, l0.PartOf);\r
286                                                 Resource expressionList = g.getPossibleObject(variable, sr.Variable_expressionList);\r
287                                                 Resource temp = g.newResource();\r
288                                                 ListUtils.replace(g, expressionList, expression, temp);\r
289 \r
290                                                 for(Resource predicate : g.getPredicates(expression)) {\r
291                                                         g.deny(expression, predicate);\r
292                                                 }\r
293                                                 g.claim(expression, l0.InstanceOf, null, sr.StockExpression);\r
294 \r
295                                                 ListUtils.replace(g, expressionList, temp, expression);\r
296 \r
297                                                 RemoverUtil.remove(g, temp);\r
298 \r
299                                                 g.claim(expression, l0.PartOf, variable);\r
300                                         }\r
301                                         g.claimLiteral(expression, sr.StockExpression_initialEquation, currentInitial);\r
302 \r
303                                         if (!currentIntegral.equals(g.getPossibleRelatedValue(expression, sr.StockExpression_integralEquation, Bindings.STRING))) {\r
304                                                 // If the value is not same as default, enable the custom tag\r
305                                                 g.claim(expression, sr.StockExpression_useCustomIntegral, expression);\r
306                                         }\r
307                                         g.claimLiteral(expression, sr.StockExpression_integralEquation, currentIntegral);\r
308 \r
309                                         updateData(data);\r
310 \r
311                                         g.markUndoPoint();\r
312 \r
313                                         Layer0Utils.addCommentMetadata(g, "Saved Stock Expression " + currentIntegral + " " + expression.toString() + " with Initial Value " + currentInitial);\r
314                                 }\r
315 \r
316                         });\r
317                 }\r
318                 this.initialExpression.setExpression(currentInitial);\r
319                 this.integralExpression.setExpression(currentIntegral);\r
320         }\r
321 \r
322         @Override\r
323         public void updateData(Map<String, Object> data) {\r
324                 if(this.initialExpression != null && this.initialExpression.getExpression() != null)\r
325                         data.put("initialEquation", this.initialExpression.getExpression());\r
326                 if(this.integralExpression != null && this.integralExpression.getExpression() != null)\r
327                         data.put("integral", this.integralExpression.getExpression());\r
328         }\r
329 \r
330 \r
331         private static String getDefaultIntegral(ReadGraph graph, Resource expression) throws DatabaseException {\r
332                 SysdynResource sr = SysdynResource.getInstance(graph);\r
333                 Layer0 l0 = Layer0.getInstance(graph);\r
334 \r
335                 // find the variable\r
336                 Resource variable = graph.getPossibleObject(expression, l0.PartOf);\r
337                 if(variable == null)\r
338                         return "";\r
339 \r
340                 SysdynModelManager sdm = SysdynModelManager.getInstance(graph.getSession());\r
341                 SysdynModel model = sdm.getModel(graph, graph.getSingleObject(variable, l0.PartOf));\r
342                 model.update(graph);\r
343 \r
344                 Stock stock = (Stock)model.getElement(variable);\r
345 \r
346                 String range = graph.getPossibleRelatedValue(expression, sr.Expression_arrayRange);\r
347                 if(range == null)\r
348                         range = "";\r
349 \r
350                 StringBuilder builder = new StringBuilder();\r
351                 builder.append("");\r
352                 for(Valve in : stock.getIncomingValves()) {\r
353                         builder.append(" + " + in.getName() + range);\r
354                 }\r
355                 for(Valve out : stock.getOutgoingValves()) {\r
356                         builder.append(" - " + out.getName() + range);\r
357                 }\r
358                 if (builder.indexOf(" + ") == 0)\r
359                         builder.delete(0, 3);\r
360 \r
361                 return builder.toString().trim();       \r
362         }\r
363 \r
364 \r
365         private static String getDefaultIntegral(final Resource expression) {\r
366 \r
367                 String integral = "";\r
368                 if(expression == null)\r
369                         return integral;\r
370                 try {\r
371                         integral = Simantics.getSession().syncRequest(new Read<String>() {\r
372 \r
373                                 @Override\r
374                                 public String perform(ReadGraph graph) throws DatabaseException {\r
375                                         return getDefaultIntegral(graph, expression);\r
376                                 }\r
377 \r
378                         });\r
379                 } catch (DatabaseException e) {\r
380                         e.printStackTrace();\r
381                 }\r
382                 return integral;\r
383         }\r
384 \r
385         @Override\r
386         public void addKeyListener(KeyListener listener) {\r
387                 this.initialExpression.getSourceViewer().getTextWidget().addKeyListener(listener);\r
388                 this.integralExpression.getSourceViewer().getTextWidget().addKeyListener(listener);\r
389 \r
390         }\r
391 \r
392         @Override\r
393         public void addModifyListener(ModifyListener listener) {\r
394                 this.initialExpression.getSourceViewer().getTextWidget().addModifyListener(listener);\r
395                 this.integralExpression.getSourceViewer().getTextWidget().addModifyListener(listener);\r
396 \r
397         }\r
398 \r
399         @Override\r
400         public void addFocusListener(FocusListener listener) {\r
401                 this.initialExpression.getSourceViewer().getTextWidget().addFocusListener(listener);\r
402                 this.integralExpression.getSourceViewer().getTextWidget().addFocusListener(listener);\r
403         }\r
404 \r
405         @Override\r
406         public void addVerifyKeyListener(VerifyKeyListener listener) {\r
407                 this.initialExpression.getSourceViewer().getTextWidget().addVerifyKeyListener(listener);\r
408                 this.integralExpression.getSourceViewer().getTextWidget().addVerifyKeyListener(listener);\r
409         }\r
410 \r
411         @Override\r
412         public IUndoManager getUndoManager() {\r
413                 return undoManager;\r
414         }\r
415 \r
416 }\r