KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > ext > html > HTMLCompletionQuery


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.html;
21
22 import org.netbeans.editor.ext.html.parser.SyntaxElement;
23 import java.awt.Component JavaDoc;
24 import java.awt.Font JavaDoc;
25 import java.awt.Graphics JavaDoc;
26 import java.io.IOException JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.util.*;
29 import java.awt.Color JavaDoc;
30 import java.awt.event.KeyEvent JavaDoc;
31 import javax.swing.Action JavaDoc;
32 import javax.swing.text.JTextComponent JavaDoc;
33 import javax.swing.text.BadLocationException JavaDoc;
34 import javax.swing.text.Caret JavaDoc;
35 import javax.swing.text.Document JavaDoc;
36 import org.netbeans.editor.*;
37 import org.netbeans.editor.SettingsUtil;
38 import org.netbeans.editor.Utilities;
39 import org.netbeans.editor.ext.*;
40 import org.netbeans.editor.ext.html.dtd.*;
41 import org.netbeans.editor.ext.html.javadoc.HelpManager;
42 import org.netbeans.api.editor.completion.Completion;
43 import org.netbeans.api.html.lexer.HTMLTokenId;
44 import org.netbeans.api.lexer.Token;
45 import org.netbeans.api.lexer.TokenHierarchy;
46 import org.netbeans.api.lexer.TokenId;
47 import org.netbeans.api.lexer.TokenSequence;
48 import org.netbeans.spi.editor.completion.CompletionDocumentation;
49 import org.netbeans.spi.editor.completion.CompletionItem;
50 import org.netbeans.spi.editor.completion.CompletionResultSet;
51 import org.netbeans.spi.editor.completion.CompletionTask;
52 import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery;
53 import org.netbeans.spi.editor.completion.support.AsyncCompletionTask;
54 import org.openide.ErrorManager;
55
56 /**
57  * HTML completion results finder
58  *
59  * @author Petr Nejedly
60  * @author Marek Fukala
61  * @version 1.10
62  */

63 public class HTMLCompletionQuery implements CompletionQuery {
64     
65     private static boolean lowerCase;
66     
67     private static final HTMLCompletionQuery DEFAULT = new HTMLCompletionQuery();
68     
69     public static HTMLCompletionQuery getDefault() {
70         return DEFAULT;
71     }
72     
73     /** Perform the query on the given component. The query usually
74      * gets the component's document, the caret position and searches back
75      * to examine surrounding context. Then it returns the result.
76      * @param component the component to use in this query.
77      * @param offset position in the component's document to which the query will
78      * be performed. Usually it's a caret position.
79      * @param support syntax-support that will be used during resolving of the query.
80      * @return result of the query or null if there's no result.
81      */

82     public CompletionQuery.Result query(JTextComponent JavaDoc component, int offset, SyntaxSupport support) {
83         Class JavaDoc kitClass = Utilities.getKitClass(component);
84         BaseDocument doc = (BaseDocument)component.getDocument();
85         return query(component, kitClass, doc, offset, support);
86     }
87     
88     CompletionQuery.Result query(JTextComponent JavaDoc component, Class JavaDoc kitClass, BaseDocument doc, int offset, SyntaxSupport support) {
89         if (kitClass != null) {
90             lowerCase = SettingsUtil.getBoolean(kitClass,
91                     HTMLSettingsNames.COMPLETION_LOWER_CASE,
92                     HTMLSettingsDefaults.defaultCompletionLowerCase);
93         }
94         
95         if( doc.getLength() == 0 ) return null; // nothing to examine
96
HTMLSyntaxSupport sup = (HTMLSyntaxSupport)support.get(HTMLSyntaxSupport.class);
97         if( sup == null ) return null;// No SyntaxSupport for us, no hint for user
98

99         DTD dtd = sup.getDTD();
100         if( dtd == null ) return null; // We have no knowledge about the structure!
101

102         doc.readLock();
103         try {
104             TokenHierarchy hi = TokenHierarchy.get(doc);
105             TokenSequence ts = hi.tokenSequence(HTMLTokenId.language());
106             if(ts == null) {
107                 //HTML language is not top level one
108
ts = hi.tokenSequence();
109                 ts.move(offset);
110                 if (ts.moveNext() || ts.movePrevious()) {
111                     ts = ts.embedded(HTMLTokenId.language());
112                 } else { // no tokens
113
return null;
114                 }
115             }
116             
117             if(ts == null) {
118                 //no HTML token on the offset
119
return null;
120             }
121             
122             int diff = ts.move(offset);
123             if(!ts.moveNext() && !ts.movePrevious()) {
124                 return null; //no token found
125
}
126             
127             Token item = ts.token();
128             
129             // are we inside token or between tokens
130
boolean inside = ts.offset() < offset;
131             
132             if(!inside) { //use the previous token
133
if(ts.movePrevious()) {
134                     item = ts.token();
135                 } else {
136                     return null; //no previous token - shouldn't happen
137
}
138             }
139             
140             Token tok = item;
141             //scan the token chain before the
142
while(!(tok.id() == HTMLTokenId.TAG_OPEN || tok.id() == HTMLTokenId.TAG_CLOSE) && ts.movePrevious()) {
143                 tok = ts.token();
144             }
145             
146             //we found an open or close tag or encountered beginning of the file
147
if(ts.index() > 0) {
148                 //found the tag
149
String JavaDoc tagName = tok.text().toString();
150                 for(int i = 0;i < tagName.length(); i++) {
151                     char ch = tagName.charAt(i);
152                     if(Character.isLetter(ch)) {
153                         lowerCase = !Character.isUpperCase(tagName.charAt(i));
154                         break;
155                     }
156                 }
157             } //else use the setting value
158

159             //rewind token sequence back
160
ts.move(item.offset(hi));
161             
162             //get text before cursor
163
int itemOffset = item.offset(hi);
164             String JavaDoc preText = item.text().toString().substring( 0, offset - itemOffset );
165             TokenId id = item.id();
166             
167             List result = null;
168             int len = 1;
169             
170             /* Character reference finder */
171             if( (id == HTMLTokenId.TEXT || id == HTMLTokenId.VALUE) && preText.endsWith( "&" ) ) { // NOI18N
172
result = translateCharRefs( offset-len, len, dtd.getCharRefList( "" ) );
173             } else if( id == HTMLTokenId.CHARACTER ) {
174                 if( inside || !preText.endsWith( ";" ) ) { // NOI18N
175
len = offset - itemOffset;
176                     result = translateCharRefs( offset-len, len, dtd.getCharRefList( preText.substring(1) ) );
177                 }
178                 /* Tag finder */
179             } else if( id == HTMLTokenId.TAG_OPEN) { // NOI18N
180
len = offset - itemOffset + 1; // minus the < char length
181
result = translateTags( itemOffset -1 , len, dtd.getElementList( preText ) );
182                 
183                 //test whether there is only one item in the CC list
184
if(result.size() == 1) {
185                     //test whether the CC is trying to complete an already COMPLETE token - the problematic situation
186
TagItem ti = (TagItem)result.get(0); //there should only one item
187
String JavaDoc itemText = ti.getItemText();
188                     //itemText = itemText.substring(1, itemText.length() - 1); //remove the < > from the tag name
189

190                     if(preText.equals(itemText)) {
191                         //now I have to look ahead to get know whether
192
//there are some attributes or an end of the tag
193

194                         ts.move(offset);
195                         ts.moveNext();
196                         Token t = ts.token();
197                         
198                         //test if next token is a whitespace and the next a tag token or an attribute token
199
if(t.id() == HTMLTokenId.WS) {
200                             if(ts.moveNext()) {
201                                 t = ts.token();
202                                 if((t.id() == HTMLTokenId.TAG_CLOSE || t.id() == HTMLTokenId.ARGUMENT )) {
203                                     //do not put the item into CC - otherwise it will break the completed tag
204
result = null;
205                                 }
206                             }
207                         }
208                     }
209                 }
210                 
211                 
212             } else if( id != HTMLTokenId.BLOCK_COMMENT && preText.endsWith( "<" ) ) { // NOI18N
213
// There will be lookup for possible StartTags, in SyntaxSupport
214
// l = translateTags( offset-len, len, sup.getPossibleStartTags ( offset-len, "" ) );
215
result = translateTags( offset-len, len, dtd.getElementList( "" ) );
216                 
217                 /* EndTag finder */
218             } else if( id == HTMLTokenId.TEXT && preText.endsWith( "</" ) ) { // NOI18N
219
len = 2;
220                 result = sup.getPossibleEndTags( offset, "" );
221             } else if( id == HTMLTokenId.TAG_OPEN_SYMBOL && preText.endsWith( "</" ) ) { // NOI18N
222
len = 2;
223                 result = sup.getPossibleEndTags( offset, "" );
224             } else if( id == HTMLTokenId.TAG_CLOSE) { // NOI18N
225
len = offset - itemOffset;
226                 result = sup.getPossibleEndTags( offset, preText);
227                 
228                 /*Argument finder */
229             /* TBD: It is possible to have arg just next to quoted value of previous
230              * arg, these rules doesn't match start of such arg this case because
231              * of need for matching starting quote
232              */

233             } else if(id == HTMLTokenId.TAG_CLOSE_SYMBOL) {
234                 result = sup.getAutocompletedEndTag(offset);
235                 
236             } else if( id == HTMLTokenId.WS || id == HTMLTokenId.ARGUMENT ) {
237                 SyntaxElement elem = null;
238                 try {
239                     elem = sup.getElementChain( offset );
240                     // #BUGFIX 25261 At the end of document the element is
241
// automatically null but that does not mean that the
242
// completion should return null. Only if element is null
243
// also for offset-1...
244
// + bugfix of #52909 - the > is recognized as SyntaxElement.TAG so we need to
245
// get a syntax element before, when cc is called before > in a tag e.g. <table w|>
246
if (elem == null || (elem.getType() == SyntaxElement.TYPE_TAG && ">".equals(elem.getText())) ) { // NOI18N
247
elem = sup.getElementChain( offset - 1 );
248                     }
249                     
250                 } catch( BadLocationException JavaDoc e ) {
251                     return null;
252                 }
253                 
254                 if( elem == null ) return null;
255                 
256                 if( elem.getType() == SyntaxElement.TYPE_TAG ) { // not endTags
257
SyntaxElement.Tag tagElem = (SyntaxElement.Tag)elem;
258                     
259                     String JavaDoc tagName = tagElem.getName().toUpperCase();
260                     DTD.Element tag = dtd.getElement( tagName );
261                     
262                     if( tag == null ) return null; // unknown tag
263

264                     String JavaDoc prefix = (id == HTMLTokenId.ARGUMENT) ? preText : "";
265                     len = prefix.length();
266                     List possible = tag.getAttributeList( prefix ); // All attribs of given tag
267
Collection<SyntaxElement.TagAttribute> existing = tagElem.getAttributes(); // Attribs already used
268

269                     String JavaDoc wordAtCursor = (item == null) ? null : item.text().toString();
270                     // #BUGFIX 25261 because of being at the end of document the
271
// wordAtCursor must be checked for null to prevent NPE
272
// below
273
if (wordAtCursor == null) {
274                         wordAtCursor = "";
275                     }
276                     
277                     result = new ArrayList();
278                     for( Iterator i = possible.iterator(); i.hasNext(); ) {
279                         DTD.Attribute attr = (DTD.Attribute)i.next();
280                         String JavaDoc aName = attr.getName();
281                         if( aName.equals( prefix )
282                         || (!existing.contains( aName.toUpperCase()) && !existing.contains( aName.toLowerCase()))
283                         || (wordAtCursor.equals( aName ) && prefix.length() > 0))
284                             result.add( attr );
285                     }
286                     result = translateAttribs( offset-len, len, result, tag );
287                 }
288                 
289                 /* Value finder */
290             /* Suggestion - find special-meaning attributes ( IMG src, A href,
291              * color,.... - may be better resolved by attr type, may be moved
292              * to propertysheet
293              */

294             } else if( id == HTMLTokenId.VALUE || id == HTMLTokenId.OPERATOR || id == HTMLTokenId.WS ) {
295                 
296                 if(id == HTMLTokenId.WS) {
297                     //is the token before an operator? '<div color= |red>'
298
ts.move(item.offset(hi));
299                     ts.movePrevious();
300                     Token t = ts.token();
301                     if(t.id() != HTMLTokenId.OPERATOR) {
302                         return null;
303                     }
304                 }
305                 
306                 SyntaxElement elem = null;
307                 try {
308                     elem = sup.getElementChain( offset );
309                 } catch( BadLocationException JavaDoc e ) {
310                     return null;
311                 }
312                 
313                 if( elem == null ) return null;
314                 
315                 // between Tag and error - common state when entering OOTL, e.g. <BDO dir=>
316
if( elem.getType() == SyntaxElement.TYPE_ERROR ) {
317                     elem = elem.getPrevious();
318                     if( elem == null ) return null;
319                 }
320                 if( elem.getType() == SyntaxElement.TYPE_TAG ) {
321                     SyntaxElement.Tag tagElem = (SyntaxElement.Tag)elem;
322                     
323                     String JavaDoc tagName = tagElem.getName().toUpperCase();
324                     DTD.Element tag = dtd.getElement( tagName );
325                     if( tag == null ) return null; // unknown tag
326

327                     ts.move(item.offset(hi));
328                     ts.moveNext();
329                     Token argItem = ts.token();
330                     while(argItem.id() != HTMLTokenId.ARGUMENT && ts.movePrevious()) {
331                         argItem = ts.token();
332                     }
333                     
334                     if(argItem.id() != HTMLTokenId.ARGUMENT) return null; // no ArgItem
335

336                     String JavaDoc argName = argItem.text().toString().toLowerCase();
337                     
338                     DTD.Attribute arg = tag.getAttribute( argName );
339                     if( arg == null || arg.getType() != DTD.Attribute.TYPE_SET ) return null;
340                     
341                     if( id != HTMLTokenId.VALUE ) {
342                         len = 0;
343                         result = translateValues( offset-len, len, arg.getValueList( "" ) );
344                     } else {
345                         len = offset - itemOffset;
346                         
347                         String JavaDoc quotationChar = null;
348                         if(preText != null && preText.length() > 0) {
349                             if(preText.substring(0,1).equals("'")) quotationChar = "'"; // NOI18N
350
if(preText.substring(0,1).equals("\"")) quotationChar = "\""; // NOI18N
351
}
352                         
353                         result = translateValues( offset-len, len, arg.getValueList( quotationChar == null ? preText : preText.substring(1)) , quotationChar );
354                     }
355                 }
356             }
357             
358             //System.err.println("l = " + l );
359
if( result == null ) return null;
360             else return new HTMLCompletionResult( component, "Results for DOCTYPE " + dtd.getIdentifier(), result, offset, len ); // NOI18N
361

362         } catch (BadLocationException JavaDoc ble) {
363             ErrorManager.getDefault().notify(ble);
364         } finally {
365             doc.readUnlock();
366         }
367         
368         return null;
369     }
370     
371     
372     List translateCharRefs( int offset, int length, List refs ) {
373         List result = new ArrayList( refs.size() );
374         String JavaDoc name;
375         for( Iterator i = refs.iterator(); i.hasNext(); ) {
376             name = ((DTD.CharRef)i.next()).getName();
377             result.add( new CharRefItem( name , offset, length, name ));
378         }
379         return result;
380     }
381     
382     List translateTags( int offset, int length, List tags ) {
383         List result = new ArrayList( tags.size() );
384         String JavaDoc name;
385         for( Iterator i = tags.iterator(); i.hasNext(); ) {
386             name = ((DTD.Element)i.next()).getName();
387             result.add( new TagItem( name , offset, length, name ));
388         }
389         return result;
390     }
391     
392     List translateAttribs( int offset, int length, List attribs, DTD.Element tag ) {
393         List result = new ArrayList( attribs.size() );
394         String JavaDoc tagName = tag.getName() + "#"; // NOI18N
395
for( Iterator i = attribs.iterator(); i.hasNext(); ) {
396             DTD.Attribute attrib = (DTD.Attribute)i.next();
397             String JavaDoc name = attrib.getName();
398             switch( attrib.getType() ) {
399                 case DTD.Attribute.TYPE_BOOLEAN:
400                     result.add( new BooleanAttribItem( name, offset, length, attrib.isRequired(), tagName+name ) );
401                     break;
402                 case DTD.Attribute.TYPE_SET:
403                     result.add( new SetAttribItem( name, offset, length, attrib.isRequired(), tagName+name ) );
404                     break;
405                 case DTD.Attribute.TYPE_BASE:
406                     result.add( new PlainAttribItem( name, offset, length, attrib.isRequired(), tagName+name ) );
407                     break;
408             }
409         }
410         return result;
411     }
412     
413     List translateValues( int offset, int length, List values ) {
414         return translateValues(offset, length, values, null);
415     }
416     
417     List translateValues( int offset, int length, List values, String JavaDoc quotationChar ) {
418         if( values == null ) return new ArrayList( 0 );
419         List result = new ArrayList( values.size() );
420         for( Iterator i = values.iterator(); i.hasNext(); ) {
421             result.add( new ValueItem(((DTD.Value)i.next()).getName(), offset, length, quotationChar ));
422         }
423         return result;
424     }
425     
426     
427     // Implementation of ResultItems for completion
428
/** The simple result item operating over an instance of the string,
429      * it is lightweight in the mean it doesn't allocate any new instances
430      * of anything and every data creates lazily on request to avoid
431      * creation of lot of string instances per completion result.
432      */

433     public static abstract class HTMLResultItem implements CompletionQuery.ResultItem,
434             CompletionItem {
435         
436         /** The String on which is this ResultItem defined */
437         String JavaDoc baseText;
438         /** the remove and insert point for this item */
439         int offset;
440         /** The length of the text to be removed */
441         int length;
442         
443         String JavaDoc helpID;
444         
445         boolean shift = false;
446         
447         private HTMLCompletionResultItemPaintComponent component;
448         
449         private static final int HTML_ITEMS_SORT_PRIORITY = 20;
450         
451         public HTMLResultItem( String JavaDoc baseText, int offset, int length ) {
452             this.baseText = lowerCase ? baseText.toLowerCase() : baseText.toUpperCase();
453             this.offset = offset;
454             this.length = length;
455             this. helpID = null;
456         }
457         
458         public HTMLResultItem( String JavaDoc baseText, int offset, int length, String JavaDoc helpID ) {
459             this(baseText, offset, length);
460             this.helpID = helpID;
461         }
462         
463         //-------------
464
protected int selectionStartOffset = -1;
465         protected int selectionEndOffset = -1;
466         
467         public int getSortPriority() {
468             return HTML_ITEMS_SORT_PRIORITY;
469         }
470         public CharSequence JavaDoc getSortText() {
471             return HTMLResultItem.this.getItemText();
472         }
473         
474         public CharSequence JavaDoc getInsertPrefix() {
475             return getItemText();
476         }
477         
478         public Component JavaDoc getPaintComponent(boolean isSelected) {
479             //TODO: the paint component should be caches somehow
480
HTMLCompletionResultItemPaintComponent component = new HTMLCompletionResultItemPaintComponent.StringPaintComponent(getPaintColor());
481             component.setSelected(isSelected);
482             component.setString(getItemText());
483             return component;
484         }
485         
486         public int getPreferredWidth(Graphics JavaDoc g, Font JavaDoc defaultFont) {
487             Component JavaDoc renderComponent = getPaintComponent(false);
488             return renderComponent.getPreferredSize().width;
489         }
490         
491         public void render(Graphics JavaDoc g, Font JavaDoc defaultFont, Color JavaDoc defaultColor,
492                 Color JavaDoc backgroundColor, int width, int height, boolean selected) {
493             Component JavaDoc renderComponent = getPaintComponent(selected);
494             renderComponent.setFont(defaultFont);
495             renderComponent.setForeground(defaultColor);
496             renderComponent.setBackground(backgroundColor);
497             renderComponent.setBounds(0, 0, width, height);
498             ((HTMLCompletionResultItemPaintComponent)renderComponent).paintComponent(g);
499         }
500         
501         protected Object JavaDoc getAssociatedObject() {
502             return getItemText();
503         }
504         
505         public static final String JavaDoc COMPLETION_SUBSTITUTE_TEXT= "completion-substitute-text"; //NOI18N
506

507         static int substituteOffset = -1;
508         
509         public int getSubstituteOffset() {
510             return substituteOffset;
511         }
512         
513         public boolean instantSubstitution(JTextComponent JavaDoc c) {
514             defaultAction(c);
515             return true;
516         }
517         
518         public CompletionTask createDocumentationTask() {
519             return new AsyncCompletionTask(new DocQuery(this));
520         }
521         
522         public CompletionTask createToolTipTask() {
523             return null;
524         }
525         
526         public int getImportance() {
527             return 0;
528         }
529         
530         public void processKeyEvent(KeyEvent JavaDoc e) {
531             shift = (e.getKeyCode() == KeyEvent.VK_ENTER && e.getID() == KeyEvent.KEY_PRESSED && e.isShiftDown());
532         }
533         
534         public void defaultAction(JTextComponent JavaDoc component) {
535             int substOffset = getSubstituteOffset();
536             if (substOffset == -1)
537                 substOffset = component.getCaretPosition();
538             
539             if(!shift) Completion.get().hideAll();
540             substituteText(component, substOffset, component.getCaretPosition() - substOffset, shift);
541         }
542         
543         boolean replaceText( JTextComponent JavaDoc component, String JavaDoc text ) {
544             BaseDocument doc = (BaseDocument)component.getDocument();
545             doc.atomicLock();
546             try {
547                 //test whether we are trying to insert sg. what is already present in the text
548
String JavaDoc currentText = doc.getText(offset, (doc.getLength() - offset) < text.length() ? (doc.getLength() - offset) : text.length()) ;
549                 if(!text.equals(currentText)) {
550                     //remove common part
551
doc.remove( offset, length );
552                     doc.insertString( offset, text, null);
553                 } else {
554                     int newCaretPos = component.getCaret().getDot() + text.length() - length;
555                     //#82242 workaround - the problem is that in some situations
556
//1) result item is created and it remembers the remove length
557
//2) document is changed
558
//3) RI is substituted.
559
//this situation shouldn't happen imho and is a problem of CC infrastructure
560
component.setCaretPosition(newCaretPos < doc.getLength() ? newCaretPos : doc.getLength());
561                 }
562             } catch( BadLocationException JavaDoc exc ) {
563                 return false; //not sucessfull
564
} finally {
565                 doc.atomicUnlock();
566             }
567             return true;
568         }
569         
570         protected void reformat(JTextComponent JavaDoc component, String JavaDoc text) {
571             //does nothing by default; is overriden in EndTag
572
}
573         
574         public boolean substituteCommonText( JTextComponent JavaDoc c, int a, int b, int subLen ) {
575             String JavaDoc text = getItemText().substring( 0, subLen );
576             boolean replaced = replaceText( c, text);
577             reformat(c, text);
578             return replaced;
579         }
580         
581         public boolean substituteText( JTextComponent JavaDoc c, int a, int b, boolean shift ) {
582             String JavaDoc text = getItemText();
583             boolean replaced = replaceText( c, text );
584             reformat(c, text);
585             return replaced;
586         }
587         
588         /** @return Properly colored JLabel with text gotten from <CODE>getPaintText()</CODE>. */
589         public Component JavaDoc getPaintComponent(javax.swing.JList JavaDoc list, boolean isSelected, boolean cellHasFocus) {
590             Component JavaDoc ret = getPaintComponent(isSelected);
591             if (ret==null) return null;
592             if (isSelected) {
593                 ret.setBackground(list.getSelectionBackground());
594                 ret.setForeground(list.getSelectionForeground());
595             } else {
596                 ret.setBackground(list.getBackground());
597                 ret.setForeground(list.getForeground());
598             }
599             ret.getAccessibleContext().setAccessibleName(getItemText());
600             ret.getAccessibleContext().setAccessibleDescription(getItemText());
601             return ret;
602         }
603         
604         /** The string used in painting by <CODE>getPaintComponent()</CODE>.
605          * It defaults to delegate to <CODE>getItemText()</CODE>.
606          * @return The String to be painted in Completion View.
607          */

608         String JavaDoc getPaintText() { return getItemText(); }
609         
610         abstract Color JavaDoc getPaintColor();
611         
612         /** @return The String used for looking up the common part of multiple
613          * items and for default way of replacing the text */

614         public String JavaDoc getItemText() { return baseText; }
615         
616         public String JavaDoc getHelpID() { return helpID; }
617         
618         public String JavaDoc toString() {
619             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
620             String JavaDoc className = this.getClass().getName();
621             className = className.substring(className.lastIndexOf('.') + 1); //cut off the package
622
sb.append(className);
623             sb.append('(');
624             sb.append(getItemText());
625             sb.append(';');
626             sb.append(getSubstituteOffset());
627             sb.append(';');
628             sb.append(getHelpID());
629             sb.append(')');
630             
631             return sb.toString();
632         }
633         
634     }
635     
636     public static class AutocompleteEndTagItem extends EndTagItem {
637         public AutocompleteEndTagItem(String JavaDoc baseText, int offset) {
638             this(baseText, offset, true);
639         }
640         
641         public AutocompleteEndTagItem(String JavaDoc baseText, int offset, boolean changeCase) {
642             super(baseText, offset, 0);
643             if(!changeCase) {
644                 this.baseText = baseText; //#87218 hotfix - set the original value
645
}
646         }
647         
648         @Override JavaDoc()
649         boolean replaceText(JTextComponent JavaDoc component, String JavaDoc text) {
650             boolean replaced = super.replaceText(component, text);
651             if(replaced) {
652                 component.setCaretPosition(offset);
653             }
654             return replaced;
655         }
656         
657         @Override JavaDoc
658                 protected void reformat(JTextComponent JavaDoc component, String JavaDoc text) {
659             try {
660                 BaseDocument doc = (BaseDocument)component.getDocument();
661                 ExtFormatter f = (ExtFormatter)doc.getFormatter();
662                 int dotPos = component.getCaretPosition();
663                 f.reformat(doc, Utilities.getRowStart(doc, dotPos), Utilities.getRowEnd(doc, dotPos), true);
664             }catch(BadLocationException JavaDoc e) {
665                 //ignore
666
}catch(IOException JavaDoc ioe) {
667                 //ignore
668
}
669         }
670         
671         @Override JavaDoc
672                 public CharSequence JavaDoc getInsertPrefix() {
673             //disable instant substitution
674
return null;
675         }
676         
677     }
678     
679     static class EndTagItem extends HTMLResultItem {
680         
681         private int order = 0;
682         
683         public EndTagItem( String JavaDoc baseText, int offset, int length ) {
684             super( baseText, offset, length );
685         }
686         
687         public EndTagItem( String JavaDoc baseText, int offset, int length, String JavaDoc helpID ) {
688             super( baseText, offset, length, helpID );
689         }
690         
691         public EndTagItem( String JavaDoc baseText, int offset, int length, String JavaDoc helpID, int order ) {
692             this(baseText, offset, length, helpID);
693             this.order = order;
694         }
695         
696         public CharSequence JavaDoc getSortText() {
697             return getSortText(this.order);
698         }
699         
700         private String JavaDoc getSortText(int index) {
701             int zeros = index > 100 ? 0 : index > 10 ? 1 : 2;
702             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
703             for (int i = 0; i < zeros; i++) {
704                 sb.append('0');
705             }
706             sb.append("" + index);
707             return sb.toString();
708         }
709         
710         Color JavaDoc getPaintColor() { return Color.blue; }
711         
712         public String JavaDoc getItemText() { return "</" + baseText + ">"; } // NOI18N
713

714         public boolean substituteText( JTextComponent JavaDoc c, int a, int b, boolean shift ) {
715             return super.substituteText( c, a, b, shift );
716         }
717         
718         @Override JavaDoc
719                 protected void reformat(JTextComponent JavaDoc component, String JavaDoc text) {
720             try {
721                 BaseDocument doc = (BaseDocument)component.getDocument();
722                 ExtFormatter f = (ExtFormatter)doc.getFormatter();
723                 int[] fmtBlk = f.getReformatBlock(component, text);
724                 if (fmtBlk != null) {
725                     fmtBlk[0] = Utilities.getRowStart(doc, fmtBlk[0]);
726                     fmtBlk[1] = Utilities.getRowEnd(doc, fmtBlk[1]);
727                     f.reformat(doc, fmtBlk[0], fmtBlk[1], true);
728                 }
729             }catch(BadLocationException JavaDoc e) {
730                 //ignore
731
}catch(IOException JavaDoc ioe) {
732                 //ignore
733
}
734         }
735         
736     }
737     
738     private static class CharRefItem extends HTMLResultItem {
739         
740         public CharRefItem( String JavaDoc name, int offset, int length ) {
741             super( name, offset, length );
742             this.baseText = name;
743         }
744         
745         public CharRefItem( String JavaDoc name, int offset, int length, String JavaDoc helpID ) {
746             super( name, offset, length, helpID );
747             this.baseText = name;
748         }
749         
750         Color JavaDoc getPaintColor() { return Color.red.darker(); }
751         
752         public CharSequence JavaDoc getSortText() {
753             String JavaDoc itext = getItemText();
754             return itext.endsWith(";") ? itext.substring(0, itext.length() - 1) : itext;
755         }
756         
757         public String JavaDoc getItemText() { return "&" + baseText + ";"; } // NOI18N
758
}
759     
760     private static class TagItem extends HTMLResultItem {
761         
762         public TagItem( String JavaDoc name, int offset, int length ) {
763             super( name, offset, length );
764         }
765         
766         public TagItem( String JavaDoc name, int offset, int length, String JavaDoc helpID ) {
767             super( name, offset, length, helpID );
768         }
769         
770         public boolean substituteText( JTextComponent JavaDoc c, int a, int b, boolean shift ) {
771             replaceText( c, "<" + baseText + (shift ? " >" : ">") ); // NOI18N
772
if( shift ) {
773                 Caret JavaDoc caret = c.getCaret();
774                 caret.setDot( caret.getDot() - 1 );
775             }
776             Completion.get().showCompletion(); //show the completion to possibly offer an end tag (end tag autocompletion feature)
777
return !shift; // flag == false;
778
}
779         
780         Color JavaDoc getPaintColor() { return Color.blue; }
781         
782         public String JavaDoc getItemText() {
783             return "<" + baseText + ">";
784         } // NOI18N
785
}
786     
787     private static class SetAttribItem extends HTMLResultItem {
788         boolean required;
789         
790         public SetAttribItem( String JavaDoc name, int offset, int length, boolean required ) {
791             super( name, offset, length );
792             this.required = required;
793         }
794         
795         public SetAttribItem( String JavaDoc name, int offset, int length, boolean required, String JavaDoc helpID ) {
796             super( name, offset, length, helpID );
797             this.required = required;
798         }
799         
800         Color JavaDoc getPaintColor() { return required ? Color.red : Color.green.darker(); }
801         
802         String JavaDoc getPaintText() { return baseText; }
803         
804         public String JavaDoc getItemText() { return baseText; } //NOI18N
805

806         public boolean substituteText( JTextComponent JavaDoc c, int a, int b, boolean shift ) {
807             replaceText( c, baseText + "=\"\"" ); //NOI18N
808
Caret JavaDoc caret = c.getCaret();
809             caret.setDot( caret.getDot() - 1 );
810             
811             return false; // always refresh
812
}
813     }
814     
815     private static class BooleanAttribItem extends HTMLResultItem {
816         
817         boolean required;
818         
819         public BooleanAttribItem( String JavaDoc name, int offset, int length, boolean required ) {
820             super( name, offset, length );
821             this.required = required;
822         }
823         
824         public BooleanAttribItem( String JavaDoc name, int offset, int length, boolean required, String JavaDoc helpID) {
825             super( name, offset, length, helpID );
826             this.required = required;
827         }
828         
829         Color JavaDoc getPaintColor() { return required ? Color.red : Color.green.darker(); }
830         
831         
832         public boolean substituteText( JTextComponent JavaDoc c, int a, int b, boolean shift ) {
833             replaceText( c, shift ? baseText + " " : baseText ); // NOI18N
834
return false; // always refresh
835
}
836     }
837     
838     private static class PlainAttribItem extends HTMLResultItem {
839         
840         boolean required;
841         
842         public PlainAttribItem( String JavaDoc name, int offset, int length, boolean required ) {
843             super( name, offset, length );
844             this.required = required;
845         }
846         
847         public PlainAttribItem( String JavaDoc name, int offset, int length, boolean required, String JavaDoc helpID ) {
848             super( name, offset, length, helpID );
849             this.required = required;
850         }
851         
852         Color JavaDoc getPaintColor() { return required ? Color.red : Color.green.darker(); }
853         
854         public boolean substituteText( JTextComponent JavaDoc c, int a, int b, boolean shift ) {
855             replaceText( c, baseText + "=\"\"" ); //NOI18N
856
Caret JavaDoc caret = c.getCaret();
857             caret.setDot( caret.getDot() - 1 );
858             return false; // always refresh
859
}
860     }
861     
862     private static class ValueItem extends HTMLResultItem {
863         
864         private String JavaDoc quotationChar = null;
865         
866         public ValueItem( String JavaDoc name, int offset, int length, String JavaDoc quotationChar) {
867             this(name, offset, length);
868             this.quotationChar = quotationChar;
869         }
870         
871         public ValueItem( String JavaDoc name, int offset, int length ) {
872             super( name, offset, length );
873         }
874         
875         public CharSequence JavaDoc getInsertPrefix() {
876             if(quotationChar == null) {
877                 return super.getInsertPrefix();
878             } else {
879                 return quotationChar + super.getInsertPrefix();
880             }
881         }
882         
883         Color JavaDoc getPaintColor() { return Color.magenta; }
884         
885         public boolean substituteText( JTextComponent JavaDoc c, int a, int b, boolean shift ) {
886             //check whether there is already a " char after the CC offset
887
BaseDocument doc = (BaseDocument)c.getDocument();
888             boolean hasQuote = false;
889             try {
890                 String JavaDoc currentText = doc.getText(c.getCaretPosition(), 1);
891                 hasQuote = "\"".equals(currentText);
892             }catch(BadLocationException JavaDoc ble) {
893                 //do nothing
894
}
895             String JavaDoc quotedText = ((quotationChar == null) ? baseText : quotationChar + baseText + (hasQuote ? "" : quotationChar));
896             replaceText( c, quotedText );
897             return !shift;
898         }
899     }
900     
901     static class DocQuery extends AsyncCompletionQuery {
902         
903         private HTMLResultItem item;
904         
905         DocQuery(HTMLResultItem item) {
906             this.item = item;
907         }
908         
909         protected void query(CompletionResultSet resultSet, Document JavaDoc doc, int caretOffset) {
910             if (item != null &&
911                     item.getHelpID() != null &&
912                     HelpManager.getDefault().findHelpItem(item.getHelpID()) != null) {
913                 resultSet.setDocumentation(new DocItem(item));
914             }
915             resultSet.finish();
916         }
917         
918     }
919     
920     static class LinkDocItem implements CompletionDocumentation {
921         private URL JavaDoc url;
922         
923         public LinkDocItem(URL JavaDoc url) {
924             this.url = url;
925         }
926         
927         public String JavaDoc getText() {
928             return null;
929             /*
930             String anchor = HelpManager.getDefault().getAnchorText(url);
931             if(anchor != null)
932                 return HelpManager.getDefault().getHelpText(url, anchor);
933             else
934                 return HelpManager.getDefault().getHelpText(url);
935              */

936         }
937         
938         public URL JavaDoc getURL() {
939             return url;
940         }
941         
942         public CompletionDocumentation resolveLink(String JavaDoc link) {
943             return new LinkDocItem(HelpManager.getDefault().getRelativeURL(url, link));
944         }
945         
946         public Action JavaDoc getGotoSourceAction() {
947             return null;
948         }
949         
950     }
951     
952     
953     public static class DocItem implements CompletionDocumentation {
954         private String JavaDoc name;
955         
956         public DocItem(HTMLResultItem ri) {
957             this(ri.getHelpID());
958         }
959         
960         public DocItem(String JavaDoc name) {
961             this.name = name;
962         }
963         
964         public String JavaDoc getText() {
965             String JavaDoc help = HelpManager.getDefault().getHelp(name);
966             return help;
967         }
968         
969         public URL JavaDoc getURL() {
970             return HelpManager.getDefault().getHelpURL(name);
971         }
972         
973         public CompletionDocumentation resolveLink(String JavaDoc link) {
974             String JavaDoc currentLink = HelpManager.getDefault().findHelpItem(name).getFile();
975             return new LinkDocItem(HelpManager.getDefault().getRelativeURL(HelpManager.getDefault().getHelpURL(name), link));
976         }
977         
978         public Action JavaDoc getGotoSourceAction() {
979             return null;
980         }
981     }
982     
983     public static class HTMLCompletionResult extends CompletionQuery.DefaultResult {
984         private int substituteOffset;
985         public HTMLCompletionResult(JTextComponent JavaDoc component, String JavaDoc title, List data, int offset, int len ) {
986             super(component, title, data, offset, len);
987             substituteOffset = offset - len;
988         }
989         
990         public int getSubstituteOffset() {
991             return substituteOffset;
992         }
993     }
994     
995 }
996
997
Popular Tags