001: package isql;
002:
003: import java.util.*;
004:
005: /** This expander class expands a given word, based on a given data model.
006: * This would typically be used by a Document, but could be used
007: * from anywhere where Tab expansion is required.
008: * This implementation uses a TabModel object which can be customized by
009: * caller.
010: * For convenience, a constructir with a String[] argument has been
011: * created.
012: * Following are examples of usage:
013: * <pre>
014: * // MyTabModel implements TabModel with your custom data structure.
015: * ETabExpander et = ETabExpander(new MyTabModel());
016: * String exp = et.getNextExpansion(pattern);
017: * // or
018: * // myArray would be populated from a file or database
019: * String myArray[] = new String[] {"abc","def", ...};
020: * ETabExpander et = ETabExpander(myArray);
021: * String exp = et.getNextExpansion(pattern);
022: *
023: * // or
024: * ETabExpander et = ETabExpander();
025: * et.setModel(ETabExpander.createTabModel(myArray));
026: * String exp = et.getNextExpansion(pattern);
027: *
028: * </pre>
029: *
030: * @author rahul kumar, 2001 $Author: rahul_kumar $
031: * $Id: ETabExpander.java,v 1.1 2003/12/24 15:15:03 rahul_kumar Exp $
032: */
033: public class ETabExpander implements ITabExpander {
034:
035: /** stores the current word typed by user on which we are tabbing.
036: * We would revert to this word if he doesnt accept any substitution */
037: private String _pattern = null;
038: /** stores all strings used by tab method, set by caller */
039: //String[] _arrCache;
040: /** stores strings matched by last tab, for further tabs by user */
041: //private String[] _arrMatched;
042: /** stores the index in _arrMatched of the last word shown to user
043: */
044: private int _matchedindex = -1;
045: TabModel tm;
046:
047: public ETabExpander(final String[] cache) {
048: this (createTabModel(cache));
049: }
050:
051: /** conveneience method for createing a TabModel based on a String
052: * array. May be used to initialize the Expander if constructed
053: * without parameters, or just for updating model.
054: */
055: public static TabModel createTabModel(final String[] sarr) {
056: return new TabModel() {
057: String[] _arrMatched = null;
058:
059: public int doMatch(String patt) {
060: _arrMatched = getMatches(patt);
061: return _arrMatched.length;
062: }
063:
064: public int matchedCount() {
065: if (_arrMatched == null)
066: return 0;
067: return _arrMatched.length;
068: }
069:
070: public String getMatched(int index) {
071: if (index >= 0 && index <= sarr.length)
072: return sarr[index];
073: return null;
074: }
075:
076: public String[] getMatches() {
077: return _arrMatched;
078: }
079:
080: public String[] getMatches(String patt) {
081: if (sarr == null || sarr.length == 0)
082: return null;
083: List v = new ArrayList();
084: int len = patt.length();
085: for (int i = 0; i < sarr.length; i++) {
086: // check if patt is not longer than array else subst throws
087: // up
088: if (patt.length() <= sarr[i].length()
089: && sarr[i].substring(0, len).equals(patt))
090: v.add(sarr[i]);
091: }
092: String s[] = new String[v.size()];
093: s = (String[]) v.toArray(s);
094: return s;
095:
096: }
097:
098: };
099: }
100:
101: public ETabExpander(TabModel tm) {
102: this .tm = tm;
103: }
104:
105: public ETabExpander() {
106: //this.tm = tm;
107: }
108:
109: public void setModel(TabModel newModel) {
110: TabModel oldModel = tm;
111:
112: if (newModel == null)
113: throw new IllegalArgumentException(
114: "Cannot set a null TabModel");
115:
116: if (newModel != oldModel) {
117: tm = newModel;
118: }
119: }
120:
121: /** returns the installed model, which may be updated by caller.
122: */
123: public TabModel getModel() {
124: return tm;
125: }
126:
127: // does throw a NPE if space followed by tab
128: //
129: /* this is how you would use from a Document
130: public void insertString(int offs, String str, AttributeSet a)
131: throws BadLocationException {
132:
133: String repls;
134: if (str == null || str.length()==0) return;
135: char lc = str.charAt(str.length()-1);
136: // name completion
137: if (lc == '\t'){
138: if (_pattern == null){
139: _pattern = getLastWord(offs, str);
140: if ( (_pattern.length()==1 &&
141: Character.isWhitespace(_pattern.charAt(0))) ){
142: insertString(offs, str, a);
143: System.err.println( "returning" + str);
144: return;
145: }
146: // get the matches for the last word entered
147: previous = next;
148: next = getNextExpansion ( _pattern );
149: if (next == null){
150: _pattern = null;
151: insertString(offs, str, a); // let the entered word go
152: return;
153: }
154: } // there is a last word already, show next one
155:
156: // first time, update string with new word
157: if (previous==null){
158: remove(offs-_pattern.length(),_pattern.length());
159: super.insertString(offs-_pattern.length(), next, null);
160: return;
161: }
162: else
163: // next time update previous replacement with new
164: // one
165: if (next != null){
166: remove(offs-next.length(),previous.length());
167:
168: super.insertString(offs- previous.length(), next, null);
169: return;
170: }
171: else
172: super.insertString(offs, str, a); // replace orig word
173: } // tabbed
174: else
175: // abbreviation - the user entered a whitespace char
176: if (Character.isWhitespace(lc)){
177: String last = getLastWord(offs, str);
178: // get the expansion from abbrev hashtable
179: if ( (repls=(String)htabbr.get(last))!=null){
180: remove(offs-last.length(),last.length());
181: super.insertString(offs-last.length(), repls+lc, ctable);}
182: else
183: super.insertString(offs, str, a);
184: }
185: else
186: // character was not WS char, let things happen
187: // normally
188: super.insertString(offs, str, a);
189: _pattern=null;
190: }
191: */
192: /** searches backwards are returns the last word before the cursor.
193: * Will return a space or tab if there are multiple whitespace
194: * characters.
195: */
196: /*
197: private String getLastWord( int offset, String str) throws BadLocationException{
198: String lastline;
199: int spos = 0;
200: lastline = getText(0, offset);
201:
202: int i = offset -1;
203: while (i-- > spos){
204: if (Character.isWhitespace(lastline.charAt(i)))
205: break;
206: }
207: // i contains the last space
208: i++;
209: if (i<0)i=0; // added since space in beg throws SOB ex
210: return lastline.substring(i);
211: }
212: */
213: /** sets the cache - required at start of program.
214: * This is for backward compatib with earlier programs that used this, a
215: * new developer would use setModel if he used the null constructor.
216: */
217: public void setTabTable(String[] tabs) {
218: setModel(createTabModel(tabs));
219: }
220:
221: /** finds matched strings in the cached array, does a startsWith
222: * and not a equals: ABC will return ABC, ABCD, ABCDE etc.
223: * returns null if no match or if cache not set.
224: */
225: /** expands the given pattern, returning the match at count
226: * position. USer would start with 0, and continue till null is
227: * returned.
228: */
229: public String expand(String patt, int index) {
230: if (patt != _pattern) {
231: _pattern = null;
232: int mcount = tm.doMatch(patt);
233: if (mcount == 0)
234: return null;
235: _pattern = patt;
236: }
237: if (index >= 0 && index <= tm.matchedCount())
238: return (tm.getMatched(index));
239: else
240: return null;
241: }
242:
243: /** returns expansions for a string. Caller would just send in a
244: * string and keep calling this until a null is returned.
245: * Caller would either call getNextExpansion or expand, whatever
246: * suits his needs better.
247: */
248: public String getNextExpansion(String patt) {
249: if (patt != _pattern)
250: _matchedindex = 0;
251: else
252: _matchedindex++;
253:
254: return expand(patt, _matchedindex);
255: }
256:
257: /* ---------
258: if (patt != _pattern){
259: _matchedindex = -1;
260: _pattern = null;
261: _arrCache = getMatches(patt);
262: if (_arrCache != null){
263: _matchedindex = 0;
264: _pattern = patt;
265: return (_arrCache[_matchedindex]);
266: }
267: else
268: return null;
269: }
270: else {
271: _matchedindex++;
272: if (_matchedindex<=_arrMatched.length)
273: return (_arrCache[_matchedindex]);
274: }
275: _matchedindex=-1;
276: _pattern = null;
277: return null;
278: */
279:
280: /** returns all expansions for the previously searched pattern
281: */
282: public String[] getExpansions() {
283: return tm.getMatches();
284: }
285:
286: /** returns expansions for the given string. Has no impact on
287: * existing searches.
288: */
289: public String[] getExpansions(String patt) {
290: return tm.getMatches(patt);
291: }
292:
293: }
|