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