Frames | No Frames |
1: /* HTMLEditorKit.java -- 2: Copyright (C) 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package javax.swing.text.html; 40: 41: 42: import gnu.classpath.NotImplementedException; 43: 44: import java.awt.event.ActionEvent; 45: import java.awt.event.MouseAdapter; 46: import java.awt.event.MouseEvent; 47: import java.awt.event.MouseMotionListener; 48: import java.awt.Cursor; 49: 50: import java.io.IOException; 51: import java.io.Reader; 52: import java.io.Serializable; 53: import java.io.StringReader; 54: import java.io.Writer; 55: 56: import javax.accessibility.Accessible; 57: import javax.accessibility.AccessibleContext; 58: 59: import javax.swing.Action; 60: import javax.swing.JEditorPane; 61: import javax.swing.text.BadLocationException; 62: import javax.swing.text.Document; 63: import javax.swing.text.EditorKit; 64: import javax.swing.text.Element; 65: import javax.swing.text.MutableAttributeSet; 66: import javax.swing.text.StyleConstants; 67: import javax.swing.text.StyleContext; 68: import javax.swing.text.StyledEditorKit; 69: import javax.swing.text.TextAction; 70: import javax.swing.text.View; 71: import javax.swing.text.ViewFactory; 72: import javax.swing.text.html.parser.ParserDelegator; 73: 74: /** 75: * @author Lillian Angel (langel at redhat dot com) 76: */ 77: public class HTMLEditorKit 78: extends StyledEditorKit 79: implements Serializable, Cloneable, Accessible 80: { 81: 82: /** 83: * Fires the hyperlink events on the associated component 84: * when needed. 85: */ 86: public static class LinkController 87: extends MouseAdapter 88: implements MouseMotionListener, Serializable 89: { 90: 91: /** 92: * Constructor 93: */ 94: public LinkController() 95: { 96: super(); 97: } 98: 99: /** 100: * Dispatched when the mouse is clicked. If the component 101: * is read-only, then the clicked event is used to drive an 102: * attempt to follow the reference specified by a link 103: * 104: * @param e - the mouse event 105: */ 106: public void mouseClicked(MouseEvent e) 107: { 108: /* 109: These MouseInputAdapter methods generate mouse appropriate events around 110: hyperlinks (entering, exiting, and activating). 111: */ 112: // FIXME: Not implemented. 113: } 114: 115: /** 116: * Dispatched when the mouse is dragged on a component. 117: * 118: * @param e - the mouse event. 119: */ 120: public void mouseDragged(MouseEvent e) 121: { 122: /* 123: These MouseInputAdapter methods generate mouse appropriate events around 124: hyperlinks (entering, exiting, and activating). 125: */ 126: // FIXME: Not implemented. 127: } 128: 129: /** 130: * Dispatched when the mouse cursor has moved into the component. 131: * 132: * @param e - the mouse event. 133: */ 134: public void mouseMoved(MouseEvent e) 135: { 136: /* 137: These MouseInputAdapter methods generate mouse appropriate events around 138: hyperlinks (entering, exiting, and activating). 139: */ 140: // FIXME: Not implemented. 141: } 142: 143: /** 144: * If the given position represents a link, then linkActivated is called 145: * on the JEditorPane. Implemented to forward to the method with the same 146: * name, but pos == editor == -1. 147: * 148: * @param pos - the position 149: * @param editor - the editor pane 150: */ 151: protected void activateLink(int pos, 152: JEditorPane editor) 153: { 154: /* 155: This method creates and fires a HyperlinkEvent if the document is an 156: instance of HTMLDocument and the href tag of the link is not null. 157: */ 158: // FIXME: Not implemented. 159: } 160: } 161: 162: /** 163: * This class is used to insert a string of HTML into an existing 164: * document. At least 2 HTML.Tags need to be supplied. The first Tag (parentTag) 165: * identifies the parent in the document to add the elements to. The second, (addTag), 166: * identifies that the first tag should be added to the document as seen in the string. 167: * The parser will generate all appropriate (opening/closing tags_ even if they are not 168: * in the HTML string passed in. 169: */ 170: public static class InsertHTMLTextAction 171: extends HTMLTextAction 172: { 173: 174: /** 175: * Tag in HTML to start adding tags from. 176: */ 177: protected HTML.Tag addTag; 178: 179: /** 180: * Alternate tag in HTML to start adding tags from if parentTag is 181: * not found and alternateParentTag is not found. 182: */ 183: protected HTML.Tag alternateAddTag; 184: 185: /** 186: * Alternate tag to check if parentTag is not found. 187: */ 188: protected HTML.Tag alternateParentTag; 189: 190: /** 191: * HTML to insert. 192: */ 193: protected String html; 194: 195: /** 196: * Tag to check for in the document. 197: */ 198: protected HTML.Tag parentTag; 199: 200: /** 201: * Initializes all fields. 202: * 203: * @param name - the name of the document. 204: * @param html - the html to insert 205: * @param parentTag - the parent tag to check for 206: * @param addTag - the tag to start adding from 207: */ 208: public InsertHTMLTextAction(String name, String html, 209: HTML.Tag parentTag, HTML.Tag addTag) 210: { 211: this(name, html, parentTag, addTag, null, null); 212: } 213: 214: /** 215: * Initializes all fields and calls super 216: * 217: * @param name - the name of the document. 218: * @param html - the html to insert 219: * @param parentTag - the parent tag to check for 220: * @param addTag - the tag to start adding from 221: * @param alternateParentTag - the alternate parent tag 222: * @param alternateAddTag - the alternate add tag 223: */ 224: public InsertHTMLTextAction(String name, String html, HTML.Tag parentTag, 225: HTML.Tag addTag, HTML.Tag alternateParentTag, 226: HTML.Tag alternateAddTag) 227: { 228: super(name); 229: // Fields are for easy access when the action is applied to an actual 230: // document. 231: this.html = html; 232: this.parentTag = parentTag; 233: this.addTag = addTag; 234: this.alternateParentTag = alternateParentTag; 235: this.alternateAddTag = alternateAddTag; 236: } 237: 238: /** 239: * HTMLEditorKit.insertHTML is called. If an exception is 240: * thrown, it is wrapped in a RuntimeException and thrown. 241: * 242: * @param editor - the editor to use to get the editorkit 243: * @param doc - 244: * the Document to insert the HTML into. 245: * @param offset - 246: * where to begin inserting the HTML. 247: * @param html - 248: * the String to insert 249: * @param popDepth - 250: * the number of ElementSpec.EndTagTypes to generate before 251: * inserting 252: * @param pushDepth - 253: * the number of ElementSpec.StartTagTypes with a direction of 254: * ElementSpec.JoinNextDirection that should be generated before 255: * @param addTag - 256: * the first tag to start inserting into document 257: */ 258: protected void insertHTML(JEditorPane editor, HTMLDocument doc, int offset, 259: String html, int popDepth, int pushDepth, 260: HTML.Tag addTag) 261: { 262: try 263: { 264: super.getHTMLEditorKit(editor).insertHTML(doc, offset, html, 265: popDepth, pushDepth, addTag); 266: } 267: catch (IOException e) 268: { 269: throw (RuntimeException) new RuntimeException("Parser is null.").initCause(e); 270: } 271: catch (BadLocationException ex) 272: { 273: throw (RuntimeException) new RuntimeException("BadLocationException: " 274: + offset).initCause(ex); 275: } 276: } 277: 278: /** 279: * Invoked when inserting at a boundary. Determines the number of pops, 280: * and then the number of pushes that need to be performed. The it calls 281: * insertHTML. 282: * 283: * @param editor - 284: * the editor to use to get the editorkit 285: * @param doc - 286: * the Document to insert the HTML into. 287: * @param offset - 288: * where to begin inserting the HTML. 289: * @param insertElement - 290: * the element to insert 291: * @param html - 292: * the html to insert 293: * @param parentTag - 294: * the parent tag 295: * @param addTag - 296: * the first tag 297: */ 298: protected void insertAtBoundary(JEditorPane editor, 299: HTMLDocument doc, int offset, 300: Element insertElement, 301: String html, HTML.Tag parentTag, 302: HTML.Tag addTag) 303: throws NotImplementedException 304: { 305: /* 306: As its name implies, this protected method is used when HTML is inserted at a 307: boundary. (A boundary in this case is an offset in doc that exactly matches the 308: beginning offset of the parentTag.) It performs the extra work required to keep 309: the tag stack in shape and then calls insertHTML(). The editor and doc argu- 310: ments are the editor pane and document where the HTML should go. The offset 311: argument represents the cursor location or selection start in doc. The insert- 312: Element and parentTag arguments are used to calculate the proper number of 313: tag pops and pushes before inserting the HTML (via html and addTag, which are 314: passed directly to insertHTML()). 315: */ 316: // FIXME: not implemented 317: } 318: 319: /** 320: * Invoked when inserting at a boundary. Determines the number of pops, 321: * and then the number of pushes that need to be performed. The it calls 322: * insertHTML. 323: * 324: * @param editor - the editor to use to get the editorkit 325: * @param doc - 326: * the Document to insert the HTML into. 327: * @param offset - 328: * where to begin inserting the HTML. 329: * @param insertElement - the element to insert 330: * @param html - the html to insert 331: * @param parentTag - the parent tag 332: * @param addTag - the first tag 333: * 334: * @deprecated as of v1.3, use insertAtBoundary 335: */ 336: protected void insertAtBoundry(JEditorPane editor, 337: HTMLDocument doc, 338: int offset, Element insertElement, 339: String html, HTML.Tag parentTag, 340: HTML.Tag addTag) 341: { 342: insertAtBoundary(editor, doc, offset, insertElement, 343: html, parentTag, addTag); 344: } 345: 346: /** 347: * Inserts the HTML. 348: * 349: * @param ae - the action performed 350: */ 351: public void actionPerformed(ActionEvent ae) 352: { 353: Object source = ae.getSource(); 354: if (source instanceof JEditorPane) 355: { 356: JEditorPane pane = ((JEditorPane) source); 357: Document d = pane.getDocument(); 358: if (d instanceof HTMLDocument) 359: insertHTML(pane, (HTMLDocument) d, 0, html, 0, 0, addTag); 360: // FIXME: is this correct parameters? 361: } 362: // FIXME: else not implemented 363: } 364: } 365: 366: /** 367: * Abstract Action class that helps inserting HTML into an existing document. 368: */ 369: public abstract static class HTMLTextAction 370: extends StyledEditorKit.StyledTextAction 371: { 372: 373: /** 374: * Constructor 375: */ 376: public HTMLTextAction(String name) 377: { 378: super(name); 379: } 380: 381: /** 382: * Gets the HTMLDocument from the JEditorPane. 383: * 384: * @param e - the editor pane 385: * @return the html document. 386: */ 387: protected HTMLDocument getHTMLDocument(JEditorPane e) 388: { 389: Document d = e.getDocument(); 390: if (d instanceof HTMLDocument) 391: return (HTMLDocument) d; 392: throw new IllegalArgumentException("Document is not a HTMLDocument."); 393: } 394: 395: /** 396: * Gets the HTMLEditorKit 397: * 398: * @param e - the JEditorPane to get the HTMLEditorKit from. 399: * @return the HTMLEditorKit 400: */ 401: protected HTMLEditorKit getHTMLEditorKit(JEditorPane e) 402: { 403: EditorKit d = e.getEditorKit(); 404: if (d instanceof HTMLEditorKit) 405: return (HTMLEditorKit) d; 406: throw new IllegalArgumentException("EditorKit is not a HTMLEditorKit."); 407: } 408: 409: /** 410: * Returns an array of Elements that contain the offset. 411: * The first elements corresponds to the roots of the doc. 412: * 413: * @param doc - the document to get the Elements from. 414: * @param offset - the offset the Elements must contain 415: * @return an array of all the elements containing the offset. 416: */ 417: protected Element[] getElementsAt(HTMLDocument doc, 418: int offset) 419: { 420: return getElementsAt(doc.getDefaultRootElement(), offset, 0); 421: } 422: 423: /** 424: * Helper function to get all elements using recursion. 425: */ 426: private Element[] getElementsAt(Element root, int offset, int depth) 427: { 428: Element[] elements = null; 429: if (root != null) 430: { 431: if (root.isLeaf()) 432: { 433: elements = new Element[depth + 1]; 434: elements[depth] = root; 435: return elements; 436: } 437: elements = getElementsAt(root.getElement(root.getElementIndex(offset)), 438: offset, depth + 1); 439: elements[depth] = root; 440: } 441: return elements; 442: } 443: 444: /** 445: * Returns the number of elements, starting at the deepest point, needed 446: * to get an element representing tag. -1 if no elements are found, 0 if 447: * the parent of the leaf at offset represents the tag. 448: * 449: * @param doc - 450: * the document to search 451: * @param offset - 452: * the offset to check 453: * @param tag - 454: * the tag to look for 455: * @return - the number of elements needed to get an element representing 456: * tag. 457: */ 458: protected int elementCountToTag(HTMLDocument doc, 459: int offset, HTML.Tag tag) 460: { 461: Element root = doc.getDefaultRootElement(); 462: int num = -1; 463: Element next = root.getElement(root.getElementIndex(offset)); 464: 465: while (!next.isLeaf()) 466: { 467: num++; 468: if (next.getAttributes(). 469: getAttribute(StyleConstants.NameAttribute).equals(tag)) 470: return num; 471: next = next.getElement(next.getElementIndex(offset)); 472: } 473: return num; 474: } 475: 476: /** 477: * Gets the deepest element at offset with the 478: * matching tag. 479: * 480: * @param doc - the document to search 481: * @param offset - the offset to check for 482: * @param tag - the tag to match 483: * @return - the element that is found, null if not found. 484: */ 485: protected Element findElementMatchingTag(HTMLDocument doc, 486: int offset, HTML.Tag tag) 487: { 488: Element element = doc.getDefaultRootElement(); 489: Element tagElement = null; 490: 491: while (element != null) 492: { 493: Object otag = element.getAttributes().getAttribute( 494: StyleConstants.NameAttribute); 495: if (otag instanceof HTML.Tag && otag.equals(tag)) 496: tagElement = element; 497: element = element.getElement(element.getElementIndex(offset)); 498: } 499: 500: return tagElement; 501: } 502: } 503: 504: /** 505: * A {@link ViewFactory} that is able to create {@link View}s for 506: * the <code>Element</code>s that are supported. 507: */ 508: public static class HTMLFactory 509: implements ViewFactory 510: { 511: 512: /** 513: * Constructor 514: */ 515: public HTMLFactory() 516: { 517: // Do Nothing here. 518: } 519: 520: /** 521: * Creates a {@link View} for the specified <code>Element</code>. 522: * 523: * @param element the <code>Element</code> to create a <code>View</code> 524: * for 525: * @return the <code>View</code> for the specified <code>Element</code> 526: * or <code>null</code> if the type of <code>element</code> is 527: * not supported 528: */ 529: public View create(Element element) 530: { 531: View view = null; 532: Object attr = 533: element.getAttributes().getAttribute(StyleConstants.NameAttribute); 534: if (attr instanceof HTML.Tag) 535: { 536: HTML.Tag tag = (HTML.Tag) attr; 537: 538: if (tag.equals(HTML.Tag.IMPLIED) || tag.equals(HTML.Tag.P) 539: || tag.equals(HTML.Tag.H1) || tag.equals(HTML.Tag.H2) 540: || tag.equals(HTML.Tag.H3) || tag.equals(HTML.Tag.H4) 541: || tag.equals(HTML.Tag.H5) || tag.equals(HTML.Tag.H6) 542: || tag.equals(HTML.Tag.DT)) 543: view = new ParagraphView(element); 544: else if (tag.equals(HTML.Tag.LI) || tag.equals(HTML.Tag.DL) 545: || tag.equals(HTML.Tag.DD) || tag.equals(HTML.Tag.BODY) 546: || tag.equals(HTML.Tag.HTML) || tag.equals(HTML.Tag.CENTER) 547: || tag.equals(HTML.Tag.DIV) 548: || tag.equals(HTML.Tag.BLOCKQUOTE) 549: || tag.equals(HTML.Tag.PRE)) 550: view = new BlockView(element, View.Y_AXIS); 551: else if (tag.equals(HTML.Tag.IMG)) 552: view = new ImageView(element); 553: 554: // FIXME: Uncomment when the views have been implemented 555: else if (tag.equals(HTML.Tag.CONTENT)) 556: view = new InlineView(element); 557: else if (tag == HTML.Tag.HEAD) 558: view = new NullView(element); 559: else if (tag.equals(HTML.Tag.TABLE)) 560: view = new HTMLTableView(element); 561: else if (tag.equals(HTML.Tag.TD)) 562: view = new ParagraphView(element); 563: 564: 565: /* 566: else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR) 567: || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL)) 568: view = new ListView(element); 569: else if (tag.equals(HTML.Tag.HR)) 570: view = new HRuleView(element); 571: else if (tag.equals(HTML.Tag.BR)) 572: view = new BRView(element); 573: else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT) 574: || tag.equals(HTML.Tag.TEXTAREA)) 575: view = new FormView(element); 576: else if (tag.equals(HTML.Tag.OBJECT)) 577: view = new ObjectView(element); 578: else if (tag.equals(HTML.Tag.FRAMESET)) 579: view = new FrameSetView(element); 580: else if (tag.equals(HTML.Tag.FRAME)) 581: view = new FrameView(element); */ 582: } 583: if (view == null) 584: { 585: System.err.println("missing tag->view mapping for: " + element); 586: view = new NullView(element); 587: } 588: return view; 589: } 590: } 591: 592: /** 593: * The abstract HTML parser declaration. 594: */ 595: public abstract static class Parser 596: { 597: /** 598: * Parse the HTML text, calling various methods of the provided callback 599: * in response to the occurence of the corresponding HTML constructions. 600: * @param reader The reader to read the source HTML from. 601: * @param callback The callback to receive information about the parsed 602: * HTML structures 603: * @param ignoreCharSet If true, the parser ignores all charset information 604: * that may be present in HTML documents. 605: * @throws IOException, normally if the reader throws one. 606: */ 607: public abstract void parse(Reader reader, ParserCallback callback, 608: boolean ignoreCharSet) throws IOException; 609: } 610: 611: /** 612: * The "hook" that receives all information about the HTML document 613: * structure while parsing it. The methods are invoked by parser 614: * and should be normally overridden. 615: */ 616: public static class ParserCallback 617: { 618: /** 619: * If the tag does not occurs in the html stream directly, but 620: * is supposed by parser, the tag attribute set contains this additional 621: * attribute, having value Boolean.True. 622: */ 623: public static final Object IMPLIED = "_implied_"; 624: 625: /** 626: * Constructor 627: */ 628: public ParserCallback() 629: { 630: // Nothing to do here. 631: } 632: 633: /** 634: * The parser calls this method after it finishes parsing the document. 635: */ 636: public void flush() throws BadLocationException 637: { 638: // Nothing to do here. 639: } 640: 641: /** 642: * Handle HTML comment, present in the given position. 643: * @param comment the comment 644: * @position the position of the comment in the text being parsed. 645: */ 646: public void handleComment(char[] comment, int position) 647: { 648: // Nothing to do here. 649: } 650: 651: /** 652: * Notifies about the character sequences, used to separate lines in 653: * this document. The parser calls this method after it finishes 654: * parsing the document, but before flush(). 655: * @param end_of_line The "end of line sequence", one of: \r or \n or \r\n. 656: */ 657: public void handleEndOfLineString(String end_of_line) 658: { 659: // Nothing to do here. 660: } 661: 662: /** 663: * The method is called when the HTML closing tag ((like </table>) 664: * is found or if the parser concludes that the one should be present 665: * in the current position. 666: * @param tag The tag being handled 667: * @param position the tag position in the text being parsed. 668: */ 669: public void handleEndTag(HTML.Tag tag, int position) 670: { 671: // Nothing to do here. 672: } 673: 674: /** 675: * Handle the error. 676: * @param message The message, explaining the error. 677: * @param position The starting position of the fragment that has caused 678: * the error in the html document being parsed. 679: */ 680: public void handleError(String message, int position) 681: { 682: // Nothing to do here. 683: } 684: 685: /** 686: * Handle the tag with no content, like <br>. The method is 687: * called for the elements that, in accordance with the current DTD, 688: * has an empty content. 689: * @param tag The tag being handled. 690: * @param position The tag position in the text being parsed. 691: */ 692: public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes, 693: int position) 694: { 695: // Nothing to do here. 696: } 697: 698: /** 699: * The method is called when the HTML opening tag ((like <table>) 700: * is found or if the parser concludes that the one should be present 701: * in the current position. 702: * @param tag The tag being handled 703: * @param position The tag position in the text being parsed 704: */ 705: public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes, 706: int position) 707: { 708: // Nothing to do here. 709: } 710: 711: /** 712: * Handle the text section. 713: * @param text A section text. 714: * @param position The text position in the HTML document text being parsed. 715: */ 716: public void handleText(char[] text, int position) 717: { 718: // Nothing to do here. 719: } 720: } 721: 722: /** 723: * Use serialVersionUID (v1.4) for interoperability. 724: */ 725: private static final long serialVersionUID = 8751997116710384592L; 726: 727: /** 728: * Default cascading stylesheed file ("default.css"). 729: */ 730: public static final String DEFAULT_CSS = "default.css"; 731: 732: /** 733: * The <b>bold</b> action identifier. 734: */ 735: public static final String BOLD_ACTION = "html-bold-action"; 736: 737: /** 738: * The <i>italic</i> action identifier. 739: */ 740: public static final String ITALIC_ACTION = "html-italic-action"; 741: 742: /** 743: * The <font color="#FF0000">color</font> action indentifier 744: * (passing the color as an argument). 745: */ 746: public static final String COLOR_ACTION = "html-color-action"; 747: 748: /** 749: * The <font size="+1">increase</font> font action identifier. 750: */ 751: public static final String FONT_CHANGE_BIGGER = "html-font-bigger"; 752: 753: /** 754: * The <font size="-1">decrease</font> font action identifier. 755: */ 756: public static final String FONT_CHANGE_SMALLER = "html-font-smaller"; 757: 758: /** 759: * Align images at the bottom. 760: */ 761: public static final String IMG_ALIGN_BOTTOM = "html-image-align-bottom"; 762: 763: /** 764: * Align images at the middle. 765: */ 766: public static final String IMG_ALIGN_MIDDLE = "html-image-align-middle"; 767: 768: /** 769: * Align images at the top. 770: */ 771: public static final String IMG_ALIGN_TOP = "html-image-align-top"; 772: 773: /** 774: * Align images at the border. 775: */ 776: public static final String IMG_BORDER = "html-image-border"; 777: 778: /** 779: * The "logical style" action identifier, passing that style as parameter. 780: */ 781: public static final String LOGICAL_STYLE_ACTION = "html-logical-style-action"; 782: 783: /** 784: * The "ident paragraph left" action. 785: */ 786: public static final String PARA_INDENT_LEFT = "html-para-indent-left"; 787: 788: /** 789: * The "ident paragraph right" action. 790: */ 791: public static final String PARA_INDENT_RIGHT = "html-para-indent-right"; 792: 793: /** 794: * Actions for HTML 795: */ 796: private static final Action[] defaultActions = { 797: // FIXME: Add default actions for html 798: }; 799: 800: /** 801: * The current style sheet. 802: */ 803: StyleSheet styleSheet; 804: 805: /** 806: * The ViewFactory for HTMLFactory. 807: */ 808: HTMLFactory viewFactory; 809: 810: /** 811: * The Cursor for links. 812: */ 813: Cursor linkCursor; 814: 815: /** 816: * The default cursor. 817: */ 818: Cursor defaultCursor; 819: 820: /** 821: * The parser. 822: */ 823: Parser parser; 824: 825: /** 826: * The mouse listener used for links. 827: */ 828: LinkController mouseListener; 829: 830: /** 831: * Style context for this editor. 832: */ 833: StyleContext styleContext; 834: 835: /** The content type */ 836: String contentType = "text/html"; 837: 838: /** The input attributes defined by default.css */ 839: MutableAttributeSet inputAttributes; 840: 841: /** The editor pane used. */ 842: JEditorPane editorPane; 843: 844: /** 845: * Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet. 846: */ 847: public HTMLEditorKit() 848: { 849: super(); 850: styleContext = new StyleContext(); 851: styleSheet = new StyleSheet(); 852: styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS)); 853: // FIXME: Set inputAttributes with default.css 854: } 855: 856: /** 857: * Gets a factory suitable for producing views of any 858: * models that are produced by this kit. 859: * 860: * @return the view factory suitable for producing views. 861: */ 862: public ViewFactory getViewFactory() 863: { 864: if (viewFactory == null) 865: viewFactory = new HTMLFactory(); 866: return viewFactory; 867: } 868: 869: /** 870: * Create a text storage model for this type of editor. 871: * 872: * @return the model 873: */ 874: public Document createDefaultDocument() 875: { 876: HTMLDocument document = new HTMLDocument(getStyleSheet()); 877: document.setParser(getParser()); 878: return document; 879: } 880: 881: /** 882: * Get the parser that this editor kit uses for reading HTML streams. This 883: * method can be overridden to use the alternative parser. 884: * 885: * @return the HTML parser (by default, {@link ParserDelegator}). 886: */ 887: protected Parser getParser() 888: { 889: if (parser == null) 890: parser = new ParserDelegator(); 891: return parser; 892: } 893: 894: /** 895: * Inserts HTML into an existing document. 896: * 897: * @param doc - the Document to insert the HTML into. 898: * @param offset - where to begin inserting the HTML. 899: * @param html - the String to insert 900: * @param popDepth - the number of ElementSpec.EndTagTypes 901: * to generate before inserting 902: * @param pushDepth - the number of ElementSpec.StartTagTypes 903: * with a direction of ElementSpec.JoinNextDirection that 904: * should be generated before 905: * @param insertTag - the first tag to start inserting into document 906: * @throws IOException - on any I/O error 907: * @throws BadLocationException - if pos represents an invalid location 908: * within the document 909: */ 910: public void insertHTML(HTMLDocument doc, int offset, String html, 911: int popDepth, int pushDepth, HTML.Tag insertTag) 912: throws BadLocationException, IOException 913: { 914: Parser parser = getParser(); 915: if (offset < 0 || offset > doc.getLength()) 916: throw new BadLocationException("Bad location", offset); 917: if (parser == null) 918: throw new IOException("Parser is null."); 919: 920: ParserCallback pc = ((HTMLDocument) doc).getReader 921: (offset, popDepth, pushDepth, insertTag); 922: 923: // FIXME: What should ignoreCharSet be set to? 924: 925: // parser.parse inserts html into the buffer 926: parser.parse(new StringReader(html), pc, false); 927: pc.flush(); 928: } 929: 930: /** 931: * Inserts content from the given stream. Inserting HTML into a non-empty 932: * document must be inside the body Element, if you do not insert into 933: * the body an exception will be thrown. When inserting into a non-empty 934: * document all tags outside of the body (head, title) will be dropped. 935: * 936: * @param in - the stream to read from 937: * @param doc - the destination for the insertion 938: * @param pos - the location in the document to place the content 939: * @throws IOException - on any I/O error 940: * @throws BadLocationException - if pos represents an invalid location 941: * within the document 942: */ 943: public void read(Reader in, Document doc, int pos) throws IOException, 944: BadLocationException 945: { 946: if (doc instanceof HTMLDocument) 947: { 948: Parser parser = getParser(); 949: if (pos < 0 || pos > doc.getLength()) 950: throw new BadLocationException("Bad location", pos); 951: if (parser == null) 952: throw new IOException("Parser is null."); 953: 954: HTMLDocument hd = ((HTMLDocument) doc); 955: if (editorPane != null) 956: hd.setBase(editorPane.getPage()); 957: ParserCallback pc = hd.getReader(pos); 958: 959: // FIXME: What should ignoreCharSet be set to? 960: 961: // parser.parse inserts html into the buffer 962: parser.parse(in, pc, false); 963: pc.flush(); 964: } 965: else 966: // read in DefaultEditorKit is called. 967: // the string is inserted in the document as usual. 968: super.read(in, doc, pos); 969: } 970: 971: /** 972: * Writes content from a document to the given stream in 973: * an appropriate format. 974: * 975: * @param out - the stream to write to 976: * @param doc - the source for the write 977: * @param pos - the location in the document to get the content. 978: * @param len - the amount to write out 979: * @throws IOException - on any I/O error 980: * @throws BadLocationException - if pos represents an invalid location 981: * within the document 982: */ 983: public void write(Writer out, Document doc, int pos, int len) 984: throws IOException, BadLocationException 985: { 986: if (doc instanceof HTMLDocument) 987: { 988: // FIXME: Not implemented. Use HTMLWriter. 989: out.write(doc.getText(pos, len)); 990: } 991: else 992: super.write(out, doc, pos, len); 993: } 994: 995: /** 996: * Gets the content type that the kit supports. 997: * This kit supports the type text/html. 998: * 999: * @returns the content type supported. 1000: */ 1001: public String getContentType() 1002: { 1003: return contentType; 1004: } 1005: 1006: /** 1007: * Creates a copy of the editor kit. 1008: * 1009: * @return a copy of this. 1010: */ 1011: public Object clone() 1012: { 1013: // FIXME: Need to clone all fields 1014: return (HTMLEditorKit) super.clone(); 1015: } 1016: 1017: /** 1018: * Copies the key/values in elements AttributeSet into set. 1019: * This does not copy component, icon, or element names attributes. 1020: * This is called anytime the caret moves over a different location. 1021: * 1022: * @param element - the element to create the input attributes for. 1023: * @param set - the set to copy the values into. 1024: */ 1025: protected void createInputAttributes(Element element, 1026: MutableAttributeSet set) 1027: { 1028: set.removeAttributes(set); 1029: set.addAttributes(element.getAttributes()); 1030: // FIXME: Not fully implemented. 1031: } 1032: 1033: /** 1034: * Called when this is installed into the JEditorPane. 1035: * 1036: * @param c - the JEditorPane installed into. 1037: */ 1038: public void install(JEditorPane c) 1039: { 1040: super.install(c); 1041: mouseListener = new LinkController(); 1042: c.addMouseListener(mouseListener); 1043: editorPane = c; 1044: // FIXME: need to set up hyperlinklistener object 1045: } 1046: 1047: /** 1048: * Called when the this is removed from the JEditorPane. 1049: * It unregisters any listeners. 1050: * 1051: * @param c - the JEditorPane being removed from. 1052: */ 1053: public void deinstall(JEditorPane c) 1054: { 1055: super.deinstall(c); 1056: c.removeMouseListener(mouseListener); 1057: mouseListener = null; 1058: editorPane = null; 1059: } 1060: 1061: /** 1062: * Gets the AccessibleContext associated with this. 1063: * 1064: * @return the AccessibleContext for this. 1065: */ 1066: public AccessibleContext getAccessibleContext() 1067: { 1068: // FIXME: Should return an instance of 1069: // javax.swing.text.html.AccessibleHTML$RootHTMLAccessibleContext 1070: // Not implemented yet. 1071: return null; 1072: } 1073: 1074: /** 1075: * Gets the action list. This list is supported by the superclass 1076: * augmented by the collection of actions defined locally for style 1077: * operations. 1078: * 1079: * @return an array of all the actions 1080: */ 1081: public Action[] getActions() 1082: { 1083: return TextAction.augmentList(super.getActions(), defaultActions); 1084: } 1085: 1086: /** 1087: * Returns the default cursor. 1088: * 1089: * @return the default cursor 1090: */ 1091: public Cursor getDefaultCursor() 1092: { 1093: if (defaultCursor == null) 1094: defaultCursor = Cursor.getDefaultCursor(); 1095: return defaultCursor; 1096: } 1097: 1098: /** 1099: * Returns the cursor for links. 1100: * 1101: * @return the cursor for links. 1102: */ 1103: public Cursor getLinkCursor() 1104: { 1105: if (linkCursor == null) 1106: linkCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); 1107: return linkCursor; 1108: } 1109: 1110: /** 1111: * Sets the Cursor for links. 1112: * 1113: * @param cursor - the new cursor for links. 1114: */ 1115: public void setLinkCursor(Cursor cursor) 1116: { 1117: linkCursor = cursor; 1118: } 1119: 1120: /** 1121: * Sets the default cursor. 1122: * 1123: * @param cursor - the new default cursor. 1124: */ 1125: public void setDefaultCursor(Cursor cursor) 1126: { 1127: defaultCursor = cursor; 1128: } 1129: 1130: /** 1131: * Gets the input attributes used for the styled editing actions. 1132: * 1133: * @return the attribute set 1134: */ 1135: public MutableAttributeSet getInputAttributes() 1136: { 1137: return inputAttributes; 1138: } 1139: 1140: /** 1141: * Get the set of styles currently being used to render the HTML elements. 1142: * By default the resource specified by DEFAULT_CSS gets loaded, and is 1143: * shared by all HTMLEditorKit instances. 1144: * 1145: * @return the style sheet. 1146: */ 1147: public StyleSheet getStyleSheet() 1148: { 1149: if (styleSheet == null) 1150: { 1151: styleSheet = new StyleSheet(); 1152: styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS)); 1153: } 1154: return styleSheet; 1155: } 1156: 1157: /** 1158: * Set the set of styles to be used to render the various HTML elements. 1159: * These styles are specified in terms of CSS specifications. Each document 1160: * produced by the kit will have a copy of the sheet which it can add the 1161: * document specific styles to. By default, the StyleSheet specified is shared 1162: * by all HTMLEditorKit instances. 1163: * 1164: * @param s - the new style sheet 1165: */ 1166: public void setStyleSheet(StyleSheet s) 1167: { 1168: styleSheet = s; 1169: } 1170: }