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