]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
b41e42d2f9b5e1cb2e5c3ecdc5f1d7e1d3d6ffc7
[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                 } catch (ParseException e1) {\r
188                         Token token = e1.currentToken;\r
189                         modelicaCode.setSyntaxError(new SyntaxError(token.image, "Syntax error", token.beginLine, token.beginColumn, token.endLine, token.endColumn));\r
190                 } catch (TokenMgrError err) {\r
191                         String message = err.getMessage();\r
192                         String line = message.substring(0, message.indexOf(","));\r
193                         line = line.substring(line.lastIndexOf(" ") + 1);\r
194                         String column = message.substring(message.indexOf(",") + 1, message.indexOf("."));\r
195                         column = column.substring(column.lastIndexOf(" ") + 1);\r
196                         try {\r
197                                 Integer endLine = Integer.parseInt(line);\r
198                                 Integer endColumn = Integer.parseInt(column);\r
199                                 Token token = modelParser.token;\r
200                                 modelicaCode.setSyntaxError(new SyntaxError(token.image, "Syntax error", token.endLine, token.endColumn, endLine, endColumn));\r
201                         } catch (NumberFormatException e) {\r
202                                 \r
203                         }\r
204                         \r
205                 }\r
206         }\r
207     \r
208     private void save() {\r
209         final String code = modelicaCode.getExpression();\r
210         \r
211         // Update input and output lists.\r
212         validate();\r
213         \r
214         SimanticsUI.getSession().asyncRequest(new WriteRequest() {\r
215             \r
216             @Override\r
217             public void perform(WriteGraph graph) throws DatabaseException {\r
218                 SysdynResource sr = SysdynResource.getInstance(graph);\r
219 \r
220                 // Remove the existing input list\r
221                 removeInputList(graph);\r
222                 // Create the new input list\r
223                 createInputList(graph);\r
224 \r
225                 // Remove the existing output list\r
226                 removeOutputList(graph);\r
227                 // Create the new output list\r
228                 createOutputList(graph);\r
229                 \r
230                 // Update the function code\r
231                 graph.claimLiteral(\r
232                         function, \r
233                         sr.SysdynModelicaFunction_modelicaFunctionCode, \r
234                         code);\r
235             }\r
236             \r
237             private void removeInputList(WriteGraph graph) throws DatabaseException {\r
238                 SysdynResource sr = SysdynResource.getInstance(graph);\r
239                 \r
240                 Resource oldInputList = graph.getPossibleObject(function, sr.SysdynModelicaFunction_inputs);\r
241                 if (oldInputList != null) {\r
242                     // Find all the inputs \r
243                     for (Resource input : ListUtils.toList(graph, oldInputList)) {\r
244                         // Check if we have a variable length input\r
245                         if (graph.isInstanceOf(input, sr.SysdynModelicaFunction_VariableLengthInput)) {\r
246                             // The variable length inputs are found here\r
247                             Resource variableLengthInputLabels = graph.getPossibleObject(input, sr.SysdynModelicaFunction_VariableLengthInput_shownLabels);\r
248                             if (variableLengthInputLabels != null) {\r
249                                 // Find labels (strings)\r
250                                 for (Resource label : ListUtils.toList(graph, variableLengthInputLabels)) {\r
251                                     //Remove string\r
252                                     RemoverUtil.remove(graph, label);\r
253                                 }\r
254                                 // Remove list\r
255                                 RemoverUtil.remove(graph, variableLengthInputLabels);\r
256                             }\r
257                         }                       \r
258                         // Remove the input\r
259                         RemoverUtil.remove(graph, input);\r
260                     }\r
261                     // Remove the list\r
262                     RemoverUtil.remove(graph, oldInputList);\r
263                 }\r
264             }\r
265             \r
266             private void createInputList(WriteGraph graph) throws DatabaseException {\r
267                 Layer0 l0 = Layer0.getInstance(graph);\r
268                 SysdynResource sr = SysdynResource.getInstance(graph);\r
269                 \r
270                 ArrayList<Resource> inputResources = new ArrayList<Resource>();\r
271                 // Create inputs\r
272                 if (inputs != null) {\r
273                     for (Parameter input : inputs) {\r
274                         Resource r = GraphUtils.create2(graph, sr.SysdynModelicaFunction_Input,\r
275                                 l0.HasName, input.name, \r
276                                 sr.Variable_type, input.type,\r
277                                 sr.SysdynModelicaFunction_optional, input.optional ? l0.True : l0.False);\r
278                         if (input.description != null) {\r
279                             // Description is optional\r
280                             graph.claimLiteral(r, sr.SysdynModelicaFunction_definition, input.description);\r
281                         }\r
282                         inputResources.add(r);\r
283                     }\r
284                     graph.claim(\r
285                             function, \r
286                             sr.SysdynModelicaFunction_inputs, \r
287                             ListUtils.create(graph, inputResources));\r
288                 }\r
289             }\r
290             \r
291             private void removeOutputList(WriteGraph graph) throws DatabaseException {\r
292                 SysdynResource sr = SysdynResource.getInstance(graph);\r
293 \r
294                 Resource oldOutputList = graph.getPossibleObject(function, sr.SysdynModelicaFunction_outputs);\r
295                 if (oldOutputList != null) {\r
296                     // Find all the outputs \r
297                     for (Resource output : ListUtils.toList(graph, oldOutputList)) {\r
298                         // Remove the output\r
299                         RemoverUtil.remove(graph, output);\r
300                     }\r
301                     // Remove the list\r
302                     RemoverUtil.remove(graph, oldOutputList);\r
303                 }\r
304             }\r
305                         \r
306             private void createOutputList(WriteGraph graph) throws DatabaseException {\r
307                 Layer0 l0 = Layer0.getInstance(graph);\r
308                 SysdynResource sr = SysdynResource.getInstance(graph);\r
309 \r
310                 ArrayList<Resource> outputResources = new ArrayList<Resource>();\r
311                 // Create outputs\r
312                 if (outputs != null) {\r
313                     for (Parameter output : outputs) {\r
314                         Resource r = GraphUtils.create2(graph, sr.SysdynModelicaFunction_Output,\r
315                                 l0.HasName, output.name, \r
316                                 sr.Variable_type, output.type);\r
317                         if (output.description != null) {\r
318                             // Description is optional\r
319                             graph.claimLiteral(r, sr.SysdynModelicaFunction_definition, output.description);\r
320                         }\r
321                         outputResources.add(r);\r
322                     }\r
323                     graph.claim(\r
324                             function, \r
325                             sr.SysdynModelicaFunction_outputs, \r
326                             ListUtils.create(graph, outputResources));\r
327                 }\r
328                 \r
329             }\r
330 \r
331                 });\r
332     }\r
333 \r
334 }\r