]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/views/DefaultFilterStrategy.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.browsing.ui.common / src / org / simantics / browsing / ui / common / views / DefaultFilterStrategy.java
diff --git a/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/views/DefaultFilterStrategy.java b/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/views/DefaultFilterStrategy.java
new file mode 100644 (file)
index 0000000..eeecfdc
--- /dev/null
@@ -0,0 +1,247 @@
+/*******************************************************************************\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