1 19 20 package org.netbeans.editor.ext.html; 21 22 import org.netbeans.editor.ext.html.parser.SyntaxElement; 23 import java.awt.Component ; 24 import java.awt.Font ; 25 import java.awt.Graphics ; 26 import java.io.IOException ; 27 import java.net.URL ; 28 import java.util.*; 29 import java.awt.Color ; 30 import java.awt.event.KeyEvent ; 31 import javax.swing.Action ; 32 import javax.swing.text.JTextComponent ; 33 import javax.swing.text.BadLocationException ; 34 import javax.swing.text.Caret ; 35 import javax.swing.text.Document ; 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 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 82 public CompletionQuery.Result query(JTextComponent component, int offset, SyntaxSupport support) { 83 Class 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 component, Class 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; HTMLSyntaxSupport sup = (HTMLSyntaxSupport)support.get(HTMLSyntaxSupport.class); 97 if( sup == null ) return null; 99 DTD dtd = sup.getDTD(); 100 if( dtd == null ) return null; 102 doc.readLock(); 103 try { 104 TokenHierarchy hi = TokenHierarchy.get(doc); 105 TokenSequence ts = hi.tokenSequence(HTMLTokenId.language()); 106 if(ts == null) { 107 ts = hi.tokenSequence(); 109 ts.move(offset); 110 if (ts.moveNext() || ts.movePrevious()) { 111 ts = ts.embedded(HTMLTokenId.language()); 112 } else { return null; 114 } 115 } 116 117 if(ts == null) { 118 return null; 120 } 121 122 int diff = ts.move(offset); 123 if(!ts.moveNext() && !ts.movePrevious()) { 124 return null; } 126 127 Token item = ts.token(); 128 129 boolean inside = ts.offset() < offset; 131 132 if(!inside) { if(ts.movePrevious()) { 134 item = ts.token(); 135 } else { 136 return null; } 138 } 139 140 Token tok = item; 141 while(!(tok.id() == HTMLTokenId.TAG_OPEN || tok.id() == HTMLTokenId.TAG_CLOSE) && ts.movePrevious()) { 143 tok = ts.token(); 144 } 145 146 if(ts.index() > 0) { 148 String 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 } 159 ts.move(item.offset(hi)); 161 162 int itemOffset = item.offset(hi); 164 String preText = item.text().toString().substring( 0, offset - itemOffset ); 165 TokenId id = item.id(); 166 167 List result = null; 168 int len = 1; 169 170 171 if( (id == HTMLTokenId.TEXT || id == HTMLTokenId.VALUE) && preText.endsWith( "&" ) ) { result = translateCharRefs( offset-len, len, dtd.getCharRefList( "" ) ); 173 } else if( id == HTMLTokenId.CHARACTER ) { 174 if( inside || !preText.endsWith( ";" ) ) { len = offset - itemOffset; 176 result = translateCharRefs( offset-len, len, dtd.getCharRefList( preText.substring(1) ) ); 177 } 178 179 } else if( id == HTMLTokenId.TAG_OPEN) { len = offset - itemOffset + 1; result = translateTags( itemOffset -1 , len, dtd.getElementList( preText ) ); 182 183 if(result.size() == 1) { 185 TagItem ti = (TagItem)result.get(0); String itemText = ti.getItemText(); 188 190 if(preText.equals(itemText)) { 191 194 ts.move(offset); 195 ts.moveNext(); 196 Token t = ts.token(); 197 198 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 result = null; 205 } 206 } 207 } 208 } 209 } 210 211 212 } else if( id != HTMLTokenId.BLOCK_COMMENT && preText.endsWith( "<" ) ) { result = translateTags( offset-len, len, dtd.getElementList( "" ) ); 216 217 218 } else if( id == HTMLTokenId.TEXT && preText.endsWith( "</" ) ) { len = 2; 220 result = sup.getPossibleEndTags( offset, "" ); 221 } else if( id == HTMLTokenId.TAG_OPEN_SYMBOL && preText.endsWith( "</" ) ) { len = 2; 223 result = sup.getPossibleEndTags( offset, "" ); 224 } else if( id == HTMLTokenId.TAG_CLOSE) { len = offset - itemOffset; 226 result = sup.getPossibleEndTags( offset, preText); 227 228 229 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 if (elem == null || (elem.getType() == SyntaxElement.TYPE_TAG && ">".equals(elem.getText())) ) { elem = sup.getElementChain( offset - 1 ); 248 } 249 250 } catch( BadLocationException e ) { 251 return null; 252 } 253 254 if( elem == null ) return null; 255 256 if( elem.getType() == SyntaxElement.TYPE_TAG ) { SyntaxElement.Tag tagElem = (SyntaxElement.Tag)elem; 258 259 String tagName = tagElem.getName().toUpperCase(); 260 DTD.Element tag = dtd.getElement( tagName ); 261 262 if( tag == null ) return null; 264 String prefix = (id == HTMLTokenId.ARGUMENT) ? preText : ""; 265 len = prefix.length(); 266 List possible = tag.getAttributeList( prefix ); Collection<SyntaxElement.TagAttribute> existing = tagElem.getAttributes(); 269 String wordAtCursor = (item == null) ? null : item.text().toString(); 270 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 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 290 294 } else if( id == HTMLTokenId.VALUE || id == HTMLTokenId.OPERATOR || id == HTMLTokenId.WS ) { 295 296 if(id == HTMLTokenId.WS) { 297 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 e ) { 310 return null; 311 } 312 313 if( elem == null ) return null; 314 315 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 tagName = tagElem.getName().toUpperCase(); 324 DTD.Element tag = dtd.getElement( tagName ); 325 if( tag == null ) return null; 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; 336 String 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 quotationChar = null; 348 if(preText != null && preText.length() > 0) { 349 if(preText.substring(0,1).equals("'")) quotationChar = "'"; if(preText.substring(0,1).equals("\"")) quotationChar = "\""; } 352 353 result = translateValues( offset-len, len, arg.getValueList( quotationChar == null ? preText : preText.substring(1)) , quotationChar ); 354 } 355 } 356 } 357 358 if( result == null ) return null; 360 else return new HTMLCompletionResult( component, "Results for DOCTYPE " + dtd.getIdentifier(), result, offset, len ); 362 } catch (BadLocationException 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 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 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 tagName = tag.getName() + "#"; for( Iterator i = attribs.iterator(); i.hasNext(); ) { 396 DTD.Attribute attrib = (DTD.Attribute)i.next(); 397 String 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 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 433 public static abstract class HTMLResultItem implements CompletionQuery.ResultItem, 434 CompletionItem { 435 436 437 String baseText; 438 439 int offset; 440 441 int length; 442 443 String 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 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 baseText, int offset, int length, String helpID ) { 459 this(baseText, offset, length); 460 this.helpID = helpID; 461 } 462 463 protected int selectionStartOffset = -1; 465 protected int selectionEndOffset = -1; 466 467 public int getSortPriority() { 468 return HTML_ITEMS_SORT_PRIORITY; 469 } 470 public CharSequence getSortText() { 471 return HTMLResultItem.this.getItemText(); 472 } 473 474 public CharSequence getInsertPrefix() { 475 return getItemText(); 476 } 477 478 public Component getPaintComponent(boolean isSelected) { 479 HTMLCompletionResultItemPaintComponent component = new HTMLCompletionResultItemPaintComponent.StringPaintComponent(getPaintColor()); 481 component.setSelected(isSelected); 482 component.setString(getItemText()); 483 return component; 484 } 485 486 public int getPreferredWidth(Graphics g, Font defaultFont) { 487 Component renderComponent = getPaintComponent(false); 488 return renderComponent.getPreferredSize().width; 489 } 490 491 public void render(Graphics g, Font defaultFont, Color defaultColor, 492 Color backgroundColor, int width, int height, boolean selected) { 493 Component 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 getAssociatedObject() { 502 return getItemText(); 503 } 504 505 public static final String COMPLETION_SUBSTITUTE_TEXT= "completion-substitute-text"; 507 static int substituteOffset = -1; 508 509 public int getSubstituteOffset() { 510 return substituteOffset; 511 } 512 513 public boolean instantSubstitution(JTextComponent 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 e) { 531 shift = (e.getKeyCode() == KeyEvent.VK_ENTER && e.getID() == KeyEvent.KEY_PRESSED && e.isShiftDown()); 532 } 533 534 public void defaultAction(JTextComponent 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 component, String text ) { 544 BaseDocument doc = (BaseDocument)component.getDocument(); 545 doc.atomicLock(); 546 try { 547 String currentText = doc.getText(offset, (doc.getLength() - offset) < text.length() ? (doc.getLength() - offset) : text.length()) ; 549 if(!text.equals(currentText)) { 550 doc.remove( offset, length ); 552 doc.insertString( offset, text, null); 553 } else { 554 int newCaretPos = component.getCaret().getDot() + text.length() - length; 555 component.setCaretPosition(newCaretPos < doc.getLength() ? newCaretPos : doc.getLength()); 561 } 562 } catch( BadLocationException exc ) { 563 return false; } finally { 565 doc.atomicUnlock(); 566 } 567 return true; 568 } 569 570 protected void reformat(JTextComponent component, String text) { 571 } 573 574 public boolean substituteCommonText( JTextComponent c, int a, int b, int subLen ) { 575 String 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 c, int a, int b, boolean shift ) { 582 String text = getItemText(); 583 boolean replaced = replaceText( c, text ); 584 reformat(c, text); 585 return replaced; 586 } 587 588 589 public Component getPaintComponent(javax.swing.JList list, boolean isSelected, boolean cellHasFocus) { 590 Component 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 608 String getPaintText() { return getItemText(); } 609 610 abstract Color getPaintColor(); 611 612 614 public String getItemText() { return baseText; } 615 616 public String getHelpID() { return helpID; } 617 618 public String toString() { 619 StringBuffer sb = new StringBuffer (); 620 String className = this.getClass().getName(); 621 className = className.substring(className.lastIndexOf('.') + 1); 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 baseText, int offset) { 638 this(baseText, offset, true); 639 } 640 641 public AutocompleteEndTagItem(String baseText, int offset, boolean changeCase) { 642 super(baseText, offset, 0); 643 if(!changeCase) { 644 this.baseText = baseText; } 646 } 647 648 @Override () 649 boolean replaceText(JTextComponent component, String text) { 650 boolean replaced = super.replaceText(component, text); 651 if(replaced) { 652 component.setCaretPosition(offset); 653 } 654 return replaced; 655 } 656 657 @Override 658 protected void reformat(JTextComponent component, String 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 e) { 665 }catch(IOException ioe) { 667 } 669 } 670 671 @Override 672 public CharSequence getInsertPrefix() { 673 return null; 675 } 676 677 } 678 679 static class EndTagItem extends HTMLResultItem { 680 681 private int order = 0; 682 683 public EndTagItem( String baseText, int offset, int length ) { 684 super( baseText, offset, length ); 685 } 686 687 public EndTagItem( String baseText, int offset, int length, String helpID ) { 688 super( baseText, offset, length, helpID ); 689 } 690 691 public EndTagItem( String baseText, int offset, int length, String helpID, int order ) { 692 this(baseText, offset, length, helpID); 693 this.order = order; 694 } 695 696 public CharSequence getSortText() { 697 return getSortText(this.order); 698 } 699 700 private String getSortText(int index) { 701 int zeros = index > 100 ? 0 : index > 10 ? 1 : 2; 702 StringBuffer sb = new StringBuffer (); 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 getPaintColor() { return Color.blue; } 711 712 public String getItemText() { return "</" + baseText + ">"; } 714 public boolean substituteText( JTextComponent c, int a, int b, boolean shift ) { 715 return super.substituteText( c, a, b, shift ); 716 } 717 718 @Override 719 protected void reformat(JTextComponent component, String 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 e) { 730 }catch(IOException ioe) { 732 } 734 } 735 736 } 737 738 private static class CharRefItem extends HTMLResultItem { 739 740 public CharRefItem( String name, int offset, int length ) { 741 super( name, offset, length ); 742 this.baseText = name; 743 } 744 745 public CharRefItem( String name, int offset, int length, String helpID ) { 746 super( name, offset, length, helpID ); 747 this.baseText = name; 748 } 749 750 Color getPaintColor() { return Color.red.darker(); } 751 752 public CharSequence getSortText() { 753 String itext = getItemText(); 754 return itext.endsWith(";") ? itext.substring(0, itext.length() - 1) : itext; 755 } 756 757 public String getItemText() { return "&" + baseText + ";"; } } 759 760 private static class TagItem extends HTMLResultItem { 761 762 public TagItem( String name, int offset, int length ) { 763 super( name, offset, length ); 764 } 765 766 public TagItem( String name, int offset, int length, String helpID ) { 767 super( name, offset, length, helpID ); 768 } 769 770 public boolean substituteText( JTextComponent c, int a, int b, boolean shift ) { 771 replaceText( c, "<" + baseText + (shift ? " >" : ">") ); if( shift ) { 773 Caret caret = c.getCaret(); 774 caret.setDot( caret.getDot() - 1 ); 775 } 776 Completion.get().showCompletion(); return !shift; } 779 780 Color getPaintColor() { return Color.blue; } 781 782 public String getItemText() { 783 return "<" + baseText + ">"; 784 } } 786 787 private static class SetAttribItem extends HTMLResultItem { 788 boolean required; 789 790 public SetAttribItem( String name, int offset, int length, boolean required ) { 791 super( name, offset, length ); 792 this.required = required; 793 } 794 795 public SetAttribItem( String name, int offset, int length, boolean required, String helpID ) { 796 super( name, offset, length, helpID ); 797 this.required = required; 798 } 799 800 Color getPaintColor() { return required ? Color.red : Color.green.darker(); } 801 802 String getPaintText() { return baseText; } 803 804 public String getItemText() { return baseText; } 806 public boolean substituteText( JTextComponent c, int a, int b, boolean shift ) { 807 replaceText( c, baseText + "=\"\"" ); Caret caret = c.getCaret(); 809 caret.setDot( caret.getDot() - 1 ); 810 811 return false; } 813 } 814 815 private static class BooleanAttribItem extends HTMLResultItem { 816 817 boolean required; 818 819 public BooleanAttribItem( String name, int offset, int length, boolean required ) { 820 super( name, offset, length ); 821 this.required = required; 822 } 823 824 public BooleanAttribItem( String name, int offset, int length, boolean required, String helpID) { 825 super( name, offset, length, helpID ); 826 this.required = required; 827 } 828 829 Color getPaintColor() { return required ? Color.red : Color.green.darker(); } 830 831 832 public boolean substituteText( JTextComponent c, int a, int b, boolean shift ) { 833 replaceText( c, shift ? baseText + " " : baseText ); return false; } 836 } 837 838 private static class PlainAttribItem extends HTMLResultItem { 839 840 boolean required; 841 842 public PlainAttribItem( String name, int offset, int length, boolean required ) { 843 super( name, offset, length ); 844 this.required = required; 845 } 846 847 public PlainAttribItem( String name, int offset, int length, boolean required, String helpID ) { 848 super( name, offset, length, helpID ); 849 this.required = required; 850 } 851 852 Color getPaintColor() { return required ? Color.red : Color.green.darker(); } 853 854 public boolean substituteText( JTextComponent c, int a, int b, boolean shift ) { 855 replaceText( c, baseText + "=\"\"" ); Caret caret = c.getCaret(); 857 caret.setDot( caret.getDot() - 1 ); 858 return false; } 860 } 861 862 private static class ValueItem extends HTMLResultItem { 863 864 private String quotationChar = null; 865 866 public ValueItem( String name, int offset, int length, String quotationChar) { 867 this(name, offset, length); 868 this.quotationChar = quotationChar; 869 } 870 871 public ValueItem( String name, int offset, int length ) { 872 super( name, offset, length ); 873 } 874 875 public CharSequence getInsertPrefix() { 876 if(quotationChar == null) { 877 return super.getInsertPrefix(); 878 } else { 879 return quotationChar + super.getInsertPrefix(); 880 } 881 } 882 883 Color getPaintColor() { return Color.magenta; } 884 885 public boolean substituteText( JTextComponent c, int a, int b, boolean shift ) { 886 BaseDocument doc = (BaseDocument)c.getDocument(); 888 boolean hasQuote = false; 889 try { 890 String currentText = doc.getText(c.getCaretPosition(), 1); 891 hasQuote = "\"".equals(currentText); 892 }catch(BadLocationException ble) { 893 } 895 String 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 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 url; 922 923 public LinkDocItem(URL url) { 924 this.url = url; 925 } 926 927 public String getText() { 928 return null; 929 936 } 937 938 public URL getURL() { 939 return url; 940 } 941 942 public CompletionDocumentation resolveLink(String link) { 943 return new LinkDocItem(HelpManager.getDefault().getRelativeURL(url, link)); 944 } 945 946 public Action getGotoSourceAction() { 947 return null; 948 } 949 950 } 951 952 953 public static class DocItem implements CompletionDocumentation { 954 private String name; 955 956 public DocItem(HTMLResultItem ri) { 957 this(ri.getHelpID()); 958 } 959 960 public DocItem(String name) { 961 this.name = name; 962 } 963 964 public String getText() { 965 String help = HelpManager.getDefault().getHelp(name); 966 return help; 967 } 968 969 public URL getURL() { 970 return HelpManager.getDefault().getHelpURL(name); 971 } 972 973 public CompletionDocumentation resolveLink(String link) { 974 String currentLink = HelpManager.getDefault().findHelpItem(name).getFile(); 975 return new LinkDocItem(HelpManager.getDefault().getRelativeURL(HelpManager.getDefault().getHelpURL(name), link)); 976 } 977 978 public Action getGotoSourceAction() { 979 return null; 980 } 981 } 982 983 public static class HTMLCompletionResult extends CompletionQuery.DefaultResult { 984 private int substituteOffset; 985 public HTMLCompletionResult(JTextComponent component, String 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 |