]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
b5bc30ea0ce0ba6d6c3e99bc78c1cf3a861ab202
[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.util.ArrayList;\r
15 import java.util.Collections;\r
16 \r
17 import org.eclipse.jface.resource.ImageDescriptor;\r
18 import org.eclipse.jface.resource.JFaceResources;\r
19 import org.eclipse.jface.resource.LocalResourceManager;\r
20 import org.eclipse.jface.text.ITextViewer;\r
21 import org.eclipse.jface.text.contentassist.CompletionProposal;\r
22 import org.eclipse.jface.text.contentassist.ICompletionProposal;\r
23 import org.eclipse.jface.text.contentassist.IContentAssistProcessor;\r
24 import org.eclipse.jface.text.contentassist.IContextInformation;\r
25 import org.eclipse.jface.text.contentassist.IContextInformationValidator;\r
26 import org.eclipse.swt.graphics.Image;\r
27 import org.eclipse.swt.widgets.Control;\r
28 import org.eclipse.swt.widgets.Table;\r
29 import org.eclipse.swt.widgets.TableItem;\r
30 import org.simantics.db.ReadGraph;\r
31 import org.simantics.db.Resource;\r
32 import org.simantics.db.exception.DatabaseException;\r
33 import org.simantics.db.layer0.variable.Variables;\r
34 import org.simantics.db.request.Read;\r
35 import org.simantics.sysdyn.ui.Activator;\r
36 import org.simantics.sysdyn.ui.utils.ExpressionUtils;\r
37 import org.simantics.ui.SimanticsUI;\r
38 \r
39 \r
40 /**\r
41  * IContentAssistProcessor to determine which options (the functions and \r
42  * variables available) are shown for ContentAssistant; this assist of\r
43  * text field allows long variable names to be selected from a popup menu.\r
44  * @author Tuomas Miettinen\r
45  *\r
46  */\r
47 public class CompletionProcessor implements IContentAssistProcessor {\r
48         \r
49     private final Table allowedVariables;\r
50     private ArrayList<Function> functions;\r
51     private ArrayList<String> variables = null;\r
52     private ArrayList<String> timeAndSelfVariables = null;\r
53     private final ExpressionWidgetInput input;\r
54     \r
55     private LocalResourceManager resourceManager;\r
56     \r
57         private final char[] allowedCharacters = {\r
58                 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','å','ä','ö',\r
59                 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','Å','Ä','Ö',\r
60                 '1','2','3','4','5','6','7','8','9','0','.','(',')'};\r
61             \r
62         private final String allowedConnectedCharactersRegExp = "[\\Q({[:;,<=>+-*/^\\E]";\r
63         \r
64         public CompletionProcessor(Table allowedVariables, boolean allowFunctions, ExpressionWidgetInput input) {\r
65                 this.allowedVariables = allowedVariables;\r
66                 this.input = input;\r
67                 this.functions = new ArrayList<Function>();\r
68                 \r
69                 if (allowFunctions) {\r
70                     if (input != null && CompletionProcessor.this.input.variable != null) {\r
71                         // Get the respective model\r
72                         Resource model = null;\r
73                     try {\r
74                     model = SimanticsUI.getSession().syncRequest(new Read<Resource>() {\r
75 \r
76                         @Override\r
77                         public Resource perform(ReadGraph graph) throws DatabaseException {\r
78                             return Variables.getModel(graph, CompletionProcessor.this.input.variable);\r
79                         }\r
80                     });\r
81                     \r
82                     //User defined functions\r
83                     functions.addAll(Function.getUserDefinedFunctions(model));\r
84                     // Shared functions\r
85                     functions.addAll(Function.getSharedFunctions(model));\r
86                 } catch (DatabaseException e) {\r
87                     e.printStackTrace();\r
88                 }\r
89                     }\r
90  \r
91                     // Collect built in functions and sort all functions.\r
92                 functions.addAll(Function.getAllBuiltInFunctions());\r
93             Collections.sort(functions);\r
94        }\r
95         }\r
96     \r
97         /**\r
98          * Collect and sort all variables.\r
99          */\r
100         private void findVariables() {\r
101             if (variables == null) {\r
102             variables = new ArrayList<String>();\r
103             timeAndSelfVariables = new ArrayList<String>();\r
104             if(allowedVariables != null && !allowedVariables.isDisposed()) {\r
105                 TableItem[] connectedVariables = allowedVariables.getItems();\r
106                 for(TableItem ti : connectedVariables) {\r
107                     // The status of the variable is determined using the color of its table item :(\r
108                     if (ExpressionUtils.variableTimeAndSelfColor(resourceManager).equals(ti.getForeground())) {\r
109                         this.timeAndSelfVariables.add(ti.getText());\r
110                     } else {\r
111                         this.variables.add(ti.getText());\r
112                     }\r
113                     \r
114                 }\r
115             }\r
116             Collections.sort(variables);\r
117             Collections.sort(timeAndSelfVariables);\r
118         }\r
119         }\r
120         \r
121         /**\r
122          * Create CompletionProposals of the variables and add them to array.\r
123          * @param array result array of CompletionProposals\r
124          * @param token current token\r
125          * @param offset an offset within the document for which completions should be computed\r
126          */\r
127         private void addVariables(ArrayList<ICompletionProposal> array, String token, int offset) {\r
128             Image imageVariable = resourceManager.createImage(ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/variable.png")));\r
129         Image imageVariableGray = resourceManager.createImage(ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/variableGray.png")));\r
130         \r
131         for (String variable : variables) {\r
132             if (token.length() == 0 || variable.toUpperCase().startsWith(token.toUpperCase())) {\r
133                 array.add(new CompletionProposal(variable, \r
134                         offset - token.length(),\r
135                         token.length(), \r
136                         variable.length(), \r
137                         imageVariable, \r
138                         variable, \r
139                         null, \r
140                         null));\r
141             }   \r
142         }\r
143         for (String variable : timeAndSelfVariables) {\r
144             if (token.length() == 0 || variable.toUpperCase().startsWith(token.toUpperCase())) {\r
145                 array.add(new CompletionProposal(variable, \r
146                         offset - token.length(),\r
147                         token.length(), \r
148                         variable.length(), \r
149                         imageVariableGray, \r
150                         variable, \r
151                         null, \r
152                         null));\r
153             }   \r
154         }\r
155         }\r
156         \r
157         /**\r
158      * Create CompletionProposals of the functions and add them to array.\r
159      * @param array result array of CompletionProposals\r
160      * @param token current token\r
161      * @param offset an offset within the document for which completions should be computed\r
162      */\r
163         private void addFunctions(ArrayList<ICompletionProposal> array, String token, int offset) {\r
164             // Parameters don't have functions\r
165             if (functions == null)\r
166                 return;\r
167             \r
168             // Create CompletionProposals out of Functions\r
169         for (Function function : functions) {\r
170             if (token.length() == 0 || function.getName().toUpperCase().startsWith(token.toUpperCase())) {\r
171                 Image image = Function.getImage(resourceManager, function);\r
172                 array.add(new CompletionProposal(\r
173                         function.getName() + "(" + function.getParameterList() + ")", \r
174                         offset - token.length(),\r
175                         token.length(), \r
176                         function.getName().length() + 1,\r
177                         image, \r
178                         function.getName() + "(" + function.getParameterList() + ")", \r
179                         null, \r
180                         function.getDescriptionHTML()));\r
181             }   \r
182         }\r
183         }\r
184         \r
185         /**\r
186      * Collect all matching proposals\r
187      * @param token current token\r
188      * @param offset an offset within the document for which completions should be computed\r
189      * @return Array of matching proposals\r
190      */\r
191     private ICompletionProposal[] collectProposals(String token, int offset) {\r
192             ArrayList<ICompletionProposal> resultArray = new ArrayList<ICompletionProposal>();\r
193         \r
194             // Find variables and functions and create CompletionProposals out of them.\r
195             findVariables();\r
196             addVariables(resultArray, token, offset);\r
197             addFunctions(resultArray, token, offset);\r
198  \r
199             ICompletionProposal[] result = new ICompletionProposal[resultArray.size()];\r
200                 for (int i = 0; i < result.length; ++i) {\r
201                         result[i] = resultArray.get(i);\r
202                 }\r
203                 return result;\r
204         }\r
205         \r
206     @Override\r
207         public ICompletionProposal[] computeCompletionProposals(\r
208                         ITextViewer viewer, int offset) {\r
209                 String equation = viewer.getDocument().get();\r
210                 Control control = viewer.getTextWidget();\r
211                 this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), control);\r
212                 \r
213                 if (equation.length() == 0 \r
214                                 || offset == 0\r
215                                 || Character.isWhitespace(equation.charAt(offset - 1))) {\r
216                         return collectProposals("", offset);\r
217                 }\r
218                 \r
219                 equation = equation.substring(0, offset);\r
220                 \r
221                 // Split into tokens on whitespace characters\r
222                 String[] tokens = equation.split("[\\s]");\r
223                 if (tokens.length == 0) {\r
224                         return collectProposals("", offset);\r
225                 }\r
226                 String token = tokens[tokens.length - 1];\r
227                 \r
228                 // If a '+', '-', etc. character is in the end, return all. \r
229             if (allowedConnectedCharactersRegExp.indexOf(token.charAt(token.length() - 1)) != -1) {\r
230                 return collectProposals("", offset);\r
231             }\r
232             \r
233             // Split the last token on '+', '-', etc. characters\r
234         String tokensOfLastToken[] = token.split(allowedConnectedCharactersRegExp);\r
235                 if (tokensOfLastToken.length == 0) {\r
236                         return collectProposals("", offset);\r
237                 }\r
238                 token = tokensOfLastToken[tokensOfLastToken.length - 1];\r
239                 //System.out.println(token + "\noffset = " + offset);\r
240 \r
241                 return collectProposals(token, offset);\r
242         }\r
243 \r
244         @Override\r
245         public IContextInformation[] computeContextInformation(\r
246                         ITextViewer viewer, int offset) {\r
247                 return null;\r
248         }\r
249 \r
250         @Override\r
251         public char[] getCompletionProposalAutoActivationCharacters() {\r
252                 return allowedCharacters;\r
253         }\r
254 \r
255         @Override\r
256         public char[] getContextInformationAutoActivationCharacters() {\r
257                 return null;\r
258         }\r
259 \r
260         @Override\r
261         public String getErrorMessage() {\r
262                 return "Error in CompletionProcessor";\r
263         }\r
264 \r
265         @Override\r
266         public IContextInformationValidator getContextInformationValidator() {\r
267                 return null;\r
268         }\r
269 \r
270 }\r