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