]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
0ef578b924a11e1fc0392086021598ac86cbe54a
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2010 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.awt.BasicStroke;\r
15 import java.awt.Frame;\r
16 import java.awt.event.ActionEvent;\r
17 import java.awt.event.ActionListener;\r
18 import java.awt.geom.Point2D;\r
19 import java.io.StringReader;\r
20 import java.util.ArrayList;\r
21 import java.util.Arrays;\r
22 import java.util.List;\r
23 import java.util.Map;\r
24 \r
25 import javax.swing.Timer;\r
26 \r
27 import org.eclipse.jface.layout.GridDataFactory;\r
28 import org.eclipse.jface.layout.GridLayoutFactory;\r
29 import org.eclipse.jface.text.BadLocationException;\r
30 import org.eclipse.jface.text.IDocument;\r
31 import org.eclipse.swt.SWT;\r
32 import org.eclipse.swt.awt.SWT_AWT;\r
33 import org.eclipse.swt.custom.VerifyKeyListener;\r
34 import org.eclipse.swt.events.FocusAdapter;\r
35 import org.eclipse.swt.events.FocusEvent;\r
36 import org.eclipse.swt.events.FocusListener;\r
37 import org.eclipse.swt.events.KeyListener;\r
38 import org.eclipse.swt.events.ModifyEvent;\r
39 import org.eclipse.swt.events.ModifyListener;\r
40 import org.eclipse.swt.graphics.Point;\r
41 import org.eclipse.swt.widgets.Composite;\r
42 import org.eclipse.swt.widgets.Label;\r
43 import org.eclipse.swt.widgets.Table;\r
44 import org.jfree.chart.ChartFactory;\r
45 import org.jfree.chart.ChartPanel;\r
46 import org.jfree.chart.JFreeChart;\r
47 import org.jfree.chart.plot.PlotOrientation;\r
48 import org.jfree.data.xy.XYDataset;\r
49 import org.jfree.data.xy.XYSeries;\r
50 import org.jfree.data.xy.XYSeriesCollection;\r
51 import org.simantics.databoard.Bindings;\r
52 import org.simantics.db.ReadGraph;\r
53 import org.simantics.db.Resource;\r
54 import org.simantics.db.VirtualGraph;\r
55 import org.simantics.db.WriteGraph;\r
56 import org.simantics.db.common.request.WriteRequest;\r
57 import org.simantics.db.common.utils.ListUtils;\r
58 import org.simantics.db.exception.DatabaseException;\r
59 import org.simantics.db.procedure.Listener;\r
60 import org.simantics.db.request.Read;\r
61 import org.simantics.layer0.Layer0;\r
62 import org.simantics.layer0.utils.direct.GraphUtils;\r
63 import org.simantics.sysdyn.SysdynResource;\r
64 import org.simantics.sysdyn.tableParser.ParseException;\r
65 import org.simantics.sysdyn.tableParser.TableParser;\r
66 import org.simantics.sysdyn.tableParser.Token;\r
67 import org.simantics.sysdyn.ui.utils.SyntaxError;\r
68 import org.simantics.ui.SimanticsUI;\r
69 \r
70 public class WithLookupExpression implements IExpression {\r
71 \r
72     private ExpressionField expression;\r
73     private ExpressionField lookup;\r
74     private ExpressionField lastSelectedText = expression;\r
75     private Timer updateChartTimer;\r
76 \r
77     private ChartPanel smallPanel;\r
78     private Frame smallFrame;\r
79 \r
80     private final ExpressionWidgetInput input;\r
81     private Resource expr;\r
82 \r
83     public WithLookupExpression(ExpressionWidgetInput input) {\r
84         this.input = input;\r
85         this.expr = input.expression;\r
86     }\r
87 \r
88     @Override\r
89     public void createExpressionFields(Composite parent, final Map<String, Object> data, Table allowedVariables) {\r
90         GridLayoutFactory.fillDefaults().numColumns(3).applyTo(parent);\r
91 \r
92         updateChartTimer = new Timer(1000, new ActionListener() {\r
93 \r
94             @Override\r
95             public void actionPerformed(ActionEvent e) {\r
96                 updateChart();\r
97             }\r
98         });\r
99         updateChartTimer.setRepeats(false);\r
100 \r
101         String equation = data.get("equation") != null ? (String)data.get("equation") : "";\r
102         String lookupTable = data.get("lookup") != null ? (String)data.get("lookup") : "";\r
103 \r
104         Label l = new Label(parent, SWT.NONE);\r
105         l.setText("With\nLookup");\r
106 \r
107         expression = new ExpressionField(parent, SWT.BORDER, allowedVariables, true ,input);\r
108         expression.setExpression(equation);\r
109         GridDataFactory.fillDefaults().grab(true, true).applyTo(expression);\r
110 \r
111         expression.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() {\r
112 \r
113             @Override\r
114             public void focusLost(FocusEvent e) {\r
115                 lastSelectedText = expression;\r
116             }\r
117         });\r
118 \r
119         Composite chartContainer = new Composite(parent, SWT.NONE);\r
120         createChart(chartContainer, data);\r
121 \r
122 \r
123         l = new Label(parent, SWT.NONE);\r
124         l.setText("Lookup\ntable");\r
125 \r
126         lookup = new ExpressionField(parent, SWT.BORDER, null, false, input);\r
127         lookup.setExpression(lookupTable);\r
128         GridDataFactory.fillDefaults().grab(true, true).applyTo(lookup);\r
129 \r
130         lookup.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() {\r
131 \r
132             @Override\r
133             public void focusLost(FocusEvent e) {\r
134                 lastSelectedText = lookup;\r
135                 save(expr, data);\r
136             }\r
137         });\r
138 \r
139         lookup.getSourceViewer().getTextWidget().addModifyListener(new ModifyListener() {\r
140 \r
141             @Override\r
142             public void modifyText(ModifyEvent e) {\r
143                 if(!updateChartTimer.isRunning())\r
144                     updateChartTimer.start();\r
145                 else\r
146                     updateChartTimer.restart();\r
147             }\r
148         });\r
149 \r
150 \r
151         SimanticsUI.getSession().asyncRequest(new Read<String>() {\r
152 \r
153             @Override\r
154             public String perform(ReadGraph graph) throws DatabaseException {\r
155                 SysdynResource sr = SysdynResource.getInstance(graph);\r
156                 String result = "";\r
157                 if (expr != null && graph.isInstanceOf(expr, sr.WithLookupExpression)) {\r
158                     result = graph.getPossibleRelatedValue(expr, sr.WithLookupExpression_lookup);\r
159                 }\r
160                 return result;\r
161             }\r
162         }, new Listener<String>() {\r
163 \r
164             @Override\r
165             public void exception(Throwable t) {\r
166                 t.printStackTrace();\r
167             }\r
168 \r
169             @Override\r
170             public void execute(final String result) {\r
171                 if(lookup != null)\r
172                     lookup.getDisplay().asyncExec(new Runnable() {\r
173 \r
174                         @Override\r
175                         public void run() {\r
176                             lookup.setExpression(result);                            \r
177                         }\r
178                     });\r
179                 updateChart();\r
180             }\r
181 \r
182             @Override\r
183             public boolean isDisposed() {\r
184                 if(lookup != null && !lookup.isDisposed()) {\r
185                     return false;\r
186                 }\r
187                 return true;\r
188             }\r
189         });\r
190 \r
191         updateChart();\r
192     }\r
193 \r
194     @Override\r
195     public void focus() {\r
196         if(this.lastSelectedText != null) this.lastSelectedText.focus();        \r
197     }\r
198 \r
199     @Override\r
200     public List<ExpressionField> getExpressionFields() {\r
201         return Arrays.asList(this.expression, this.lookup);\r
202     }\r
203 \r
204     @Override\r
205     public void readData(final Resource expression, Map<String, Object> data) {\r
206 \r
207         class Auxiliary {\r
208             String equation, lookup;\r
209         }\r
210 \r
211         Auxiliary results = null;\r
212 \r
213         if (data.get("equation") == null) {\r
214             try {\r
215                 results = SimanticsUI.getSession().syncRequest(new Read<Auxiliary>() {\r
216 \r
217                     @Override\r
218                     public Auxiliary perform(ReadGraph graph) throws DatabaseException {\r
219                         Auxiliary results = new Auxiliary();\r
220                         SysdynResource sr = SysdynResource.getInstance(graph);\r
221                         if (expression != null && graph.isInstanceOf(expression, sr.WithLookupExpression)) {\r
222                             results.equation = graph.getPossibleRelatedValue(expression, sr.WithLookupExpression_expression);\r
223                             results.lookup = graph.getPossibleRelatedValue(expression, sr.WithLookupExpression_lookup);\r
224                         } else {\r
225                             results.equation = "";\r
226                             results.lookup = "";\r
227                         }\r
228                         return results;\r
229                     }\r
230                 });\r
231             } catch (DatabaseException e1) {\r
232                 e1.printStackTrace();\r
233             }\r
234             data.put("equation", results.equation == null ? "" : results.equation);\r
235             data.put("lookup", results.lookup == null ? "" : results.lookup);\r
236         }\r
237 \r
238     }\r
239 \r
240     @Override\r
241     public void replaceSelection(String var) {\r
242         if(lastSelectedText != null) {\r
243             IDocument doc = lastSelectedText.getDocument();\r
244             try {\r
245                 Point selection = lastSelectedText.getSelection();\r
246                 doc.replace(selection.x, selection.y, var);\r
247                 lastSelectedText.setSelection(selection.x + var.length());\r
248             } catch (BadLocationException e) {\r
249                 e.printStackTrace();\r
250             }\r
251         }        \r
252     }\r
253 \r
254     @Override\r
255     public void save(final Resource expression, Map<String, Object> data) {\r
256         final String currentExpression = this.expression.getExpression();\r
257         final String currentLookupTable = lookup.getExpression();\r
258         String oldExpression = (String)data.get("equation");\r
259         String oldLookupTable = (String)data.get("lookup");\r
260 \r
261         if(oldExpression == null || oldLookupTable == null ||\r
262                 (currentExpression != null && currentLookupTable != null\r
263                         && (!currentExpression.equals(oldExpression) || \r
264                                 !currentLookupTable.equals(oldLookupTable)))) {\r
265             data.putAll(data);\r
266             data.put("equation", currentExpression);\r
267             data.put("lookup", currentLookupTable);\r
268             SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
269                 @Override\r
270                 public void perform(WriteGraph g)\r
271                 throws DatabaseException {\r
272                     SysdynResource sr = SysdynResource.getInstance(g);\r
273                     Layer0 l0 = Layer0.getInstance(g);\r
274                     \r
275                     if(!g.isInstanceOf(expr, sr.WithLookupExpression)) {\r
276                         \r
277                         \r
278                         final Resource newExpression = GraphUtils.create2(g, sr.WithLookupExpression,\r
279                                         sr.WithLookupExpression_minX, 0.0,\r
280                                         sr.WithLookupExpression_maxX, 10.0,\r
281                                         sr.WithLookupExpression_minY, 0.0,\r
282                                         sr.WithLookupExpression_maxY, 10.0);\r
283                         String arrayRange = g.getPossibleRelatedValue(expression, sr.Expression_arrayRange, Bindings.STRING);\r
284                         if(arrayRange != null)\r
285                                 g.claimLiteral(newExpression, sr.Expression_arrayRange, arrayRange);\r
286                         \r
287                         final Resource variable = g.getSingleObject(expression, l0.PartOf);\r
288                         Resource expressions = g.getPossibleObject(variable, sr.Variable_expressionList);\r
289                         Resource node = ListUtils.getNode(g, expressions, expression);\r
290                         g.deny(node, l0.List_Element);\r
291                         g.claim(node, l0.List_Element, newExpression);\r
292                         \r
293                         g.deny(expression, l0.PartOf);\r
294                         g.claim(newExpression, l0.PartOf, variable);\r
295                         \r
296                                                 VirtualGraph runtime = g.getService(VirtualGraph.class);\r
297                                                 g.syncRequest(new WriteRequest(runtime) {\r
298                                                         @Override\r
299                                                         public void perform(WriteGraph graph) throws DatabaseException {\r
300                                                                 SysdynResource sr = SysdynResource.getInstance(graph);\r
301                                                                 if(graph.hasStatement(variable, sr.IndependentVariable_activeExpression))\r
302                                                                         graph.deny(variable, sr.IndependentVariable_activeExpression);\r
303                                                                 graph.claim(variable, sr.IndependentVariable_activeExpression, newExpression);\r
304                                                         }\r
305                                                 }\r
306                                                 );\r
307                         expr = newExpression;\r
308                         \r
309                     }\r
310                     g.claimLiteral(expr, sr.WithLookupExpression_expression, currentExpression);\r
311                     g.claimLiteral(expr, sr.WithLookupExpression_lookup, currentLookupTable);\r
312                 }\r
313             });\r
314         }\r
315 \r
316     }\r
317 \r
318     @Override\r
319     public void updateData(Map<String, Object> data) {\r
320         if(this.expression != null && this.expression.getExpression() != null)\r
321             data.put("equation", this.expression.getExpression());\r
322         if(this.lookup != null && this.lookup.getExpression() != null)\r
323             data.put("lookup", this.lookup.getExpression());   \r
324     }\r
325 \r
326     @Override\r
327     public void addKeyListener(KeyListener listener) {\r
328         this.expression.getSourceViewer().getTextWidget().addKeyListener(listener);\r
329         this.lookup.getSourceViewer().getTextWidget().addKeyListener(listener);\r
330     }\r
331     \r
332         @Override\r
333         public void addVerifyKeyListener(VerifyKeyListener listener) {\r
334                 this.expression.getSourceViewer().getTextWidget().addVerifyKeyListener(listener);\r
335                 this.lookup.getSourceViewer().getTextWidget().addVerifyKeyListener(listener);\r
336         }\r
337 \r
338     @Override\r
339     public void addModifyListener(ModifyListener listener) {\r
340         this.expression.getSourceViewer().getTextWidget().addModifyListener(listener);\r
341         this.lookup.getSourceViewer().getTextWidget().addModifyListener(listener);\r
342     }\r
343 \r
344     @Override\r
345     public void addFocusListener(FocusListener listener) {\r
346         this.expression.getSourceViewer().getTextWidget().addFocusListener(listener);\r
347         this.lookup.getSourceViewer().getTextWidget().addFocusListener(listener);\r
348     }\r
349 \r
350     private void createChart(Composite composite, final Map<String, Object> data) {\r
351         GridLayoutFactory.fillDefaults().applyTo(composite);\r
352         GridDataFactory.fillDefaults().span(1, 2).hint(150, SWT.DEFAULT).applyTo(composite);\r
353         final Composite chartComposite = new Composite(composite, \r
354                 SWT.NO_BACKGROUND | SWT.EMBEDDED);\r
355         GridDataFactory.fillDefaults().grab(true, true).applyTo(chartComposite);\r
356         smallFrame = SWT_AWT.new_Frame(chartComposite);\r
357 \r
358         XYDataset dataset = new XYSeriesCollection(new XYSeries("Lookup Table"));\r
359         JFreeChart chart = createChart(dataset);\r
360         smallPanel = new ChartPanel(chart);\r
361         smallFrame.add(smallPanel);\r
362 \r
363     }\r
364 \r
365     private static JFreeChart createChart(XYDataset dataset) {\r
366         JFreeChart chart = ChartFactory.createXYLineChart(\r
367                 null,\r
368                 null,\r
369                 null,\r
370                 dataset,\r
371                 PlotOrientation.VERTICAL,\r
372                 true,\r
373                 true,\r
374                 false\r
375         );\r
376         chart.removeLegend();\r
377         chart.getXYPlot().getDomainAxis().setTickLabelsVisible(true);\r
378         chart.getXYPlot().getDomainAxis().setAxisLineVisible(false);\r
379         chart.getXYPlot().getDomainAxis().setTickMarksVisible(true);\r
380         chart.getXYPlot().getRangeAxis().setTickLabelsVisible(true);\r
381         chart.getXYPlot().getRangeAxis().setAxisLineVisible(false);\r
382         chart.getXYPlot().getRangeAxis().setTickMarksVisible(true);\r
383         chart.getXYPlot().getRenderer().setSeriesStroke(0, new BasicStroke(3.0f));\r
384         return chart;\r
385     }\r
386 \r
387     private void updateChart() {\r
388         ArrayList<Point2D> dataPoints = new ArrayList<Point2D>();\r
389         TableParser parser = new TableParser(new StringReader(""));\r
390         parser.ReInit(new StringReader(lookup.getExpression()));\r
391         try {\r
392             parser.table();\r
393             ArrayList<Token> xTokens = parser.getXTokens();\r
394             ArrayList<Token> yTokens = parser.getYTokens();\r
395             for(int i = 0; i < xTokens.size(); i++) {\r
396                 dataPoints.add(new Point2D.Double(\r
397                         Double.parseDouble(xTokens.get(i).image), \r
398                         Double.parseDouble(yTokens.get(i).image)));\r
399             }\r
400         } catch (ParseException e1) {\r
401             this.lookup.setSyntaxError(new SyntaxError(e1.currentToken, "Syntax Error"));\r
402             System.out.println("MESSAGE: " + e1.getMessage());\r
403             return;\r
404         }\r
405 \r
406         XYSeries series = new XYSeries("Lookup Table");\r
407         for(Point2D point : dataPoints) {\r
408             series.add(point.getX(), point.getY());\r
409         }\r
410         XYSeriesCollection dataset =  new XYSeriesCollection(series);\r
411         smallPanel.getChart().getXYPlot().setDataset(dataset);\r
412     }\r
413 \r
414 }\r