KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > ext > CompletionQuery


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.editor.ext;
21
22 import java.util.List JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.awt.Color JavaDoc;
25 import java.awt.Component JavaDoc;
26 import javax.swing.JLabel JavaDoc;
27 import javax.swing.JList JavaDoc;
28 import javax.swing.text.Document JavaDoc;
29 import javax.swing.text.JTextComponent JavaDoc;
30 import javax.swing.text.BadLocationException JavaDoc;
31 import org.netbeans.editor.SyntaxSupport;
32 import org.netbeans.editor.BaseDocument;
33 import org.netbeans.lib.editor.util.CharSequenceUtilities;
34 import org.netbeans.lib.editor.util.swing.DocumentUtilities;
35
36 /**
37 * Code completion querying SPI and support.
38 *
39 * @author Miloslav Metelka
40 * @version 1.01
41 */

42
43 public interface CompletionQuery {
44
45     /** Perform the query on the given component. The query usually
46     * gets the component's document, the caret position and searches back
47     * to find the last command start. Then it inspects the text up to the caret
48     * position and returns the result.
49     * <p>Implementations must be thread safe (also reentrant) because it can be
50     * called speculatively from multiple threads. This requirement can be removed in future SPI
51     * by passing additional flag marking speculative query. Skeletal implementation
52     * could handle multithreading based on the flag.
53     * @param component the component to use in this query.
54     * @param offset position in the component's document to which the query will
55     * be performed. Usually it's a caret position.
56     * @param support syntax-support that will be used during resolving of the query.
57     * @return result of the query or null if there's no result.
58     */

59     public Result query(JTextComponent JavaDoc component, int offset, SyntaxSupport support);
60
61     /**
62      * Marker interface that should implement all providers that are
63      * compatible with #13768 semantics. It requires thread safe and reentrant
64      * completion query provider implementation. It's performance gain
65      * to implement as it allows asynchronous speculative queries.
66      *
67      * @deprecated It is a workaround. It's suggested that providers
68      * should wait for new completion query SPI that should better
69      * support speculative queries, partial results, result
70      * cancellation and result narrowing. Implement only if it's simple.
71      *
72      * @since CompletionQuery version 1.01
73      */

74     public interface SupportsSpeculativeInvocation {
75         // marker interface
76
}
77     
78     /** Result of the query or expression evaluation. Simply said it consists
79     * of the list of the data and title and an internal information about
80     * how to substitute the text.
81     */

82     public interface Result {
83
84         /** Get the list with the items satisfying the query. The list
85         * must always be non-null. If there are no data it will have a zero size.
86         * @return List of objects implementing ResultItem.
87         */

88         public List JavaDoc getData();
89
90         /** Get the title describing the result or null if there's no title. */
91         public String JavaDoc getTitle();
92
93         /** Substitute the text in the document if the user picks
94         * the item from the data with the given index either by
95         * pressing ENTER or doubleclicking the item by mouse.
96         * @param dataIndex current selected item index in the current data list.
97         * It can be used for making the substitution.
98         * @param shift indicates request for some kind of different behaviour,
99         * means that e.g. user hold shift while pressing ENTER.
100         * @return whether the text was substituted or not
101         */

102         public boolean substituteText(int dataIndex, boolean shift);
103
104         /** Substitute the text that is common for all the data entries.
105         * This is used to update the document with
106         * the common text when the user presses the TAB key.
107         * @param dataIndex current selected item index in the current data list.
108         * Although normally it shouldn't be necessary for making
109         * the substitution, the completion implementations
110         * can use it for customized behavior.
111         * @return whether the text was substituted or not
112         */

113         public boolean substituteCommonText(int dataIndex);
114
115     }
116
117     /**
118     * The very basic funztionality of Result is implemented by this class,
119     * but parts general enough to not need to be overriden.
120     */

121     public static abstract class AbstractResult implements Result {
122
123         /** The List of the ResultItem instances - the content of the result */
124         private List JavaDoc data;
125
126         /** The title of the result */
127         private String JavaDoc title;
128
129         public AbstractResult(List JavaDoc data, String JavaDoc title) {
130             this.data = data;
131             this.title = title;
132         }
133
134         public List JavaDoc getData() {
135             return data;
136         }
137
138         public String JavaDoc getTitle() {
139             return title;
140         }
141
142     }
143
144     
145     /** Full implementation of Result, managing substitution of the text and
146     * finding and substituting common prefix of items
147     */

148     public static class DefaultResult extends AbstractResult {
149
150         private JTextComponent JavaDoc component;
151         private int offset;
152         private int len;
153
154         /** Constructor for DefaultResult
155         * @param component the JTextComponent the result is tightened with,
156         * used for operations on its Document, caret, selection and so.
157         * @param title the title displayed in header of completion window
158         * @param data the list of ResultItem instances to be displayed in
159         * completion window, may be null.
160         * @param the offset in the document corresponding to the start
161         * of the text occassionally replaced by the result.
162         * @param the length of the text to be replaced.
163         */

164         public DefaultResult(JTextComponent JavaDoc component, String JavaDoc title, List JavaDoc data, int offset, int len ) {
165             super(data, title);
166             this.component = component;
167             this.offset = offset;
168             this.len = len;
169         }
170
171         /** Internal method used to find longest common prefix of two Strings.
172         * it is made private, because I'm going to change its interface
173         * for better performance.
174         */

175         private int getCommonPrefixLength( char[] commonPrefix, int len, String JavaDoc s ) {
176             char[] c = s.toCharArray();
177             int i=0;
178             if( len > c.length ) len = c.length;
179             for( ; i<len; i++ ) {
180                 if( commonPrefix[i] != c[i] ) break;
181             }
182             return i;
183         }
184         
185         /** Update the text in response to pressing TAB key. Searches through
186         * all items of this result looking for longest common prefix and then
187         * calls the substitution method on selected item providing it with
188         * the length of common part.
189         * @return whether the text was successfully updated
190         */

191         public boolean substituteCommonText( int dataIndex ) {
192             List JavaDoc data = getData();
193             if( data.size() == 0 ) return false;
194
195             Iterator JavaDoc i = data.iterator();
196             char[] commonPrefix = ((CompletionQuery.ResultItem)i.next()).getItemText().toCharArray();
197             int commonLength = commonPrefix.length;
198             
199             for( ; i.hasNext(); ) {
200                 String JavaDoc second = ((CompletionQuery.ResultItem)i.next()).getItemText();
201                 commonLength = getCommonPrefixLength( commonPrefix, commonLength, second );
202             }
203             CompletionQuery.ResultItem actData = (CompletionQuery.ResultItem)data.get(dataIndex);
204             return actData.substituteCommonText( component, offset, len, commonLength );
205         }
206
207         
208         /** Update the text in response to pressing ENTER.
209         * @return whether the text was successfully updated
210         */

211         public boolean substituteText(int dataIndex, boolean shift ) {
212             Object JavaDoc actData = getData().get( dataIndex );
213             return ((CompletionQuery.ResultItem)actData).substituteText( component, offset, len, shift );
214         }
215     }
216
217     
218     /** An interface used as an item of List returned by CompletionQuery.Result.getData()
219     * Such items are then able to their part in Completion process themselves
220     */

221     public static interface ResultItem {
222         /** Update the text in response to pressing TAB key (or any key mapped to
223         * this function) on this element
224         * @param c the text component to operate on, enables implementation to
225         * do things like movement of caret.
226         * @param offset the offset where the item should be placed
227         * @param len the length of recognized text which should be replaced
228         * @param subLen the length of common part - the length of text that should
229         * be inserted after removal of recognized text
230         * @return whether the text was successfully updated
231         */

232         public boolean substituteCommonText( JTextComponent JavaDoc c, int offset, int len, int subLen );
233
234         /** Update the text in response to pressing ENTER on this element.
235         * @param c the text component to operate on, enables implementation to
236         * do things like movement of caret.
237         * @param offset the offset where the item should be placed
238         * @param len the length of recognized text which should be replaced
239         * @param shift the flag that instructs completion to behave somehow
240         * differently - enables more kinds of invocation of substituteText
241         * @return whether the text was successfully updated
242         */

243         public boolean substituteText( JTextComponent JavaDoc c, int offset, int len, boolean shift );
244
245         /** Says what text would this Element use if substituteText is called.
246         * @return the substitution text, usable e.g. for finding common text/its' length
247         */

248         public String JavaDoc getItemText();
249
250         /** Prepare proper component for painting value of <CODE>this</CODE>.
251         * @param JList the list this item will be drawn into, usefull e.g. for
252         * obtaining preferred colors.
253         * @param isSelected tells if this item is just selected, for using
254         * proper color scheme.
255         * @param cellHasFocus tells it this item is just focused.
256         * @return the component usable for painting this value
257         */

258         public Component JavaDoc getPaintComponent( JList JavaDoc list, boolean isSelected, boolean cellHasFocus);
259     }
260
261     /**
262      * An interface allowing to obtain
263      * the object carrying the actual data associated with the result item.
264      */

265     public static interface ResultItemAssociatedObject {
266
267         /**
268          * Get the object carrying the actual data associated with the result item
269          */

270         Object JavaDoc getAssociatedObject();
271
272     }
273
274     /** A class providing generic, nearly full implementation of ResultItem
275     */

276     public abstract static class AbstractResultItem implements CompletionQuery.ResultItem {
277         /* The text this item would expand to */
278         protected String JavaDoc text;
279
280         /** Create new ResultItem for given text, should be used in subclass constructors
281         */

282         public AbstractResultItem( String JavaDoc text ) {
283             this.text = text;
284         }
285         
286         /** Generic implementation, behaves just as described in specification
287         * in substituteCommonText() - removes <CODE>len</CODE>
288         * characters at <CODE>offset</CODE> out of document and then inserts
289         * <CODE>subLen<CODE> characters from the <CODE>text</CODE>
290         */

291         public boolean substituteCommonText( JTextComponent JavaDoc c, int offset, int len, int subLen ) {
292             BaseDocument doc = (BaseDocument)c.getDocument();
293             try {
294                 doc.atomicLock();
295                 try {
296                     doc.remove( offset, len );
297                     doc.insertString( offset, text.substring( 0, subLen ), null);
298                 } finally {
299                     doc.atomicUnlock();
300                 }
301             } catch( BadLocationException JavaDoc exc ) {
302                 return false; //not sucessfull
303
}
304             return true;
305         }
306
307         /** Generic implementation, behaves just as described in specification
308         * in substituteText() - removes <CODE>len</CODE> characters
309         * at <CODE>offset</CODE> out of document and then inserts
310         * whole <CODE>text</CODE>. Ignores <CODE>shift</CODE> argument.
311         */

312         public boolean substituteText( JTextComponent JavaDoc c, int offset, int len, boolean shift ) {
313             BaseDocument doc = (BaseDocument)c.getDocument();
314             try {
315                 doc.atomicLock();
316                 try {
317                     CharSequence JavaDoc textToReplace = DocumentUtilities.getText(doc, offset, len);
318                     if (CharSequenceUtilities.textEquals(text, textToReplace)) return false;
319                     doc.remove( offset, len );
320                     doc.insertString( offset, text, null);
321                 } finally {
322                     doc.atomicUnlock();
323                 }
324             } catch( BadLocationException JavaDoc exc ) {
325                 return false; //not sucessfull
326
}
327             return true;
328         }
329
330         /** @return the text this item would expand to.
331         */

332         public String JavaDoc getItemText() {
333             return text;
334         }
335
336     }
337
338     public static class DefaultResultItem extends CompletionQuery.AbstractResultItem {
339         /** The cache for component used for painting value of <CODE>this</CODE>
340         * this component is reused, on every call to getPaintComponent it is
341         * set up and then painted. By default, this component is hold opaque.
342         */

343         static JLabel JavaDoc rubberStamp = new JLabel JavaDoc();
344
345         static {
346             rubberStamp.setOpaque( true );
347         }
348         
349         /** Color used for painting text of non-selected item */
350         protected Color JavaDoc foreColor;
351         
352         public DefaultResultItem( String JavaDoc text, Color JavaDoc foreColor ) {
353             super( text );
354             this.foreColor = foreColor;
355         }
356
357         public Component JavaDoc getPaintComponent( JList JavaDoc list, boolean isSelected, boolean cellHasFocus ) {
358             rubberStamp.setText( " " + text ); // NOI18N
359
if (isSelected) {
360                 rubberStamp.setBackground(list.getSelectionBackground());
361                 rubberStamp.setForeground(list.getSelectionForeground());
362             } else {
363                 rubberStamp.setBackground(list.getBackground());
364                 rubberStamp.setForeground( foreColor );
365             }
366             return rubberStamp;
367         }
368     }
369
370 }
371
Popular Tags