]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
bf51ebe7d4edb6da26395d8dd3add89cc8ac71c9
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2011 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.functions;\r
13 \r
14 import java.awt.event.ActionEvent;\r
15 import java.awt.event.ActionListener;\r
16 import java.io.StringReader;\r
17 import java.util.ArrayList;\r
18 \r
19 import javax.swing.Timer;\r
20 \r
21 import org.eclipse.jface.layout.GridDataFactory;\r
22 import org.eclipse.swt.SWT;\r
23 import org.eclipse.swt.custom.StyledText;\r
24 import org.eclipse.swt.custom.VerifyKeyListener;\r
25 import org.eclipse.swt.events.FocusAdapter;\r
26 import org.eclipse.swt.events.FocusEvent;\r
27 import org.eclipse.swt.events.ModifyEvent;\r
28 import org.eclipse.swt.events.ModifyListener;\r
29 import org.eclipse.swt.events.VerifyEvent;\r
30 import org.eclipse.swt.widgets.Composite;\r
31 import org.eclipse.swt.widgets.Listener;\r
32 import org.simantics.browsing.ui.swt.widgets.impl.Widget;\r
33 import org.simantics.browsing.ui.swt.widgets.impl.WidgetSupport;\r
34 import org.simantics.db.ReadGraph;\r
35 import org.simantics.db.Resource;\r
36 import org.simantics.db.WriteGraph;\r
37 import org.simantics.db.common.request.WriteRequest;\r
38 import org.simantics.db.common.utils.ListUtils;\r
39 import org.simantics.db.exception.DatabaseException;\r
40 import org.simantics.db.layer0.util.RemoverUtil;\r
41 import org.simantics.db.management.ISessionContext;\r
42 import org.simantics.db.request.Read;\r
43 import org.simantics.layer0.Layer0;\r
44 import org.simantics.layer0.utils.direct.GraphUtils;\r
45 import org.simantics.sysdyn.SysdynResource;\r
46 import org.simantics.sysdyn.modelParser.ModelParser;\r
47 import org.simantics.sysdyn.modelParser.ModelParser.Parameter;\r
48 import org.simantics.sysdyn.modelParser.ParseException;\r
49 import org.simantics.sysdyn.modelParser.Token;\r
50 import org.simantics.sysdyn.modelParser.TokenMgrError;\r
51 import org.simantics.sysdyn.ui.properties.widgets.expressions.ExpressionField;\r
52 import org.simantics.sysdyn.ui.utils.SyntaxError;\r
53 import org.simantics.ui.SimanticsUI;\r
54 import org.simantics.ui.utils.AdaptionUtils;\r
55 \r
56 public class FunctionCodeWidget implements Widget {\r
57         \r
58         private ExpressionField modelicaCode;\r
59         private Resource function;\r
60         \r
61     private Timer updateChartTimer;\r
62     private static int VALIDATION_DELAY_TIME = 500;\r
63         \r
64     private ArrayList<Parameter> inputs;\r
65     private ArrayList<Parameter> outputs;\r
66     \r
67         public FunctionCodeWidget(Composite parent, WidgetSupport support, int style) {\r
68                 support.register(this);\r
69         modelicaCode = new ExpressionField(parent, SWT.BORDER, null, false, null);\r
70         GridDataFactory.fillDefaults().grab(true, true).applyTo(modelicaCode);\r
71         \r
72 \r
73         // Support shift+enter for line change\r
74         modelicaCode.getSourceViewer().getTextWidget().addVerifyKeyListener(new VerifyKeyListener() {\r
75 \r
76                 @Override\r
77                 public void verifyKey(VerifyEvent event) {\r
78                         if(event.keyCode == SWT.CR || event.keyCode == SWT.KEYPAD_CR) {\r
79                                 if((event.stateMask & SWT.SHIFT) == 0) {\r
80                                         event.doit = false;\r
81                                         Listener[] listeners = modelicaCode.getSourceViewer().getTextWidget().getListeners(SWT.FocusOut);\r
82                                         for(Listener l : listeners) {\r
83                                                 modelicaCode.getSourceViewer().getTextWidget().removeListener(SWT.FocusOut, l);\r
84                                         }\r
85                                         ((StyledText)event.widget).getParent().forceFocus();\r
86                                         save();\r
87                                         for(Listener l : listeners) {\r
88                                                 modelicaCode.getSourceViewer().getTextWidget().addListener(SWT.FocusOut, l);\r
89                                         }\r
90                                 \r
91                                 }\r
92                         }\r
93                 }\r
94         });\r
95         \r
96         \r
97         modelicaCode.getSourceViewer().getTextWidget().addModifyListener(new ModifyListener() {\r
98 \r
99                         @Override\r
100                         public void modifyText(ModifyEvent e) {\r
101                                 validateFieldsTimed();\r
102                         }\r
103                 });\r
104         \r
105         modelicaCode.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() {\r
106                         @Override\r
107                         public void focusLost(FocusEvent e) {\r
108                                 save();\r
109                         }\r
110                 });\r
111                 \r
112         \r
113         updateChartTimer = new Timer(VALIDATION_DELAY_TIME, new ActionListener() {\r
114 \r
115             @Override\r
116             public void actionPerformed(ActionEvent e) {\r
117                 if(modelicaCode == null || modelicaCode.isDisposed())\r
118                         return;\r
119                 modelicaCode.getDisplay().asyncExec(new Runnable() {\r
120                                 \r
121                                 @Override\r
122                                 public void run() {\r
123                                         validate();\r
124                                 }\r
125                         });\r
126             }\r
127         });\r
128         updateChartTimer.setRepeats(false);\r
129         }\r
130 \r
131         @Override\r
132         public void setInput(ISessionContext context, Object input) {\r
133                 function = AdaptionUtils.adaptToSingle(input, Resource.class);\r
134                 \r
135                 try {\r
136                         String code = context.getSession().syncRequest(new Read<String>() {\r
137 \r
138                                 @Override\r
139                                 public String perform(ReadGraph graph) throws DatabaseException {\r
140                                         String code = graph.getPossibleRelatedValue(\r
141                                                         function, SysdynResource.getInstance(graph).SysdynModelicaFunction_modelicaFunctionCode);\r
142                                         if (code == null) {\r
143                                             code = graph.getPossibleRelatedValue(\r
144                                                     function, SysdynResource.getInstance(graph).SysdynModelicaFunction_modelicaFunctionInterface);\r
145                                             if (code == null) {\r
146                                 code = new String("");\r
147                             }\r
148                                         }\r
149                                         return code;\r
150                                 }\r
151                                 \r
152                         });\r
153                         if(code != null) {\r
154                                 modelicaCode.setExpression(code);\r
155                                 validate();\r
156                         }\r
157                 } catch (DatabaseException e) {\r
158                         e.printStackTrace();\r
159                 }\r
160         }\r
161         \r
162         \r
163     public void validateFieldsTimed() {         \r
164         validateFieldsTimed(VALIDATION_DELAY_TIME);\r
165     }\r
166     \r
167     public void validateFieldsTimed(int delay) {\r
168         updateChartTimer.setDelay(delay);\r
169         if(!updateChartTimer.isRunning())\r
170             updateChartTimer.start();\r
171         else\r
172             updateChartTimer.restart();\r
173     }\r
174     \r
175     public void validate() {\r
176         modelicaCode.resetAnnotations();\r
177         String code = modelicaCode.getExpression();\r
178         StringReader sr = new StringReader(code);\r
179         ModelParser modelParser = new ModelParser(sr);\r
180         \r
181         try {\r
182                         modelParser.parse_composition();\r
183                         \r
184                         inputs = modelParser.getInputs();\r
185                     outputs = modelParser.getOutputs();\r
186                         \r
187             /*for (Parameter input : inputs) {\r
188                 System.out.print("input " + input.type + " " + input.name);\r
189                 if (input.optional) System.out.print(" [optional]");\r
190                 if (input.description != null) System.out.print(" [Description: " + input.description + "]");\r
191                 System.out.println();\r
192             }\r
193             for (Parameter output : outputs) {    \r
194                 System.out.print("output " + output.type + " " + output.name);\r
195                 if (output.description != null) System.out.print(" [Description: " + output.description + "]");\r
196                 System.out.println();\r
197             }^*/\r
198 \r
199                 } catch (ParseException e1) {\r
200                         Token token = e1.currentToken;\r
201                         modelicaCode.setSyntaxError(new SyntaxError(token.image, "Syntax error", token.beginLine, token.beginColumn, token.endLine, token.endColumn));\r
202                 } catch (TokenMgrError err) {\r
203                         String message = err.getMessage();\r
204                         String line = message.substring(0, message.indexOf(","));\r
205                         line = line.substring(line.lastIndexOf(" ") + 1);\r
206                         String column = message.substring(message.indexOf(",") + 1, message.indexOf("."));\r
207                         column = column.substring(column.lastIndexOf(" ") + 1);\r
208                         try {\r
209                                 Integer endLine = Integer.parseInt(line);\r
210                                 Integer endColumn = Integer.parseInt(column);\r
211                                 Token token = modelParser.token;\r
212                                 modelicaCode.setSyntaxError(new SyntaxError(token.image, "Syntax error", token.endLine, token.endColumn, endLine, endColumn));\r
213                         } catch (NumberFormatException e) {\r
214                                 \r
215                         }\r
216                         \r
217                 }\r
218         }\r
219     \r
220     private void save() {\r
221         final String code = modelicaCode.getExpression();\r
222         SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
223          \r
224             private void removeInputList(WriteGraph graph) throws DatabaseException {\r
225                 SysdynResource sr = SysdynResource.getInstance(graph);\r
226                 \r
227                 Resource oldInputList = graph.getPossibleObject(function, sr.SysdynModelicaFunction_inputs);\r
228                 if (oldInputList != null) {\r
229                     // Find all the inputs \r
230                     for (Resource input : ListUtils.toList(graph, oldInputList)) {\r
231                         // Check if we have a variable length input\r
232                         if (graph.isInstanceOf(input, sr.SysdynModelicaFunction_VariableLengthInput)) {\r
233                             // The variable length inputs are found here\r
234                             Resource variableLengthInputLabels = graph.getPossibleObject(input, sr.SysdynModelicaFunction_VariableLengthInput_shownLabels);\r
235                             if (variableLengthInputLabels != null) {\r
236                                 // Find labels (strings)\r
237                                 for (Resource label : ListUtils.toList(graph, variableLengthInputLabels)) {\r
238                                     //Remove string\r
239                                     RemoverUtil.remove(graph, label);\r
240                                 }\r
241                                 // Remove list\r
242                                 RemoverUtil.remove(graph, variableLengthInputLabels);\r
243                             }\r
244                         }                       \r
245                         // Remove the input\r
246                         RemoverUtil.remove(graph, input);\r
247                     }\r
248                     // Remove the list\r
249                     RemoverUtil.remove(graph, oldInputList);\r
250                 }\r
251             }\r
252             \r
253             private void createInputList(WriteGraph graph) throws DatabaseException {\r
254                 Layer0 l0 = Layer0.getInstance(graph);\r
255                 SysdynResource sr = SysdynResource.getInstance(graph);\r
256                 \r
257                 ArrayList<Resource> inputResources = new ArrayList<Resource>();\r
258                 // Create inputs\r
259                 for (Parameter input : inputs) {\r
260                     Resource r = GraphUtils.create2(graph, sr.SysdynModelicaFunction_Input,\r
261                             l0.HasName, input.name, \r
262                             sr.Variable_type, input.type,\r
263                             sr.SysdynModelicaFunction_optional, input.optional ? l0.True : l0.False);\r
264                     if (input.description != null) {\r
265                         // Description is optional\r
266                         graph.claimLiteral(r, sr.SysdynModelicaFunction_definition, input.description);\r
267                     }\r
268                     inputResources.add(r);\r
269                 }\r
270                 graph.claim(\r
271                         function, \r
272                         sr.SysdynModelicaFunction_inputs, \r
273                         ListUtils.create(graph, inputResources));\r
274             }\r
275             \r
276             private void removeOutputList(WriteGraph graph) throws DatabaseException {\r
277                 SysdynResource sr = SysdynResource.getInstance(graph);\r
278 \r
279                 Resource oldOutputList = graph.getPossibleObject(function, sr.SysdynModelicaFunction_outputs);\r
280                 if (oldOutputList != null) {\r
281                     // Find all the outputs \r
282                     for (Resource output : ListUtils.toList(graph, oldOutputList)) {\r
283                         // Remove the output\r
284                         RemoverUtil.remove(graph, output);\r
285                     }\r
286                     // Remove the list\r
287                     RemoverUtil.remove(graph, oldOutputList);\r
288                 }\r
289             }\r
290                         \r
291             private void createOutputList(WriteGraph graph) throws DatabaseException {\r
292                 Layer0 l0 = Layer0.getInstance(graph);\r
293                 SysdynResource sr = SysdynResource.getInstance(graph);\r
294 \r
295                 ArrayList<Resource> outputResources = new ArrayList<Resource>();\r
296                 // Create outputs\r
297                 for (Parameter output : outputs) {\r
298                     Resource r = GraphUtils.create2(graph, sr.SysdynModelicaFunction_Output,\r
299                             l0.HasName, output.name, \r
300                             sr.Variable_type, output.type);\r
301                     if (output.description != null) {\r
302                         // Description is optional\r
303                         graph.claimLiteral(r, sr.SysdynModelicaFunction_definition, output.description);\r
304                     }\r
305                     outputResources.add(r);\r
306                 }\r
307                 graph.claim(\r
308                         function, \r
309                         sr.SysdynModelicaFunction_outputs, \r
310                         ListUtils.create(graph, outputResources));\r
311                 \r
312             }\r
313             \r
314                         @Override\r
315                         public void perform(WriteGraph graph) throws DatabaseException {\r
316                 SysdynResource sr = SysdynResource.getInstance(graph);\r
317 \r
318                     // Remove the existing input list\r
319                             removeInputList(graph);\r
320                         // Create the new input list\r
321                             createInputList(graph);\r
322                 \r
323                 // Remove the existing output list\r
324                             removeOutputList(graph);\r
325                 // Create the new output list\r
326                             createOutputList(graph);\r
327                             \r
328                 // Update the function code\r
329                                 graph.claimLiteral(\r
330                                                 function, \r
331                                                 sr.SysdynModelicaFunction_modelicaFunctionCode, \r
332                                                 code);\r
333                         }\r
334                 });\r
335     }\r
336 \r
337 }\r