| 1 7 package javax.swing.text.html; 8 9 import java.lang.reflect.Method ; 10 import java.awt.*; 11 import java.awt.event.*; 12 import java.io.*; 13 import java.net.MalformedURLException ; 14 import java.net.URL ; 15 import javax.swing.text.*; 16 import javax.swing.*; 17 import javax.swing.border.*; 18 import javax.swing.event.*; 19 import javax.swing.plaf.TextUI ; 20 import java.util.*; 21 import javax.accessibility.*; 22 import java.lang.ref.*; 23 24 145 public class HTMLEditorKit extends StyledEditorKit implements Accessible { 146 147 private JEditorPane theEditor; 148 149 153 public HTMLEditorKit() { 154 155 } 156 157 164 public String getContentType() { 165 return "text/html"; 166 } 167 168 175 public ViewFactory getViewFactory() { 176 return defaultFactory; 177 } 178 179 185 public Document createDefaultDocument() { 186 StyleSheet styles = getStyleSheet(); 187 StyleSheet ss = new StyleSheet (); 188 189 ss.addStyleSheet(styles); 190 191 HTMLDocument doc = new HTMLDocument (ss); 192 doc.setParser(getParser()); 193 doc.setAsynchronousLoadPriority(4); 194 doc.setTokenThreshold(100); 195 return doc; 196 } 197 198 216 public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException { 217 218 if (doc instanceof HTMLDocument ) { 219 HTMLDocument hdoc = (HTMLDocument ) doc; 220 Parser p = getParser(); 221 if (p == null) { 222 throw new IOException("Can't load parser"); 223 } 224 if (pos > doc.getLength()) { 225 throw new BadLocationException("Invalid location", pos); 226 } 227 228 ParserCallback receiver = hdoc.getReader(pos); 229 Boolean ignoreCharset = (Boolean )doc.getProperty("IgnoreCharsetDirective"); 230 p.parse(in, receiver, (ignoreCharset == null) ? false : ignoreCharset.booleanValue()); 231 receiver.flush(); 232 } else { 233 super.read(in, doc, pos); 234 } 235 } 236 237 251 public void insertHTML(HTMLDocument doc, int offset, String html, 252 int popDepth, int pushDepth, 253 HTML.Tag insertTag) throws 254 BadLocationException, IOException { 255 Parser p = getParser(); 256 if (p == null) { 257 throw new IOException("Can't load parser"); 258 } 259 if (offset > doc.getLength()) { 260 throw new BadLocationException("Invalid location", offset); 261 } 262 263 ParserCallback receiver = doc.getReader(offset, popDepth, pushDepth, 264 insertTag); 265 Boolean ignoreCharset = (Boolean )doc.getProperty 266 ("IgnoreCharsetDirective"); 267 p.parse(new StringReader(html), receiver, (ignoreCharset == null) ? 268 false : ignoreCharset.booleanValue()); 269 receiver.flush(); 270 } 271 272 285 public void write(Writer out, Document doc, int pos, int len) 286 throws IOException, BadLocationException { 287 288 if (doc instanceof HTMLDocument ) { 289 HTMLWriter w = new HTMLWriter (out, (HTMLDocument )doc, pos, len); 290 w.write(); 291 } else if (doc instanceof StyledDocument) { 292 MinimalHTMLWriter w = new MinimalHTMLWriter (out, (StyledDocument)doc, pos, len); 293 w.write(); 294 } else { 295 super.write(out, doc, pos, len); 296 } 297 } 298 299 305 public void install(JEditorPane c) { 306 c.addMouseListener(linkHandler); 307 c.addMouseMotionListener(linkHandler); 308 c.addCaretListener(nextLinkAction); 309 super.install(c); 310 theEditor = c; 311 } 312 313 320 public void deinstall(JEditorPane c) { 321 c.removeMouseListener(linkHandler); 322 c.removeMouseMotionListener(linkHandler); 323 c.removeCaretListener(nextLinkAction); 324 super.deinstall(c); 325 theEditor = null; 326 } 327 328 332 public static final String DEFAULT_CSS = "default.css"; 333 334 344 public void setStyleSheet(StyleSheet s) { 345 defaultStyles = s; 346 } 347 348 354 public StyleSheet getStyleSheet() { 355 if (defaultStyles == null) { 356 defaultStyles = new StyleSheet (); 357 try { 358 InputStream is = HTMLEditorKit.getResourceAsStream(DEFAULT_CSS); 359 Reader r = new BufferedReader( 360 new InputStreamReader(is, "ISO-8859-1")); 361 defaultStyles.loadRules(r, null); 362 r.close(); 363 } catch (Throwable e) { 364 } 367 } 368 return defaultStyles; 369 } 370 371 381 static InputStream getResourceAsStream(String name) { 382 try { 383 return ResourceLoader.getResourceAsStream(name); 384 } catch (Throwable e) { 385 return HTMLEditorKit .class.getResourceAsStream(name); 388 } 389 } 390 391 399 public Action[] getActions() { 400 return TextAction.augmentList(super.getActions(), this.defaultActions); 401 } 402 403 412 protected void createInputAttributes(Element element, 413 MutableAttributeSet set) { 414 set.removeAttributes(set); 415 set.addAttributes(element.getAttributes()); 416 set.removeAttribute(StyleConstants.ComposedTextAttribute); 417 418 Object o = set.getAttribute(StyleConstants.NameAttribute); 419 if (o instanceof HTML.Tag ) { 420 HTML.Tag tag = (HTML.Tag )o; 421 if(tag == HTML.Tag.IMG) { 424 set.removeAttribute(HTML.Attribute.SRC); 426 set.removeAttribute(HTML.Attribute.HEIGHT); 427 set.removeAttribute(HTML.Attribute.WIDTH); 428 set.addAttribute(StyleConstants.NameAttribute, 429 HTML.Tag.CONTENT); 430 } 431 else if (tag == HTML.Tag.HR || tag == HTML.Tag.BR) { 432 set.addAttribute(StyleConstants.NameAttribute, 434 HTML.Tag.CONTENT); 435 } 436 else if (tag == HTML.Tag.COMMENT) { 437 set.addAttribute(StyleConstants.NameAttribute, 439 HTML.Tag.CONTENT); 440 set.removeAttribute(HTML.Attribute.COMMENT); 441 } 442 else if (tag == HTML.Tag.INPUT) { 443 set.addAttribute(StyleConstants.NameAttribute, 445 HTML.Tag.CONTENT); 446 set.removeAttribute(HTML.Tag.INPUT); 447 } 448 else if (tag instanceof HTML.UnknownTag ) { 449 set.addAttribute(StyleConstants.NameAttribute, 451 HTML.Tag.CONTENT); 452 set.removeAttribute(HTML.Attribute.ENDTAG); 453 } 454 } 455 } 456 457 463 public MutableAttributeSet getInputAttributes() { 464 if (input == null) { 465 input = getStyleSheet().addStyle(null, null); 466 } 467 return input; 468 } 469 470 475 public void setDefaultCursor(Cursor cursor) { 476 defaultCursor = cursor; 477 } 478 479 484 public Cursor getDefaultCursor() { 485 return defaultCursor; 486 } 487 488 493 public void setLinkCursor(Cursor cursor) { 494 linkCursor = cursor; 495 } 496 497 500 public Cursor getLinkCursor() { 501 return linkCursor; 502 } 503 504 514 public boolean isAutoFormSubmission() { 515 return isAutoFormSubmission; 516 } 517 518 527 public void setAutoFormSubmission(boolean isAuto) { 528 isAutoFormSubmission = isAuto; 529 } 530 531 536 public Object clone() { 537 HTMLEditorKit o = (HTMLEditorKit )super.clone(); 538 if (o != null) { 539 o.input = null; 540 o.linkHandler = new LinkController(); 541 } 542 return o; 543 } 544 545 553 protected Parser getParser() { 554 if (defaultParser == null) { 555 try { 556 Class c = Class.forName("javax.swing.text.html.parser.ParserDelegator"); 557 defaultParser = (Parser) c.newInstance(); 558 } catch (Throwable e) { 559 } 560 } 561 return defaultParser; 562 } 563 564 private AccessibleContext accessibleContext; 566 567 573 public AccessibleContext getAccessibleContext() { 574 if (theEditor == null) { 575 return null; 576 } 577 if (accessibleContext == null) { 578 AccessibleHTML a = new AccessibleHTML (theEditor); 579 accessibleContext = a.getAccessibleContext(); 580 } 581 return accessibleContext; 582 } 583 584 586 private static final Cursor MoveCursor = Cursor.getPredefinedCursor 587 (Cursor.HAND_CURSOR); 588 private static final Cursor DefaultCursor = Cursor.getPredefinedCursor 589 (Cursor.DEFAULT_CURSOR); 590 591 592 private static final ViewFactory defaultFactory = new HTMLFactory(); 593 594 MutableAttributeSet input; 595 private static StyleSheet defaultStyles = null; 596 private LinkController linkHandler = new LinkController(); 597 private static Parser defaultParser = null; 598 private Cursor defaultCursor = DefaultCursor; 599 private Cursor linkCursor = MoveCursor; 600 private boolean isAutoFormSubmission = true; 601 602 606 public static class LinkController extends MouseAdapter implements MouseMotionListener, Serializable { 607 private Element curElem = null; 608 611 private boolean curElemImage = false; 612 private String href = null; 613 615 private Position.Bias[] bias = new Position.Bias[1]; 616 619 private int curOffset; 620 621 630 public void mouseClicked(MouseEvent e) { 631 JEditorPane editor = (JEditorPane) e.getSource(); 632 633 if (! editor.isEditable() && SwingUtilities.isLeftMouseButton(e)) { 634 Point pt = new Point(e.getX(), e.getY()); 635 int pos = editor.viewToModel(pt); 636 if (pos >= 0) { 637 activateLink(pos, editor, e.getX(), e.getY()); 638 } 639 } 640 } 641 642 public void mouseDragged(MouseEvent e) { 644 } 645 646 public void mouseMoved(MouseEvent e) { 648 JEditorPane editor = (JEditorPane) e.getSource(); 649 HTMLEditorKit kit = (HTMLEditorKit )editor.getEditorKit(); 650 boolean adjustCursor = true; 651 Cursor newCursor = kit.getDefaultCursor(); 652 if (!editor.isEditable()) { 653 Point pt = new Point(e.getX(), e.getY()); 654 int pos = editor.getUI().viewToModel(editor, pt, bias); 655 if (bias[0] == Position.Bias.Backward && pos > 0) { 656 pos--; 657 } 658 if (pos >= 0 &&(editor.getDocument() instanceof HTMLDocument )){ 659 HTMLDocument hdoc = (HTMLDocument )editor.getDocument(); 660 Element elem = hdoc.getCharacterElement(pos); 661 if (!doesElementContainLocation(editor, elem, pos, 662 e.getX(), e.getY())) { 663 elem = null; 664 } 665 if (curElem != elem || curElemImage) { 666 Element lastElem = curElem; 667 curElem = elem; 668 String href = null; 669 curElemImage = false; 670 if (elem != null) { 671 AttributeSet a = elem.getAttributes(); 672 AttributeSet anchor = (AttributeSet)a. 673 getAttribute(HTML.Tag.A); 674 if (anchor == null) { 675 curElemImage = (a.getAttribute(StyleConstants. 676 NameAttribute) == HTML.Tag.IMG); 677 if (curElemImage) { 678 href = getMapHREF(editor, hdoc, elem, a, 679 pos, e.getX(), e.getY()); 680 } 681 } 682 else { 683 href = (String )anchor.getAttribute 684 (HTML.Attribute.HREF); 685 } 686 } 687 688 if (href != this.href) { 689 fireEvents(editor, hdoc, href, lastElem); 691 this.href = href; 692 if (href != null) { 693 newCursor = kit.getLinkCursor(); 694 } 695 } 696 else { 697 adjustCursor = false; 698 } 699 } 700 else { 701 adjustCursor = false; 702 } 703 curOffset = pos; 704 } 705 } 706 if (adjustCursor && editor.getCursor() != newCursor) { 707 editor.setCursor(newCursor); 708 } 709 } 710 711 715 private String getMapHREF(JEditorPane html, HTMLDocument hdoc, 716 Element elem, AttributeSet attr, int offset, 717 int x, int y) { 718 Object useMap = attr.getAttribute(HTML.Attribute.USEMAP); 719 if (useMap != null && (useMap instanceof String )) { 720 Map m = hdoc.getMap((String )useMap); 721 if (m != null && offset < hdoc.getLength()) { 722 Rectangle bounds; 723 TextUI ui = html.getUI(); 724 try { 725 Shape lBounds = ui.modelToView(html, offset, 726 Position.Bias.Forward); 727 Shape rBounds = ui.modelToView(html, offset + 1, 728 Position.Bias.Backward); 729 bounds = lBounds.getBounds(); 730 bounds.add((rBounds instanceof Rectangle) ? 731 (Rectangle)rBounds : rBounds.getBounds()); 732 } catch (BadLocationException ble) { 733 bounds = null; 734 } 735 if (bounds != null) { 736 AttributeSet area = m.getArea(x - bounds.x, 737 y - bounds.y, 738 bounds.width, 739 bounds.height); 740 if (area != null) { 741 return (String )area.getAttribute(HTML.Attribute. 742 HREF); 743 } 744 } 745 } 746 } 747 return null; 748 } 749 750 755 private boolean doesElementContainLocation(JEditorPane editor, 756 Element e, int offset, 757 int x, int y) { 758 if (e != null && offset > 0 && e.getStartOffset() == offset) { 759 try { 760 TextUI ui = editor.getUI(); 761 Shape s1 = ui.modelToView(editor, offset, 762 Position.Bias.Forward); 763 if (s1 == null) { 764 return false; 765 } 766 Rectangle r1 = (s1 instanceof Rectangle) ? (Rectangle)s1 : 767 s1.getBounds(); 768 Shape s2 = ui.modelToView(editor, e.getEndOffset(), 769 Position.Bias.Backward); 770 if (s2 != null) { 771 Rectangle r2 = (s2 instanceof Rectangle) ? (Rectangle)s2 : 772 s2.getBounds(); 773 r1.add(r2); 774 } 775 return r1.contains(x, y); 776 } catch (BadLocationException ble) { 777 } 778 } 779 return true; 780 } 781 782 791 protected void activateLink(int pos, JEditorPane editor) { 792 activateLink(pos, editor, -1, -1); 793 } 794 795 805 void activateLink(int pos, JEditorPane html, int x, int y) { 806 Document doc = html.getDocument(); 807 if (doc instanceof HTMLDocument ) { 808 HTMLDocument hdoc = (HTMLDocument ) doc; 809 Element e = hdoc.getCharacterElement(pos); 810 AttributeSet a = e.getAttributes(); 811 AttributeSet anchor = (AttributeSet)a.getAttribute(HTML.Tag.A); 812 HyperlinkEvent linkEvent = null; 813 String description; 814 815 if (anchor == null) { 816 href = getMapHREF(html, hdoc, e, a, pos, x, y); 817 } 818 else { 819 href = (String )anchor.getAttribute(HTML.Attribute.HREF); 820 } 821 822 if (href != null) { 823 linkEvent = createHyperlinkEvent(html, hdoc, href, anchor, 824 e); 825 } 826 if (linkEvent != null) { 827 html.fireHyperlinkUpdate(linkEvent); 828 } 829 } 830 } 831 832 837 HyperlinkEvent createHyperlinkEvent(JEditorPane html, 838 HTMLDocument hdoc, String href, 839 AttributeSet anchor, 840 Element element) { 841 URL u; 842 try { 843 URL base = hdoc.getBase(); 844 u = new URL (base, href); 845 if (href != null && "file".equals(u.getProtocol()) && 849 href.startsWith("#")) { 850 String baseFile = base.getFile(); 851 String newFile = u.getFile(); 852 if (baseFile != null && newFile != null && 853 !newFile.startsWith(baseFile)) { 854 u = new URL (base, baseFile + href); 855 } 856 } 857 } catch (MalformedURLException m) { 858 u = null; 859 } 860 HyperlinkEvent linkEvent = null; 861 862 if (!hdoc.isFrameDocument()) { 863 linkEvent = new HyperlinkEvent(html, HyperlinkEvent.EventType. 864  
|