source: other-projects/FileTransfer-WebSocketPair/testGXTWithGreenstone/src/org/greenstone/gatherer/gui/metaaudit/Autofilter.java@ 33053

Last change on this file since 33053 was 33053, checked in by ak19, 5 years ago

I still had some stuff of Nathan Kelly's (FileTransfer-WebSocketPair) sitting on my USB. Had already commited the Themes folder at the time, 2 years back. Not sure if he wanted this additional folder commited. But I didn't want to delete it and decided it will be better off on SVN. When we use his project, if we find we didn't need this test folder, we can remove it from svn then.

File size: 15.2 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.gui.metaaudit;
28
29
30import java.util.ArrayList;
31import org.greenstone.gatherer.util.StaticStrings;
32
33/** An Autofilter object stores the filters set on a single column, and provides a method for determining if a certain value passes the filter.
34 * @author John Thompson
35 * @version 2.3
36 */
37public class Autofilter {
38
39 static public void main(String[] args) {
40 if(args.length != 2) {
41 System.err.println("Usage: java Autofilter <string> <pattern>");
42 }
43 else {
44 switch(compareToPattern(args[0], args[1])) {
45 case LESS_THAN:
46 System.err.print(args[0] + " is less than");
47 break;
48 case GREATER_THAN:
49 System.err.print(args[0] + " is greater than");
50 break;
51 case EQUAL:
52 System.err.print(args[0] + " is equal to");
53 break;
54 default:
55 System.err.print(args[0] + " is something to");
56 }
57 System.err.println(" " + args[1]);
58 }
59 }
60
61 /** A String comparison which also recognises the WildCard character. The basic idea is that '*' matches zero or more of any characters, and if we limited patterns to be like "a*" then as soon as we hit the star we could return a match. The problem is that we want patterns like "b*y" which would match "boy" but not "bee" nor "bus" (but should return less than or greater than for each of these respectively). Thus our testing has to become non-deterministic so the matches are conducted like so:
62 * Given p = [ b * y ]
63 * Test s = [ b e e ] Result: p0=s0,{(p2>s1=>ERROR),(p1=s1,{(p1>s2=>ERROR),(p2>s2=>LESS_THAN)})} => LESS_THAN
64 * Test s = [ b o y ] Result: p0=s0,{(p2>s1=>ERROR),(p1=s1,{(p1>s2=>ERROR),(p2=s2=>EQUAL)})} => EQUAL
65 * Test s = [ b u s ] Result: p0=s0,{(p2>s1=>ERROR),(p1=s1,{(p1>s2=>ERROR),(p2<s2=>GREATER_THAN)})} => GREATER_THAN
66 * where the two () phrases within a {} represent two different 'threads' of processing. Errors are generated when one string runs out of characters before the other. Only non-error results are propogated. I've decided to implement this non-deterministic matching as a recursive function call.
67 * If you analyse it you can see there are three possible actions when a '*' is detected.
68 * 1. * is an empty string, ignore it in pattern and try to compare the next character in p with the current character in s. This case only occurs if there are more characters in p (otherwise apple would be greater than a*)
69 * 2. * matches exactly the current character in s, try to match the next character in p with the next character in s
70 * 3. * matches some string of characters including the current character in s, try to match '*' against the next character in s
71 * @param s the String being matched
72 * @param p the Pattern to match it against
73 * @return -1 if s is less than p, 0 if they are equal, 1 if s is greater than p
74 */
75 static private int compareToPattern(String s, String p) {
76 if(p.indexOf(StaticStrings.STAR_CHAR) == -1) {
77 return compareToPattern(s, p, 0, 0, false);
78 }
79 else {
80 return compareToPattern(s, p, 0, 0, true);
81 }
82 }
83
84 static final private int LESS_THAN = -1;
85 static final private int EQUAL = 0;
86 static final private int GREATER_THAN = 1;
87 static final private int ERROR = 42;
88
89 static private int compareToPattern(String s, String p, int s_index, int p_index, boolean wildcard_matching) {
90 // Lets do the simple cases first.
91 // Both out of characters at the same time
92 if(s_index >= s.length() && p_index >= p.length()) {
93 ///ystem.err.println("Both out of characters. Equal.");
94 return EQUAL;
95 }
96 // s out of characters first
97 if(s_index >= s.length()) {
98 // Not allowed to run out if matching wildcard
99 if(wildcard_matching) {
100 return ERROR;
101 }
102 // Remember that wildcard matches the empty string too, so as long as there are only '*' characters left in the pattern we can say they are equal as well.
103 else {
104 while(p_index < p.length()) {
105 if(p.charAt(p_index) == StaticStrings.STAR_CHAR) {
106 p_index++;
107 }
108 else {
109 ///ystem.err.println("S out of characters. Less Than.");
110 return LESS_THAN;
111 }
112 }
113 // We've run out of pattern and it only contained '*' so we're still equal
114 ///ystem.err.println("Both out of characters. Equal.");
115 return EQUAL;
116 }
117 }
118 // p out of characters first
119 if(p_index >= p.length()) {
120 // Not allowed to run out if matching wildcard
121 if(wildcard_matching) {
122 return ERROR;
123 }
124 // so it is greater than
125 else {
126 ///ystem.err.println("P out of characters. Greater Than.");
127 return GREATER_THAN;
128 }
129 }
130 char s_char = s.charAt(s_index);
131 char p_char = p.charAt(p_index);
132 ///ystem.err.println("Comparing " + s_char + " against pattern character " + p_char);
133 // Equivelent characters
134 // Now the tricky-dicky bit - WildCard matching.
135 if(p_char == StaticStrings.STAR_CHAR) {
136 int result;
137 // Case 1
138 ///ystem.err.println("WildCard Case 1");
139 if(p_index + 1 < p.length()) {
140 if((result = compareToPattern(s, p, s_index, p_index + 1, wildcard_matching)) != ERROR) {
141 return result;
142 }
143 }
144 // Case 2
145 ///ystem.err.println("WildCard Case 2");
146 if((result = compareToPattern(s, p, s_index + 1, p_index + 1, wildcard_matching)) != ERROR) {
147 return result;
148 }
149 // Case 3
150 ///ystem.err.println("WildCard Case 3");
151 if((result = compareToPattern(s, p, s_index + 1, p_index, wildcard_matching)) != ERROR) {
152 return result;
153 }
154 }
155 if(s_char == p_char) {
156 return compareToPattern(s, p, s_index + 1, p_index + 1, wildcard_matching);
157 }
158 // A preceeding character
159 if(s_char < p_char) {
160 ///ystem.err.println("s char is less than p char");
161 if(wildcard_matching) {
162 ///ystem.err.println("Because we are wildcard matching we still have to match the rest of s incase of errors.");
163 if(compareToPattern(s, p, s_index + 1, p_index + 1, wildcard_matching) != ERROR) {
164 ///ystem.err.println("No error. Less than.");
165 return LESS_THAN;
166 }
167 else {
168 ///ystem.err.println("Error detected.");
169 return ERROR;
170 }
171 }
172 else {
173 ///ystem.err.println("Less than.");
174 return LESS_THAN;
175 }
176 }
177 // A succeeding character
178 if(s_char > p_char) {
179 ///ystem.err.println("s char is greater than p char");
180 if(wildcard_matching) {
181 ///ystem.err.println("Because we are wildcard matching we still have to match the rest of s incase of errors.");
182 if(compareToPattern(s, p, s_index + 1, p_index + 1, wildcard_matching) != ERROR) {
183 ///ystem.err.println("No error. Greater than.");
184 return GREATER_THAN;
185 }
186 else {
187 ///ystem.err.println("Error detected.");
188 return ERROR;
189 }
190 }
191 else {
192 ///ystem.err.println("Greater than.");
193 return GREATER_THAN;
194 }
195 }
196 // Oh-No. Well, we'll just assume that string is less than pattern
197 return LESS_THAN;
198 }
199
200 /** <i>true</i> if the filter should be applied, <i>false</i> to indicate the filter is turned off. */
201 public boolean active;
202 /** <i>true</i> if the matching for the first expression should be case sensitive, <i>false</i> otherwise. */
203 public boolean casesense_one;
204 /** <i>true</i> if the matching for the second expression should be case sensitive, <i>false</i> otherwise. */
205 public boolean casesense_two;
206 /** Used to determine the operation intended when applying two filters, and set using the values of the OPERATION_TYPE enumeration. */
207 public boolean operation;
208 /** Used to determine how the column this filter is applied to should be sorted, and set using the values of the SORT_TYPE enumeration. */
209 public boolean sort;
210 /** The method to be used for the first filter expression, set from the values of the METHOD_LIST enumeration. */
211 public int method_one;
212 /** The method to be used for the second filter expression, set from the values of the METHOD_LIST enumeration. */
213 public int method_two;
214 /** The value to be matched against for the first expression. */
215 public String value_one;
216 /** The value to be matched against for the second expression. */
217 public String value_two;
218 /** An element of the SORT_TYPE enumeration, indicates lowest to highest value column ordering. */
219 public static final boolean ASCENDING = true;
220 /** An element of the OPERATION_TYPE enumeration, indicates that both filter expressions must be met (conjunction). */
221 public static final boolean AND = true;
222 /** An element of the SORT_TYPE enumeration, indicates highest to lowest value column ordering. */
223 public static final boolean DESCENDING = false;
224 /** An element of the OPERATION_TYPE enumeration, indicates that either (or both) filter expressions must be met (disjunction). */
225 public static final boolean OR = false;
226 /** An enumeration of symbolic names of various matching methods. */
227 public static final String METHOD_LIST[] = { "Autofilter.eqeq", "Autofilter.!eq", "Autofilter.<", "Autofilter.<eq", "Autofilter.>", "Autofilter.>eq", "Autofilter.^", "Autofilter.!^", "Autofilter.$", "Autofilter.!$", "Autofilter.?", "Autofilter.!?" };
228
229 /** Default Constructor. */
230 public Autofilter() {
231 operation = OR;
232 sort = ASCENDING;
233 }
234 /** Determine if this filter is currently active.
235 * @return <i>true</i> if it is active, <i>false</i> otherwise.
236 */
237 public boolean active() {
238 return active;
239 }
240 /** Determine if this list of values (for a certain cell) passes the filter.
241 * @param values An <strong>ArrayList</strong> of values sourced from a single cell in the associated column.
242 * @return <i>true</i> if the values match and should be displayed, <i>false</i> otherwise.
243 */
244 public boolean filter(ArrayList values) {
245 boolean result = false;
246 if(value_one != null) {
247 result = filter(values, method_one, value_one, casesense_one);
248 if(result) {
249 if(operation == AND && value_two != null) {
250 result = filter(values, method_two, value_two, casesense_two);
251 }
252 }
253 else if(operation == OR && value_two != null) {
254 result = filter(values, method_two, value_two, casesense_two);
255 }
256 }
257 return result;
258 }
259 /** Set the current activity state of this filter.
260 * @param active The new state of this filter, <i>true</i> to activate, <i>false</i> otherwise.
261 */
262 public void setActive(boolean active) {
263 this.active = active;
264 }
265 /** Set one of the filter expressions using the given information.
266 * @param number The number of the filter you wish to set as an <i>int</i>. Either 1 or 2.
267 * @param method An <i>int</i> indicating the method to be used when matching.
268 * @param value The <strong>String</strong> to be matched against.
269 * @param casesense <i>true</i> if this expression should be case sensitive, <i>false</i> otherwise.
270 */
271 public void setFilter(int number, int method, String value, boolean casesense) {
272 if(!casesense && value != null) {
273 value = value.toLowerCase();
274 }
275 if(number == 1) {
276 casesense_one = casesense;
277 method_one = method;
278 value_one = value;
279 }
280 else {
281 casesense_two = casesense;
282 method_two = method;
283 value_two = value;
284 }
285 }
286 /** Set the operation to be used to join the two filters (if a second filter is set).
287 * @param operation <i>true</i> for conjunct filters, <i>false</i> for disjunct.
288 */
289 public void setOperation(boolean operation) {
290 this.operation = operation;
291 }
292 /** Set the sort order of this column.
293 * @param sort <i>true</i> for ascending sort, <i>false</i> for descending.
294 */
295 public void setSort(boolean sort) {
296 this.sort = sort;
297 }
298 /** Decide whether a row should be displayed or filtered. The result depends on the selector set with setFilterType.
299 * @param values An <strong>ArrayList</strong> of values to be checked against the filter.
300 * @param method The method of matching to be used, as an <i>int</i>.
301 * @param target The <strong>String</Strong> to match against.
302 * @param casesense <i>true</i> if the match is to be case sensitive, <i>false</i> otherwise.
303 * @return <i>true</i> to display the row, <i>false</i> to hide it.
304 */
305 public boolean filter(ArrayList values, int method, String target, boolean casesense) {
306 boolean result = false;
307 // There are several special cases when the filter always returns turn, such as when the target is the wildcard character.
308 if(target == null || target.length() == 0 || target.equals("*")) {
309 result = true;
310 }
311 else {
312 // For each value in the list...
313 for(int i = 0; i < values.size(); i++) {
314 boolean pass;
315 String source;
316 // Account for case sensitivity.
317 if(casesense) {
318 source = values.get(i).toString();
319 }
320 else {
321 source = values.get(i).toString().toLowerCase();
322 }
323 ///ystem.err.println("Testing " + source + " against pattern " + target);
324 // Perform the match, based on the selected method.
325 switch(method) {
326 case 1: // !EQ
327 pass = (compareToPattern(source, target) != 0);
328 break;
329 case 2: // <
330 pass = (compareToPattern(source, target) < 0);
331 break;
332 case 3: // <eq
333 pass = (compareToPattern(source, target) <= 0);
334 break;
335 case 4: // >
336 pass = (compareToPattern(source, target) > 0);
337 break;
338 case 5: // >eq
339 pass = (compareToPattern(source, target) >= 0);
340 break;
341 case 6: // ^
342 pass = source.startsWith(target);
343 break;
344 case 7: // !^
345 pass = !(source.startsWith(target));
346 break;
347 case 8: // $
348 pass = source.endsWith(target);
349 break;
350 case 9: // !$
351 pass = !(source.endsWith(target));
352 break;
353 case 10: // ?
354 pass = (source.indexOf(target) != -1);
355 break;
356 case 11: // !?
357 pass = (source.indexOf(target) == -1);
358 break;
359 default: // EQEQ
360 pass = (compareToPattern(source, target) == 0);
361 break;
362 }
363 result = result || pass;
364 }
365 }
366 return result;
367 }
368 /** Produce a textual representation of this autofilter.
369 * @return A <strong>String</strong> displaying details of this autofilter.
370 */
371 public String toString() {
372 String result = "One: " + method_one + " - " + value_one + " - " + casesense_one;
373 if(value_two != null) {
374 result = result + "\n" + "Operation: " + (operation?"AND":"OR") + "\n";
375 result = result + "Two: " + method_two + " - " + value_two + " - " + casesense_two;
376 }
377 return result;
378 }
379}
Note: See TracBrowser for help on using the repository browser.