-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in 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
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.browsing.ui.common.views;\r
-\r
-import java.nio.CharBuffer;\r
-import java.util.regex.Matcher;\r
-import java.util.regex.Pattern;\r
-\r
-/**\r
- * Default implementation of IFilterStrategy.\r
- * \r
- * <p>\r
- * It implements simple search semantics with only the special wildcard\r
- * characters '*' ( 0 to n any characters) and '?' (any one character)\r
- * recognized. In order to allow the filter to pass arbitrary prefixes, the\r
- * client has to give a '*' prefix in the filter string. On the contrary, the\r
- * client does not have to specify a '*' in order to pass arbitrary suffixes -\r
- * arbitrary suffixes are allowed by default by this strategy.\r
- * \r
- * <p>\r
- * This strategy forces the filter string to lowercase.\r
- * \r
- * TODO: implement case-insensitiveness properly, not by forcing the search string into lower case. Also Fix FilterSelectionRequestQueryProcessor after doing this.\r
- * \r
- * @author Tuukka Lehtonen\r
- */\r
-public class DefaultFilterStrategy implements IFilterStrategy {\r
-\r
- private static final boolean DEBUG = false;\r
-\r
- boolean implicitPreAsterisk = true;\r
-\r
- public DefaultFilterStrategy() {\r
- this(true);\r
- }\r
-\r
- public DefaultFilterStrategy(boolean implicitPreAsterisk) {\r
- this.implicitPreAsterisk = implicitPreAsterisk;\r
- }\r
-\r
- private static StringBuilder addSearchWord(StringBuilder sb, String pattern) {\r
- if (DEBUG)\r
- System.out.println("addSearchWord(" + pattern + ") to '" + sb.toString() + "'");\r
-\r
- if (pattern == null || pattern.isEmpty())\r
- return sb;\r
- if (sb.length() > 0)\r
- sb.append('|');\r
- sb.append('(');\r
- sb.append(pattern);\r
- sb.append(')');\r
- return sb;\r
- }\r
-\r
- private static String toString(CharBuffer cb) {\r
- cb.limit(cb.position());\r
- cb.reset();\r
- if (DEBUG)\r
- System.out.println("toString(" + cb + ")");\r
- String result = cb.toString();\r
- cb.limit(cb.capacity());\r
- return result;\r
- }\r
-\r
- public static String toSinglePatternString(String filter, boolean implicitPreAsterisk) {\r
- if (!filter.isEmpty()) {\r
- // Force searching in lowercase.\r
- filter = filter.toLowerCase();\r
-\r
- // Construct a regular expression from the specified text.\r
- String regExFilter = filter\r
- .replace("\\", "\\\\") // \ -> \\\r
- .replace(".", "\\.") // . -> \.\r
- .replace("*", ".*") // * -> Any 0..n characters\r
- .replace("?", ".") // ? -> Any single character\r
- .replace("+", "\\+") // + -> \+\r
- .replace("(", "\\(") // ( -> \(\r
- .replace(")", "\\)") // ) -> \)\r
- .replace("[", "\\[") // [ -> \[\r
- .replace("]", "\\]") // ] -> \]\r
- .replace("{", "\\{") // { -> \{\r
- .replace("}", "\\}") // } -> \}\r
- .replace("^", "\\^") // ^ -> \^\r
- .replace("$", "\\$") // $ -> \$\r
- .replace("|", ".*|") // $ -> \$\r
- //.replace("|", "\\|") // | -> \|\r
- .replace("&&", "\\&&") // && -> \&&\r
- ;\r
-\r
- if (implicitPreAsterisk)\r
- if (!regExFilter.startsWith(".*"))\r
- regExFilter = ".*" + regExFilter ;\r
- if (!regExFilter.endsWith(".*"))\r
- regExFilter += ".*" ;\r
-\r
- return regExFilter;\r
- }\r
- return null;\r
- }\r
-\r
- public static String defaultToPatternString(String filter, boolean implicitPreAsterisk) {\r
- if (filter.isEmpty())\r
- return null;\r
-\r
- CharBuffer buf = CharBuffer.allocate(filter.length()*2);\r
- buf.mark();\r
- StringBuilder sb = new StringBuilder(filter.length()*2);\r
- boolean inQuote = false;\r
- int len = filter.length();\r
- for (int i = 0; i < len;) {\r
- char ch = filter.charAt(i);\r
- if (DEBUG)\r
- System.out.println("char[" + i + "]: '" + ch + "'");\r
-\r
- if (ch == '"') {\r
- if (!inQuote) {\r
- if (DEBUG)\r
- System.out.println("begin quoted text");\r
- inQuote = true;\r
- } else {\r
- if (DEBUG)\r
- System.out.println("end quoted text");\r
- inQuote = false;\r
- addSearchWord(sb, toSinglePatternString( toString(buf), implicitPreAsterisk ));\r
- }\r
- ++i;\r
- continue;\r
- } else if (ch == '\\') {\r
- // Next character is escaped, i.e. taken as is.\r
- ++i;\r
- if (i >= len)\r
- // Unexpected end-of-string\r
- break;\r
-\r
- ch = filter.charAt(i);\r
- if (DEBUG)\r
- System.out.println("append escaped character '" + ch + "'");\r
-\r
- buf.append(ch);\r
- ++i;\r
- break;\r
- } else if (ch == ' ') {\r
- if (inQuote) {\r
- if (DEBUG)\r
- System.out.println("append char '" + ch + "'");\r
- buf.append(ch);\r
- ++i;\r
- } else {\r
- if (buf.position() > 0) {\r
- addSearchWord(sb, toSinglePatternString( toString(buf), implicitPreAsterisk ));\r
- }\r
- ++i;\r
- }\r
- } else {\r
- if (DEBUG)\r
- System.out.println("append char '" + ch + "'");\r
- buf.append(ch);\r
- ++i;\r
- }\r
- }\r
- if (buf.position() > 0) {\r
- addSearchWord(sb, toSinglePatternString( toString(buf), implicitPreAsterisk ));\r
- }\r
-\r
- //sb.append(".*");\r
-\r
- return sb.toString();\r
- }\r
-\r
- @Override\r
- public String toPatternString(String filter) {\r
- return defaultToPatternString(filter, implicitPreAsterisk);\r
- }\r
-\r
- public static Pattern compilePattern(String s) {\r
- IFilterStrategy st = new DefaultFilterStrategy(true);\r
- System.out.println("compilePattern(" + s + ")");\r
- String regex = st.toPatternString(s);\r
- System.out.println(s + " -> " + regex);\r
- Pattern p = Pattern.compile(regex);\r
- return p;\r
- }\r
-\r
- public static void test(String pattern, String... testStrings) {\r
- Pattern p = compilePattern(pattern);\r
- for (String test : testStrings) {\r
- System.out.print("\ttesting '" + test + "'");\r
- Matcher m = p.matcher(test);\r
- if (m.matches()) {\r
- System.out.println(" - MATCHES");\r
- } else {\r
- System.out.println(" - NO MATCH");\r
- }\r
- }\r
- }\r
-\r
- static String[] TEST = {\r
- "foo bar baz biz boz",\r
- "biz bar baz foo boz",\r
- "foo",\r
- "bar",\r
- " foo bar ",\r
- "quux",\r
- " quux ",\r
- " quux foo",\r
- };\r
-\r
- public static void main(String[] args) {\r
- test("foo$");\r
- test(".");\r
- test("*");\r
- test("?");\r
- test("+");\r
- test("^");\r
- test("&");\r
- test("&&");\r
- test("&&&");\r
- test("|");\r
- test("(");\r
- test(")");\r
- test("[");\r
- test("]");\r
- test("{");\r
- test("}");\r
- test("()");\r
- test("[]");\r
- test("{}");\r
- test("\\\\");\r
- test("\\");\r
-\r
- test("foo bar", TEST);\r
- test("\"foo bar\"", TEST);\r
- test("\"foo bar\" quux", TEST);\r
- test("*\"foo bar\" *quux", TEST);\r
- test("\"*foo bar\" *quux", TEST);\r
- }\r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.browsing.ui.common.views;
+
+import java.nio.CharBuffer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Default implementation of IFilterStrategy.
+ *
+ * <p>
+ * It implements simple search semantics with only the special wildcard
+ * characters '*' ( 0 to n any characters) and '?' (any one character)
+ * recognized. In order to allow the filter to pass arbitrary prefixes, the
+ * client has to give a '*' prefix in the filter string. On the contrary, the
+ * client does not have to specify a '*' in order to pass arbitrary suffixes -
+ * arbitrary suffixes are allowed by default by this strategy.
+ *
+ * <p>
+ * This strategy forces the filter string to lowercase.
+ *
+ * TODO: implement case-insensitiveness properly, not by forcing the search string into lower case. Also Fix FilterSelectionRequestQueryProcessor after doing this.
+ *
+ * @author Tuukka Lehtonen
+ */
+public class DefaultFilterStrategy implements IFilterStrategy {
+
+ private static final boolean DEBUG = false;
+
+ boolean implicitPreAsterisk = true;
+
+ public DefaultFilterStrategy() {
+ this(true);
+ }
+
+ public DefaultFilterStrategy(boolean implicitPreAsterisk) {
+ this.implicitPreAsterisk = implicitPreAsterisk;
+ }
+
+ private static StringBuilder addSearchWord(StringBuilder sb, String pattern) {
+ if (DEBUG)
+ System.out.println("addSearchWord(" + pattern + ") to '" + sb.toString() + "'");
+
+ if (pattern == null || pattern.isEmpty())
+ return sb;
+ if (sb.length() > 0)
+ sb.append('|');
+ sb.append('(');
+ sb.append(pattern);
+ sb.append(')');
+ return sb;
+ }
+
+ private static String toString(CharBuffer cb) {
+ cb.limit(cb.position());
+ cb.reset();
+ if (DEBUG)
+ System.out.println("toString(" + cb + ")");
+ String result = cb.toString();
+ cb.limit(cb.capacity());
+ return result;
+ }
+
+ public static String toSinglePatternString(String filter, boolean implicitPreAsterisk) {
+ if (!filter.isEmpty()) {
+ // Force searching in lowercase.
+ filter = filter.toLowerCase();
+
+ // Construct a regular expression from the specified text.
+ String regExFilter = filter
+ .replace("\\", "\\\\") // \ -> \\
+ .replace(".", "\\.") // . -> \.
+ .replace("*", ".*") // * -> Any 0..n characters
+ .replace("?", ".") // ? -> Any single character
+ .replace("+", "\\+") // + -> \+
+ .replace("(", "\\(") // ( -> \(
+ .replace(")", "\\)") // ) -> \)
+ .replace("[", "\\[") // [ -> \[
+ .replace("]", "\\]") // ] -> \]
+ .replace("{", "\\{") // { -> \{
+ .replace("}", "\\}") // } -> \}
+ .replace("^", "\\^") // ^ -> \^
+ .replace("$", "\\$") // $ -> \$
+ .replace("|", ".*|") // $ -> \$
+ //.replace("|", "\\|") // | -> \|
+ .replace("&&", "\\&&") // && -> \&&
+ ;
+
+ if (implicitPreAsterisk)
+ if (!regExFilter.startsWith(".*"))
+ regExFilter = ".*" + regExFilter ;
+ if (!regExFilter.endsWith(".*"))
+ regExFilter += ".*" ;
+
+ return regExFilter;
+ }
+ return null;
+ }
+
+ public static String defaultToPatternString(String filter, boolean implicitPreAsterisk) {
+ if (filter.isEmpty())
+ return null;
+
+ CharBuffer buf = CharBuffer.allocate(filter.length()*2);
+ buf.mark();
+ StringBuilder sb = new StringBuilder(filter.length()*2);
+ boolean inQuote = false;
+ int len = filter.length();
+ for (int i = 0; i < len;) {
+ char ch = filter.charAt(i);
+ if (DEBUG)
+ System.out.println("char[" + i + "]: '" + ch + "'");
+
+ if (ch == '"') {
+ if (!inQuote) {
+ if (DEBUG)
+ System.out.println("begin quoted text");
+ inQuote = true;
+ } else {
+ if (DEBUG)
+ System.out.println("end quoted text");
+ inQuote = false;
+ addSearchWord(sb, toSinglePatternString( toString(buf), implicitPreAsterisk ));
+ }
+ ++i;
+ continue;
+ } else if (ch == '\\') {
+ // Next character is escaped, i.e. taken as is.
+ ++i;
+ if (i >= len)
+ // Unexpected end-of-string
+ break;
+
+ ch = filter.charAt(i);
+ if (DEBUG)
+ System.out.println("append escaped character '" + ch + "'");
+
+ buf.append(ch);
+ ++i;
+ break;
+ } else if (ch == ' ') {
+ if (inQuote) {
+ if (DEBUG)
+ System.out.println("append char '" + ch + "'");
+ buf.append(ch);
+ ++i;
+ } else {
+ if (buf.position() > 0) {
+ addSearchWord(sb, toSinglePatternString( toString(buf), implicitPreAsterisk ));
+ }
+ ++i;
+ }
+ } else {
+ if (DEBUG)
+ System.out.println("append char '" + ch + "'");
+ buf.append(ch);
+ ++i;
+ }
+ }
+ if (buf.position() > 0) {
+ addSearchWord(sb, toSinglePatternString( toString(buf), implicitPreAsterisk ));
+ }
+
+ //sb.append(".*");
+
+ return sb.toString();
+ }
+
+ @Override
+ public String toPatternString(String filter) {
+ return defaultToPatternString(filter, implicitPreAsterisk);
+ }
+
+ public static Pattern compilePattern(String s) {
+ IFilterStrategy st = new DefaultFilterStrategy(true);
+ System.out.println("compilePattern(" + s + ")");
+ String regex = st.toPatternString(s);
+ System.out.println(s + " -> " + regex);
+ Pattern p = Pattern.compile(regex);
+ return p;
+ }
+
+ public static void test(String pattern, String... testStrings) {
+ Pattern p = compilePattern(pattern);
+ for (String test : testStrings) {
+ System.out.print("\ttesting '" + test + "'");
+ Matcher m = p.matcher(test);
+ if (m.matches()) {
+ System.out.println(" - MATCHES");
+ } else {
+ System.out.println(" - NO MATCH");
+ }
+ }
+ }
+
+ static String[] TEST = {
+ "foo bar baz biz boz",
+ "biz bar baz foo boz",
+ "foo",
+ "bar",
+ " foo bar ",
+ "quux",
+ " quux ",
+ " quux foo",
+ };
+
+ public static void main(String[] args) {
+ test("foo$");
+ test(".");
+ test("*");
+ test("?");
+ test("+");
+ test("^");
+ test("&");
+ test("&&");
+ test("&&&");
+ test("|");
+ test("(");
+ test(")");
+ test("[");
+ test("]");
+ test("{");
+ test("}");
+ test("()");
+ test("[]");
+ test("{}");
+ test("\\\\");
+ test("\\");
+
+ test("foo bar", TEST);
+ test("\"foo bar\"", TEST);
+ test("\"foo bar\" quux", TEST);
+ test("*\"foo bar\" *quux", TEST);
+ test("\"*foo bar\" *quux", TEST);
+ }
+
+}