KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > rice > cs > drjava > ui > predictive > PredictiveInputModel


1 /*BEGIN_COPYRIGHT_BLOCK
2  *
3  * This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4  * or http://sourceforge.net/projects/drjava/
5  *
6  * DrJava Open Source License
7  *
8  * Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9  *
10  * Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13  * documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15  * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16  *
17  * - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18  * following disclaimers.
19  * - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20  * following disclaimers in the documentation and/or other materials provided with the distribution.
21  * - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22  * endorse or promote products derived from this Software without specific prior written permission.
23  * - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24  * names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27  * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * WITH THE SOFTWARE.
31  *
32  *END_COPYRIGHT_BLOCK*/

33
34 package edu.rice.cs.drjava.ui.predictive;
35
36 import java.util.List JavaDoc;
37 import java.util.ArrayList JavaDoc;
38 import java.util.Collections JavaDoc;
39 import java.util.regex.Pattern JavaDoc;
40 import java.util.regex.Matcher JavaDoc;
41 import java.util.regex.PatternSyntaxException JavaDoc;
42
43 /** Model class for predictive string input. */
44 public class PredictiveInputModel<T extends Comparable JavaDoc<? super T>> {
45   
46   /** Strategy used for matching and mask extension. */
47   public static interface MatchingStrategy<X extends Comparable JavaDoc<? super X>> {
48     
49     /** Returns true if the item is a match.
50      * @param item item to check
51      * @param pim predictive input model
52      * @return true if the item is a match
53      */

54     public boolean isMatch(X item, PredictiveInputModel<X> pim);
55     
56     /** Returns true if the two items are equivalent under this matching strategy.
57      * @param item1 first item
58      * @param item2 second item
59      * @param pim predictive input model
60      * @return true if equivalent
61      */

62     public boolean equivalent(X item1, X item2, PredictiveInputModel<X> pim);
63     
64     /** Compare the two items and return -1, 0, or 1 if item1 is less than, equal to, or greater than item2.
65       * @param item1 first item
66       * @param item2 second item
67       * @param pim predictive input model
68       * @return -1, 0, or 1
69       */

70     public int compare(X item1, X item2, PredictiveInputModel<X> pim);
71
72     /** Returns the item from the list that is the longest match.
73       * @param item target item
74       * @param items list with items
75       * @param pim predictive input model
76       * @return longest match
77       */

78     public X getLongestMatch(X item, List JavaDoc<X> items, PredictiveInputModel<X> pim);
79     
80     /** Returns the shared mask extension for the list of items.
81       * @param items items for which the mask extension should be generated
82       * @param pim predictive input model
83       * @return the shared mask extension
84       */

85     public String JavaDoc getSharedMaskExtension(List JavaDoc<X> items, PredictiveInputModel<X> pim);
86        
87     /** Returns the mask extended by the shared extension.
88       * @param items items for which the mask extension should be generated
89       * @param pim predictive input model
90       * @return the extended shared mask
91       */

92     public String JavaDoc getExtendedSharedMask(List JavaDoc<X> items, PredictiveInputModel<X> pim);
93   
94     /** Force the mask to fit this entry. The matching strategies that accept line numbers
95       * can combine the current item with the line number. Other strategies just return the
96       * current item.
97       * @return forced string
98       */

99     public String JavaDoc force(X item, String JavaDoc mask);
100   }
101   
102   /** Matching based on string prefix. */
103   public static class PrefixStrategy<X extends Comparable JavaDoc<? super X>> implements MatchingStrategy<X> {
104     public String JavaDoc toString() { return "Prefix"; }
105     public boolean isMatch(X item, PredictiveInputModel<X> pim) {
106       String JavaDoc a = (pim._ignoreCase)?(item.toString().toLowerCase()):(item.toString());
107       String JavaDoc b = (pim._ignoreCase)?(pim._mask.toLowerCase()):(pim._mask);
108       return a.startsWith(b);
109     }
110     public boolean equivalent(X item1, X item2, PredictiveInputModel<X> pim) {
111       String JavaDoc a = (pim._ignoreCase)?(item1.toString().toLowerCase()):(item1.toString());
112       String JavaDoc b = (pim._ignoreCase)?(item2.toString().toLowerCase()):(item2.toString());
113       return a.equals(b);
114     }
115     public int compare(X item1, X item2, PredictiveInputModel<X> pim) {
116       String JavaDoc a = (pim._ignoreCase)?(item1.toString().toLowerCase()):(item1.toString());
117       String JavaDoc b = (pim._ignoreCase)?(item2.toString().toLowerCase()):(item2.toString());
118       return a.compareTo(b);
119     }
120     public X getLongestMatch(X item, List JavaDoc<X> items, PredictiveInputModel<X> pim) {
121       X longestMatch = null;
122       int matchLength = -1;
123       for(X i: items) {
124         String JavaDoc s = (pim._ignoreCase)?(i.toString().toLowerCase()):(i.toString());
125         String JavaDoc t = (pim._ignoreCase)?(item.toString().toLowerCase()):(item.toString());
126         int ml = 0;
127         while((s.length() > ml) && (t.length() > ml) && (s.charAt(ml) == t.charAt(ml))) {
128           ++ml;
129         }
130         if (ml>matchLength) {
131           matchLength = ml;
132           longestMatch = i;
133         }
134       }
135       return longestMatch;
136     }
137     public String JavaDoc getSharedMaskExtension(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
138       String JavaDoc res = "";
139       String JavaDoc ext = "";
140       if (items.size() == 0) {
141         return ext;
142       }
143       boolean allMatching = true;
144       int len = pim._mask.length();
145       while((allMatching) && (pim._mask.length() + ext.length() < items.get(0).toString().length())) {
146         char origCh = items.get(0).toString().charAt(pim._mask.length()+ext.length());
147         char ch = (pim._ignoreCase)?(Character.toLowerCase(origCh)):(origCh);
148         allMatching = true;
149         for (X i: items) {
150           String JavaDoc a = (pim._ignoreCase)?(i.toString().toLowerCase()):(i.toString());
151           if (a.charAt(len)!=ch) {
152             allMatching = false;
153             break;
154           }
155         }
156         if (allMatching) {
157           ext = ext + ch;
158           res = res + origCh;
159           ++len;
160         }
161       }
162       return res;
163     }
164     public String JavaDoc getExtendedSharedMask(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
165       return pim._mask + getSharedMaskExtension(items, pim);
166     }
167     public String JavaDoc force(X item, String JavaDoc mask) { return item.toString(); }
168   };
169   
170   /** Matching based on string fragments. */
171   public static class FragmentStrategy<X extends Comparable JavaDoc<? super X>> implements MatchingStrategy<X> {
172     public String JavaDoc toString() { return "Fragments"; }
173     public boolean isMatch(X item, PredictiveInputModel<X> pim) {
174       String JavaDoc a = (pim._ignoreCase)?(item.toString().toLowerCase()):(item.toString());
175       String JavaDoc b = (pim._ignoreCase)?(pim._mask.toLowerCase()):(pim._mask);
176
177       java.util.StringTokenizer JavaDoc tok = new java.util.StringTokenizer JavaDoc(b);
178       while(tok.hasMoreTokens()) {
179         if (a.indexOf(tok.nextToken()) < 0) return false;
180       }
181       return true;
182     }
183     public boolean equivalent(X item1, X item2, PredictiveInputModel<X> pim) {
184       String JavaDoc a = (pim._ignoreCase)?(item1.toString().toLowerCase()):(item1.toString());
185       String JavaDoc b = (pim._ignoreCase)?(item2.toString().toLowerCase()):(item2.toString());
186       return a.equals(b);
187     }
188     public int compare(X item1, X item2, PredictiveInputModel<X> pim) {
189       String JavaDoc a = (pim._ignoreCase)?(item1.toString().toLowerCase()):(item1.toString());
190       String JavaDoc b = (pim._ignoreCase)?(item2.toString().toLowerCase()):(item2.toString());
191       return a.compareTo(b);
192     }
193     public X getLongestMatch(X item, List JavaDoc<X> items, PredictiveInputModel<X> pim) {
194       if (items.size() > 0) return items.get(0);
195       else return null;
196     }
197     public String JavaDoc getSharedMaskExtension(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
198       return ""; // can't thing of a good way
199
}
200     public String JavaDoc getExtendedSharedMask(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
201       return pim._mask;
202     }
203     public String JavaDoc force(X item, String JavaDoc mask) { return item.toString(); }
204   };
205   
206   /** Matching based on string regular expressions. */
207   public static class RegExStrategy<X extends Comparable JavaDoc<? super X>> implements MatchingStrategy<X> {
208     public String JavaDoc toString() { return "RegEx"; }
209     public boolean isMatch(X item, PredictiveInputModel<X> pim) {
210       String JavaDoc a = item.toString();
211
212       try {
213         Pattern JavaDoc p = Pattern.compile(pim._mask,
214                                     (pim._ignoreCase)?(Pattern.CASE_INSENSITIVE):(0));
215         Matcher JavaDoc m = p.matcher(a);
216         return m.matches();
217       }
218       catch (PatternSyntaxException JavaDoc e) {
219         return false;
220       }
221     }
222     public boolean equivalent(X item1, X item2, PredictiveInputModel<X> pim) {
223       String JavaDoc a = (pim._ignoreCase)?(item1.toString().toLowerCase()):(item1.toString());
224       String JavaDoc b = (pim._ignoreCase)?(item2.toString().toLowerCase()):(item2.toString());
225       return a.equals(b);
226     }
227     public int compare(X item1, X item2, PredictiveInputModel<X> pim) {
228       String JavaDoc a = (pim._ignoreCase)?(item1.toString().toLowerCase()):(item1.toString());
229       String JavaDoc b = (pim._ignoreCase)?(item2.toString().toLowerCase()):(item2.toString());
230       return a.compareTo(b);
231     }
232     public X getLongestMatch(X item, List JavaDoc<X> items, PredictiveInputModel<X> pim) {
233       if (items.size() > 0) return items.get(0); // can't thing of a good way
234
else return null;
235     }
236     public String JavaDoc getSharedMaskExtension(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
237       return ""; // can't thing of a good way
238
}
239     public String JavaDoc getExtendedSharedMask(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
240       return pim._mask;
241     }
242     public String JavaDoc force(X item, String JavaDoc mask) { return item.toString(); }
243   };
244   
245   /** Matching based on string prefix, supporting line numbers separated by :. */
246   public static class PrefixLineNumStrategy<X extends Comparable JavaDoc<? super X>> implements MatchingStrategy<X> {
247     public String JavaDoc toString() { return "Prefix"; }
248     public boolean isMatch(X item, PredictiveInputModel<X> pim) {
249       int posB = pim._mask.lastIndexOf(':');
250       if (posB<0) { posB = pim._mask.length(); }
251       String JavaDoc mask = pim._mask.substring(0,posB);
252       
253       String JavaDoc a = (pim._ignoreCase)?(item.toString().toLowerCase()):(item.toString());
254       String JavaDoc b = (pim._ignoreCase)?(mask.toLowerCase()):(mask);
255       return a.startsWith(b);
256     }
257     public boolean equivalent(X item1, X item2, PredictiveInputModel<X> pim) {
258       int posA = item1.toString().lastIndexOf(':');
259       if (posA<0) { posA = item1.toString().length(); }
260       String JavaDoc i1 = item1.toString().substring(0,posA);
261
262       int posB = item2.toString().lastIndexOf(':');
263       if (posB<0) { posB = item2.toString().length(); }
264       String JavaDoc i2 = item2.toString().substring(0,posB);
265       
266       String JavaDoc a = (pim._ignoreCase)?(i1.toLowerCase()):(i1);
267       String JavaDoc b = (pim._ignoreCase)?(i2.toLowerCase()):(i2);
268       return a.equals(b);
269     }
270     public int compare(X item1, X item2, PredictiveInputModel<X> pim) {
271       int posA = item1.toString().lastIndexOf(':');
272       if (posA<0) { posA = item1.toString().length(); }
273       String JavaDoc i1 = item1.toString().substring(0,posA);
274
275       int posB = item2.toString().lastIndexOf(':');
276       if (posB<0) { posB = item2.toString().length(); }
277       String JavaDoc i2 = item2.toString().substring(0,posB);
278       
279       String JavaDoc a = (pim._ignoreCase)?(i1.toLowerCase()):(i1);
280       String JavaDoc b = (pim._ignoreCase)?(i2.toLowerCase()):(i2);
281       return a.compareTo(b);
282     }
283     public X getLongestMatch(X item, List JavaDoc<X> items, PredictiveInputModel<X> pim) {
284       X longestMatch = null;
285       int matchLength = -1;
286       for(X i: items) {
287         int posA = i.toString().lastIndexOf(':');
288         if (posA<0) { posA = i.toString().length(); }
289         String JavaDoc i1 = i.toString().substring(0,posA);
290         
291         int posB = item.toString().lastIndexOf(':');
292         if (posB<0) { posB = item.toString().length(); }
293         String JavaDoc i2 = item.toString().substring(0,posB);
294         
295         String JavaDoc s = (pim._ignoreCase)?(i1.toLowerCase()):(i1);
296         String JavaDoc t = (pim._ignoreCase)?(i2.toLowerCase()):(i2);
297         int ml = 0;
298         while((s.length() > ml) && (t.length() > ml) && (s.charAt(ml) == t.charAt(ml))) {
299           ++ml;
300         }
301         if (ml>matchLength) {
302           matchLength = ml;
303           longestMatch = i;
304         }
305       }
306       return longestMatch;
307     }
308     public String JavaDoc getSharedMaskExtension(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
309       String JavaDoc res = "";
310       String JavaDoc ext = "";
311       if (items.size() == 0) {
312         return ext;
313       }
314       
315       int posB = pim._mask.lastIndexOf(':');
316       if (posB<0) { posB = pim._mask.length(); }
317       String JavaDoc mask = pim._mask.substring(0,posB);
318       
319       boolean allMatching = true;
320       int len = mask.length();
321       while((allMatching) && (mask.length() + ext.length() < items.get(0).toString().length())) {
322         char origCh = items.get(0).toString().charAt(mask.length()+ext.length());
323         char ch = (pim._ignoreCase)?(Character.toLowerCase(origCh)):(origCh);
324         allMatching = true;
325         for (X i: items) {
326           String JavaDoc a = (pim._ignoreCase)?(i.toString().toLowerCase()):(i.toString());
327           if (a.charAt(len)!=ch) {
328             allMatching = false;
329             break;
330           }
331         }
332         if (allMatching) {
333           ext = ext + ch;
334           res = res + origCh;
335           ++len;
336         }
337       }
338       return res;
339     }
340     public String JavaDoc getExtendedSharedMask(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
341       int pos = pim._mask.lastIndexOf(':');
342       if (pos<0) {
343         return pim._mask + getSharedMaskExtension(items, pim);
344       }
345       else {
346         return pim._mask.substring(0,pos) + getSharedMaskExtension(items, pim) + pim._mask.substring(pos);
347       }
348     }
349     public String JavaDoc force(X item, String JavaDoc mask) {
350       int pos = mask.lastIndexOf(':');
351       if (pos<0) {
352         return item.toString();
353       }
354       else {
355         return item.toString()+mask.substring(pos);
356       }
357     }
358   };
359   
360   /** Matching based on string fragments, supporting line numbers. */
361   public static class FragmentLineNumStrategy<X extends Comparable JavaDoc<? super X>> implements MatchingStrategy<X> {
362     public String JavaDoc toString() { return "Fragments"; }
363     public boolean isMatch(X item, PredictiveInputModel<X> pim) {
364       int posB = pim._mask.lastIndexOf(':');
365       if (posB<0) { posB = pim._mask.length(); }
366       String JavaDoc mask = pim._mask.substring(0,posB);
367       
368       String JavaDoc a = (pim._ignoreCase)?(item.toString().toLowerCase()):(item.toString());
369       String JavaDoc b = (pim._ignoreCase)?(mask.toLowerCase()):(mask);
370
371       java.util.StringTokenizer JavaDoc tok = new java.util.StringTokenizer JavaDoc(b);
372       while(tok.hasMoreTokens()) {
373         if (a.indexOf(tok.nextToken()) < 0) return false;
374       }
375       return true;
376     }
377     public boolean equivalent(X item1, X item2, PredictiveInputModel<X> pim) {
378       int posA = item1.toString().lastIndexOf(':');
379       if (posA<0) { posA = item1.toString().length(); }
380       String JavaDoc i1 = item1.toString().substring(0,posA);
381
382       int posB = item2.toString().lastIndexOf(':');
383       if (posB<0) { posB = item2.toString().length(); }
384       String JavaDoc i2 = item2.toString().substring(0,posB);
385       
386       String JavaDoc a = (pim._ignoreCase)?(i1.toLowerCase()):(i1);
387       String JavaDoc b = (pim._ignoreCase)?(i2.toLowerCase()):(i2);
388       return a.equals(b);
389     }
390     public int compare(X item1, X item2, PredictiveInputModel<X> pim) {
391       int posA = item1.toString().lastIndexOf(':');
392       if (posA<0) { posA = item1.toString().length(); }
393       String JavaDoc i1 = item1.toString().substring(0,posA);
394
395       int posB = item2.toString().lastIndexOf(':');
396       if (posB<0) { posB = item2.toString().length(); }
397       String JavaDoc i2 = item2.toString().substring(0,posB);
398       
399       String JavaDoc a = (pim._ignoreCase)?(i1.toLowerCase()):(i1);
400       String JavaDoc b = (pim._ignoreCase)?(i2.toLowerCase()):(i2);
401       return a.compareTo(b);
402     }
403     public X getLongestMatch(X item, List JavaDoc<X> items, PredictiveInputModel<X> pim) {
404       if (items.size() > 0) return items.get(0);
405       else return null;
406     }
407     public String JavaDoc getSharedMaskExtension(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
408       return ""; // can't thing of a good way
409
}
410     public String JavaDoc getExtendedSharedMask(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
411       return pim._mask;
412     }
413     public String JavaDoc force(X item, String JavaDoc mask) {
414       int pos = mask.lastIndexOf(':');
415       if (pos<0) {
416         return item.toString();
417       }
418       else {
419         return item.toString()+mask.substring(pos);
420       }
421     }
422   };
423   
424   /** Matching based on string regular expressions, supporting line numbers. */
425   public static class RegExLineNumStrategy<X extends Comparable JavaDoc<? super X>> implements MatchingStrategy<X> {
426     public String JavaDoc toString() { return "RegEx"; }
427     public boolean isMatch(X item, PredictiveInputModel<X> pim) {
428       int posB = pim._mask.lastIndexOf(':');
429       if (posB<0) { posB = pim._mask.length(); }
430       String JavaDoc mask = pim._mask.substring(0,posB);
431       
432       String JavaDoc a = item.toString();
433
434       try {
435         Pattern JavaDoc p = Pattern.compile(mask,
436                                     (pim._ignoreCase)?(Pattern.CASE_INSENSITIVE):(0));
437         Matcher JavaDoc m = p.matcher(a);
438         return m.matches();
439       }
440       catch (PatternSyntaxException JavaDoc e) {
441         return false;
442       }
443     }
444     public boolean equivalent(X item1, X item2, PredictiveInputModel<X> pim) {
445       int posA = item1.toString().lastIndexOf(':');
446       if (posA<0) { posA = item1.toString().length(); }
447       String JavaDoc i1 = item1.toString().substring(0,posA);
448
449       int posB = item2.toString().lastIndexOf(':');
450       if (posB<0) { posB = item2.toString().length(); }
451       String JavaDoc i2 = item2.toString().substring(0,posB);
452       
453       String JavaDoc a = (pim._ignoreCase)?(i1.toLowerCase()):(i1);
454       String JavaDoc b = (pim._ignoreCase)?(i2.toLowerCase()):(i2);
455       return a.equals(b);
456     }
457     public int compare(X item1, X item2, PredictiveInputModel<X> pim) {
458       int posA = item1.toString().lastIndexOf(':');
459       if (posA<0) { posA = item1.toString().length(); }
460       String JavaDoc i1 = item1.toString().substring(0,posA);
461
462       int posB = item2.toString().lastIndexOf(':');
463       if (posB<0) { posB = item2.toString().length(); }
464       String JavaDoc i2 = item2.toString().substring(0,posB);
465       
466       String JavaDoc a = (pim._ignoreCase)?(i1.toLowerCase()):(i1);
467       String JavaDoc b = (pim._ignoreCase)?(i2.toLowerCase()):(i2);
468       return a.compareTo(b);
469     }
470     public X getLongestMatch(X item, List JavaDoc<X> items, PredictiveInputModel<X> pim) {
471       if (items.size() > 0) return items.get(0); // can't thing of a good way
472
else return null;
473     }
474     public String JavaDoc getSharedMaskExtension(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
475       return ""; // can't thing of a good way
476
}
477     public String JavaDoc getExtendedSharedMask(List JavaDoc<X> items, PredictiveInputModel<X> pim) {
478       return pim._mask;
479     }
480    public String JavaDoc force(X item, String JavaDoc mask) {
481       int pos = mask.lastIndexOf(':');
482       if (pos<0) {
483         return item.toString();
484       }
485       else {
486         return item.toString()+mask.substring(pos);
487       }
488     }
489   };
490   
491   /** Array of items. */
492   private volatile ArrayList JavaDoc<T> _items = new ArrayList JavaDoc<T>();
493
494   /** Index of currently selected full string. */
495   private volatile int _index = 0;
496
497   /** Array of matching items. */
498   private final ArrayList JavaDoc<T> _matchingItems = new ArrayList JavaDoc<T>();
499
500   /** Currently entered mask. */
501   private volatile String JavaDoc _mask = "";
502   
503   /** True if case should be ignored. */
504   private volatile boolean _ignoreCase = false;
505   
506   /** Matching strategy. */
507   private volatile MatchingStrategy<T> _strategy;
508
509   /** Create a new predictive input model.
510     * @param ignoreCase true if case should be ignored
511     * @param pim other predictive input model
512     */

513   public PredictiveInputModel(boolean ignoreCase, PredictiveInputModel<T> pim) {
514     this(ignoreCase, pim._strategy, pim._items);
515     setMask(pim.getMask());
516   }
517
518   /** Create a new predictive input model.
519     * @param ignoreCase true if case should be ignored
520     * @param strategy matching strategy to use
521     * @param items list of items
522     */

523   public PredictiveInputModel(boolean ignoreCase, MatchingStrategy<T> strategy, List JavaDoc<T> items) {
524     _ignoreCase = ignoreCase;
525     _strategy = strategy;
526     setList(items);
527   }
528
529   /**
530    * Create a new predictive input model.
531    * @param ignoreCase true if case should be ignored
532    * @param strategy matching strategy to use
533    * @param items varargs/array of items
534    */

535   public PredictiveInputModel(boolean ignoreCase, MatchingStrategy<T> strategy, T... items) {
536     _ignoreCase = ignoreCase;
537     _strategy = strategy;
538     setList(items);
539   }
540
541   /**
542    * Sets the strategy
543    */

544   public void setStrategy(MatchingStrategy<T> strategy) {
545     _strategy = strategy;
546     updateMatchingStrings(_items);
547   }
548
549   /**
550    * Sets the list.
551    * @param items list of items
552    */

553   public void setList(List JavaDoc<T> items) {
554     _items = new ArrayList JavaDoc<T>(items);
555     Collections.sort(_items);
556     updateMatchingStrings(_items);
557   }
558
559   /** Sets the list
560     * @param items varargs/array of items
561     */

562   public void setList(T... items) {
563     _items = new ArrayList JavaDoc<T>(items.length);
564     for(T s: items) _items.add(s);
565     Collections.sort(_items);
566     updateMatchingStrings(_items);
567   }
568
569   /** Sets the list.
570     * @param pim other predictive input model
571     */

572   public void setList(PredictiveInputModel<T> pim) { setList(pim._items); }
573
574   /** Return the current mask.
575     * @return current mask
576     */

577   public String JavaDoc getMask() { return _mask; }
578
579   /** Set the current mask.
580     * @param mask new mask
581     */

582   public void setMask(String JavaDoc mask) {
583     _mask = mask;
584     updateMatchingStrings(_items);
585   }
586
587   /** Helper function that does indexOf with ignoreCase option.
588     * @param l list
589     * @param item item for which the index should be retrieved
590     * @return index of item in list, or -1 if not found
591     */

592   private int indexOf(ArrayList JavaDoc<T> l, T item) {
593     int index = 0;
594     for (T i: l) {
595       if (_strategy.equivalent(item, i, this)) return index;
596       ++index;
597     }
598     return -1;
599   }
600   
601   /** Update the list of matching strings and current index.
602     * @param items list of items to base the matching on
603     */

604   private void updateMatchingStrings(ArrayList JavaDoc<T> items) {
605     items = new ArrayList JavaDoc<T>(items); // create a new copy, otherwise we might be clearing the list in the next line
606
_matchingItems.clear();
607     for(T s: items) {
608       if (_strategy.isMatch(s, this)) _matchingItems.add(s);
609     }
610     if (_items.size() > 0) setCurrentItem(_items.get(_index));
611     else _index = 0;
612   }
613
614   /** Get currently selected item.
615     * @return currently selected item
616     */

617   public T getCurrentItem() {
618     if (_items.size() > 0) return _items.get(_index);
619     else return null;
620   }
621
622   /** Set currently selected item. Will select the item, or if the item does not match the mask, an item as closely
623     * preceding as possible.
624     * @param item currently selected item
625     */

626   public void setCurrentItem(T item) {
627     if (_items.size() == 0) {
628       _index = 0;
629       return;
630     }
631     boolean found = false;
632     int index = indexOf(_items, item);
633     if (index<0) {
634       // not in list of items, pick first item
635
pickClosestMatch(item);
636     }
637     else {
638       for (int i=index; i<_items.size(); ++i) {
639         if (0 <= indexOf(_matchingItems, _items.get(i))) {
640           _index = i;
641           found = true;
642           break;
643         }
644       }
645       if (!found) {
646         pickClosestMatch(item);
647       }
648     }
649   }
650
651   /** Select as current item the item in the list of current matches that lexicographically precedes it most closely.
652     * @param item item for witch to find the closest match
653     */

654   private void pickClosestMatch(T item) {
655     if (_matchingItems.size() > 0) {
656       // pick item that lexicographically follows
657
T follows = _matchingItems.get(0);
658       for (T i: _matchingItems) {
659         if (_strategy.compare(item, i, this) < 0) {
660           break;
661         }
662         follows = i;
663       }
664       _index = indexOf(_items, follows);
665     }
666     else {
667       _index = indexOf(_items, _strategy.getLongestMatch(item, _items, this));
668     }
669   }
670
671   /**
672    * Get matching items.
673    * @return list of matching items
674    */

675   public List JavaDoc<T> getMatchingItems() {
676     return new ArrayList JavaDoc<T>(_matchingItems);
677   }
678
679   /**
680    * Returns the shared mask extension.
681    * The shared mask extension is the string that can be added to the mask such that the list of
682    * matching strings does not change.
683    * @return shared mask extension
684    */

685   public String JavaDoc getSharedMaskExtension() {
686     return _strategy.getSharedMaskExtension(_matchingItems, this);
687   }
688
689   /**
690    * Extends the mask. This operation can only narrow the list of matching strings and is thus faster than
691    * setting the mask.
692    * @param extension string to append to mask
693    */

694   public void extendMask(String JavaDoc extension) {
695     _mask = _mask + extension;
696     updateMatchingStrings(_matchingItems);
697   }
698   
699
700   /**
701    * Extends the mask by the shared string.
702    */

703   public void extendSharedMask() {
704     _mask = _strategy.getExtendedSharedMask(_matchingItems, this);
705     updateMatchingStrings(_matchingItems);
706   }
707 }
708
Popular Tags