/*******************************************************************************\r
- * Copyright (c) 2010 Association for Decentralized Information Management in\r
+ * Copyright (c) 2010, 2014 Association for Decentralized Information Management in\r
* Industry THTH ry.\r
* All rights reserved. This program and the accompanying materials\r
* are made available under the terms of the Eclipse Public License v1.0\r
\r
import java.util.ArrayList;\r
import java.util.Collections;\r
+import java.util.Comparator;\r
\r
import org.eclipse.jface.resource.ImageDescriptor;\r
import org.eclipse.jface.resource.JFaceResources;\r
\r
private LocalResourceManager resourceManager;\r
\r
- private final char[] allowedCharacters = {\r
+ private static final char[] ALLOWED_CHARACTERS = {\r
'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
'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
'1','2','3','4','5','6','7','8','9','0','.','(',')'};\r
\r
- private final String allowedConnectedCharactersRegExp = "[\\Q({[:;,<=>+-*/^\\E]";\r
+ private static final String ALLOWED_CONNECTED_CHARACTERS_REG_EXP = "[\\Q({[:;,<=>+-*/^\\E]";\r
+ \r
+ private static final ArrayList<String> ALLOW_ALL_COMPLETIONS_LIST = new ArrayList<String>();\r
+ static {\r
+ ALLOW_ALL_COMPLETIONS_LIST.add("");\r
+ }\r
\r
public CompletionProcessor(Table allowedVariables, boolean allowFunctions, ExpressionWidgetInput input) {\r
this.allowedVariables = allowedVariables;\r
}\r
\r
/**\r
- * Create CompletionProposals of the variables and add them to array.\r
+ * Create CompletionProposals of the variables and add them to array. Do not allow duplicates.\r
* @param array result array of CompletionProposals\r
* @param token current token\r
* @param offset an offset within the document for which completions should be computed\r
Image imageVariableGray = resourceManager.createImage(ImageDescriptor.createFromURL(Activator.getDefault().getBundle().getResource("icons/variableGray.png")));\r
\r
for (String variable : variables) {\r
- if (token.length() == 0 || variable.toUpperCase().startsWith(token.toUpperCase())) {\r
- array.add(new CompletionProposal(variable, \r
+ if ((token.length() == 0 || variable.toUpperCase().startsWith(token.toUpperCase()))\r
+ && !listContainsVariable(array, variable)) {\r
+ array.add(new CompletionProposal(variable, \r
offset - token.length(),\r
token.length(), \r
variable.length(), \r
} \r
}\r
for (String variable : timeAndSelfVariables) {\r
- if (token.length() == 0 || variable.toUpperCase().startsWith(token.toUpperCase())) {\r
+ if ((token.length() == 0 || variable.toUpperCase().startsWith(token.toUpperCase()))\r
+ && !listContainsVariable(array, variable)) {\r
array.add(new CompletionProposal(variable, \r
offset - token.length(),\r
token.length(), \r
}\r
}\r
\r
+ private boolean listContainsVariable(ArrayList<ICompletionProposal> array,\r
+ String variable) {\r
+ for (ICompletionProposal proposal : array) {\r
+ if (proposal.getDisplayString().equals(variable))\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
/**\r
* Create CompletionProposals of the functions and add them to array.\r
* @param array result array of CompletionProposals\r
}\r
\r
/**\r
- * Collect all matching proposals\r
- * @param token current token\r
+ * Collect all matching proposals. Duplicates are removed; the one with the longest token stays.\r
+ * @param possibleLabelBeginnings sets of whitespace delimited tokens (as Strings)\r
* @param offset an offset within the document for which completions should be computed\r
* @return Array of matching proposals\r
*/\r
- private ICompletionProposal[] collectProposals(String token, int offset) {\r
+ private ICompletionProposal[] collectProposals(ArrayList<String> possibleLabelBeginnings, int offset) {\r
ArrayList<ICompletionProposal> resultArray = new ArrayList<ICompletionProposal>();\r
\r
// Find variables and functions and create CompletionProposals out of them.\r
findVariables();\r
- addVariables(resultArray, token, offset);\r
- addFunctions(resultArray, token, offset);\r
+ \r
+ // Sort the list based on the length of the tokens (descending) to get "" to end.\r
+ Collections.sort(possibleLabelBeginnings, new Comparator<String>(){\r
+ @Override\r
+ public int compare(String o1, String o2) {\r
+ if (o1.length() > o2.length()) {\r
+ return -1;\r
+ } else if (o1.length() < o2.length()) {\r
+ return 1;\r
+ }\r
+ return 0;\r
+ }\r
+ });\r
+ \r
+ for (String possibleLabelBeginning : possibleLabelBeginnings) {\r
+ addVariables(resultArray, possibleLabelBeginning, offset);\r
+ }\r
\r
- ICompletionProposal[] result = new ICompletionProposal[resultArray.size()];\r
+ // No support for whitespace in function names; get shortest beginning\r
+ addFunctions(resultArray, possibleLabelBeginnings.get(possibleLabelBeginnings.size() - 1), offset);\r
+\r
+ ICompletionProposal[] result = new ICompletionProposal[resultArray.size()];\r
for (int i = 0; i < result.length; ++i) {\r
result[i] = resultArray.get(i);\r
}\r
Control control = viewer.getTextWidget();\r
this.resourceManager = new LocalResourceManager(JFaceResources.getResources(), control);\r
\r
- if (equation.length() == 0 \r
- || offset == 0\r
- || Character.isWhitespace(equation.charAt(offset - 1))) {\r
- return collectProposals("", offset);\r
+ if (equation.length() == 0 || offset == 0) {\r
+ return collectProposals(ALLOW_ALL_COMPLETIONS_LIST, offset);\r
}\r
\r
equation = equation.substring(0, offset);\r
\r
- // Split into tokens on whitespace characters\r
- String[] tokens = equation.split("[\\s]");\r
- if (tokens.length == 0) {\r
- return collectProposals("", offset);\r
+ // Split the equation on '+', '-', etc. characters\r
+ String stringsBetweenConnectedCharacters[] = equation.split(ALLOWED_CONNECTED_CHARACTERS_REG_EXP);\r
+ if (stringsBetweenConnectedCharacters.length == 0) {\r
+ return collectProposals(ALLOW_ALL_COMPLETIONS_LIST, offset);\r
}\r
- String token = tokens[tokens.length - 1];\r
+ String stringAfterLastConnectedCharacter = stringsBetweenConnectedCharacters[stringsBetweenConnectedCharacters.length - 1];\r
+ String stringAfterWhitespaceAfterLastConnectedCharacter = removeLeadingWhitespace(stringAfterLastConnectedCharacter);\r
+ \r
+ // Split into tokens on whitespace characters, include also the trailing empty strings\r
+ String[] tokens = stringAfterWhitespaceAfterLastConnectedCharacter.split("[\\s]", -42);\r
\r
- // If a '+', '-', etc. character is in the end, return all. \r
- if (allowedConnectedCharactersRegExp.indexOf(token.charAt(token.length() - 1)) != -1) {\r
- return collectProposals("", offset);\r
- }\r
- \r
- // Split the last token on '+', '-', etc. characters\r
- String tokensOfLastToken[] = token.split(allowedConnectedCharactersRegExp);\r
- if (tokensOfLastToken.length == 0) {\r
- return collectProposals("", offset);\r
+ // Only whitespace after the last connection character\r
+ if (allTokensAreEmpty(tokens))\r
+ return collectProposals(ALLOW_ALL_COMPLETIONS_LIST, offset);\r
+ \r
+ return collectProposals(getPossibleLabelBeginnings(tokens), offset);\r
+ }\r
+\r
+ /**\r
+ * Collect all possible strings (with each whitespace replaced by a space character)\r
+ * which may be a beginning of a variable. \r
+ * Create the beginnings by adding whitespace between. E.g.:\r
+ * {"multi", "part", "variab"}\r
+ * -> { "multi part variab",\r
+ * "part variab",\r
+ * "variab" }\r
+ * @param tokens list of tokens\r
+ * @return all possible label beginnings\r
+ */\r
+ private ArrayList<String> getPossibleLabelBeginnings(String[] tokens) {\r
+ ArrayList<String> possibleLabelBeginnings = new ArrayList<String>();\r
+ for (int i = 0; i < tokens.length; ++i) {\r
+ String token = new String();\r
+ for (int j = i; j < tokens.length; ++j) {\r
+ token += " " + tokens[j];\r
+ }\r
+ // Remove the excess space character from the beginning\r
+ token = token.substring(1);\r
+ \r
+ possibleLabelBeginnings.add(token);\r
}\r
- token = tokensOfLastToken[tokensOfLastToken.length - 1];\r
- //System.out.println(token + "\noffset = " + offset);\r
+ return possibleLabelBeginnings;\r
+ }\r
+\r
+ /**\r
+ * Remove leading whitespace\r
+ * @param input\r
+ * @return\r
+ */\r
+ private String removeLeadingWhitespace(String input) {\r
+ for (int i = 0; i < input.length(); ++i) {\r
+ if (!Character.isWhitespace(input.charAt(i))) {\r
+ return input.substring(i);\r
+ }\r
+ }\r
+ return "";\r
+ }\r
\r
- return collectProposals(token, offset);\r
+ private boolean allTokensAreEmpty(String[] tokens) {\r
+ for (String token : tokens)\r
+ if (!token.equals(""))\r
+ return false;\r
+ return true;\r
}\r
\r
@Override\r
\r
@Override\r
public char[] getCompletionProposalAutoActivationCharacters() {\r
- return allowedCharacters;\r
+ return ALLOWED_CHARACTERS;\r
}\r
\r
@Override\r