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