1 /*******************************************************************************
\r
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
\r
3 * in 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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.browsing.ui.common.views;
\r
14 import java.nio.CharBuffer;
\r
15 import java.util.regex.Matcher;
\r
16 import java.util.regex.Pattern;
\r
19 * Default implementation of IFilterStrategy.
\r
22 * It implements simple search semantics with only the special wildcard
\r
23 * characters '*' ( 0 to n any characters) and '?' (any one character)
\r
24 * recognized. In order to allow the filter to pass arbitrary prefixes, the
\r
25 * client has to give a '*' prefix in the filter string. On the contrary, the
\r
26 * client does not have to specify a '*' in order to pass arbitrary suffixes -
\r
27 * arbitrary suffixes are allowed by default by this strategy.
\r
30 * This strategy forces the filter string to lowercase.
\r
32 * TODO: implement case-insensitiveness properly, not by forcing the search string into lower case. Also Fix FilterSelectionRequestQueryProcessor after doing this.
\r
34 * @author Tuukka Lehtonen
\r
36 public class DefaultFilterStrategy implements IFilterStrategy {
\r
38 private static final boolean DEBUG = false;
\r
40 boolean implicitPreAsterisk = true;
\r
42 public DefaultFilterStrategy() {
\r
46 public DefaultFilterStrategy(boolean implicitPreAsterisk) {
\r
47 this.implicitPreAsterisk = implicitPreAsterisk;
\r
50 private static StringBuilder addSearchWord(StringBuilder sb, String pattern) {
\r
52 System.out.println("addSearchWord(" + pattern + ") to '" + sb.toString() + "'");
\r
54 if (pattern == null || pattern.isEmpty())
\r
56 if (sb.length() > 0)
\r
64 private static String toString(CharBuffer cb) {
\r
65 cb.limit(cb.position());
\r
68 System.out.println("toString(" + cb + ")");
\r
69 String result = cb.toString();
\r
70 cb.limit(cb.capacity());
\r
74 public static String toSinglePatternString(String filter, boolean implicitPreAsterisk) {
\r
75 if (!filter.isEmpty()) {
\r
76 // Force searching in lowercase.
\r
77 filter = filter.toLowerCase();
\r
79 // Construct a regular expression from the specified text.
\r
80 String regExFilter = filter
\r
81 .replace("\\", "\\\\") // \ -> \\
\r
82 .replace(".", "\\.") // . -> \.
\r
83 .replace("*", ".*") // * -> Any 0..n characters
\r
84 .replace("?", ".") // ? -> Any single character
\r
85 .replace("+", "\\+") // + -> \+
\r
86 .replace("(", "\\(") // ( -> \(
\r
87 .replace(")", "\\)") // ) -> \)
\r
88 .replace("[", "\\[") // [ -> \[
\r
89 .replace("]", "\\]") // ] -> \]
\r
90 .replace("{", "\\{") // { -> \{
\r
91 .replace("}", "\\}") // } -> \}
\r
92 .replace("^", "\\^") // ^ -> \^
\r
93 .replace("$", "\\$") // $ -> \$
\r
94 .replace("|", ".*|") // $ -> \$
\r
95 //.replace("|", "\\|") // | -> \|
\r
96 .replace("&&", "\\&&") // && -> \&&
\r
99 if (implicitPreAsterisk)
\r
100 if (!regExFilter.startsWith(".*"))
\r
101 regExFilter = ".*" + regExFilter ;
\r
102 if (!regExFilter.endsWith(".*"))
\r
103 regExFilter += ".*" ;
\r
105 return regExFilter;
\r
110 public static String defaultToPatternString(String filter, boolean implicitPreAsterisk) {
\r
111 if (filter.isEmpty())
\r
114 CharBuffer buf = CharBuffer.allocate(filter.length()*2);
\r
116 StringBuilder sb = new StringBuilder(filter.length()*2);
\r
117 boolean inQuote = false;
\r
118 int len = filter.length();
\r
119 for (int i = 0; i < len;) {
\r
120 char ch = filter.charAt(i);
\r
122 System.out.println("char[" + i + "]: '" + ch + "'");
\r
127 System.out.println("begin quoted text");
\r
131 System.out.println("end quoted text");
\r
133 addSearchWord(sb, toSinglePatternString( toString(buf), implicitPreAsterisk ));
\r
137 } else if (ch == '\\') {
\r
138 // Next character is escaped, i.e. taken as is.
\r
141 // Unexpected end-of-string
\r
144 ch = filter.charAt(i);
\r
146 System.out.println("append escaped character '" + ch + "'");
\r
151 } else if (ch == ' ') {
\r
154 System.out.println("append char '" + ch + "'");
\r
158 if (buf.position() > 0) {
\r
159 addSearchWord(sb, toSinglePatternString( toString(buf), implicitPreAsterisk ));
\r
165 System.out.println("append char '" + ch + "'");
\r
170 if (buf.position() > 0) {
\r
171 addSearchWord(sb, toSinglePatternString( toString(buf), implicitPreAsterisk ));
\r
176 return sb.toString();
\r
180 public String toPatternString(String filter) {
\r
181 return defaultToPatternString(filter, implicitPreAsterisk);
\r
184 public static Pattern compilePattern(String s) {
\r
185 IFilterStrategy st = new DefaultFilterStrategy(true);
\r
186 System.out.println("compilePattern(" + s + ")");
\r
187 String regex = st.toPatternString(s);
\r
188 System.out.println(s + " -> " + regex);
\r
189 Pattern p = Pattern.compile(regex);
\r
193 public static void test(String pattern, String... testStrings) {
\r
194 Pattern p = compilePattern(pattern);
\r
195 for (String test : testStrings) {
\r
196 System.out.print("\ttesting '" + test + "'");
\r
197 Matcher m = p.matcher(test);
\r
199 System.out.println(" - MATCHES");
\r
201 System.out.println(" - NO MATCH");
\r
206 static String[] TEST = {
\r
207 "foo bar baz biz boz",
\r
208 "biz bar baz foo boz",
\r
217 public static void main(String[] args) {
\r
240 test("foo bar", TEST);
\r
241 test("\"foo bar\"", TEST);
\r
242 test("\"foo bar\" quux", TEST);
\r
243 test("*\"foo bar\" *quux", TEST);
\r
244 test("\"*foo bar\" *quux", TEST);
\r