X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.browsing.ui.common%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fcommon%2Fviews%2FDefaultFilterStrategy.java;fp=bundles%2Forg.simantics.browsing.ui.common%2Fsrc%2Forg%2Fsimantics%2Fbrowsing%2Fui%2Fcommon%2Fviews%2FDefaultFilterStrategy.java;h=eeecfdc30dfbd4ee729913c557e6fa23e95f02a3;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 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 index 000000000..eeecfdc30 --- /dev/null +++ b/bundles/org.simantics.browsing.ui.common/src/org/simantics/browsing/ui/common/views/DefaultFilterStrategy.java @@ -0,0 +1,247 @@ +/******************************************************************************* + * 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. + * + *

+ * 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. + * + *

+ * 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); + } + +}