GNU Classpath (0.91) | |
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: 552: // FIXME: Uncomment when the views have been implemented 553: else if (tag.equals(HTML.Tag.CONTENT)) 554: view = new InlineView(element); 555: else if (tag == HTML.Tag.HEAD) 556: view = new NullView(element); 557: else if (tag.equals(HTML.Tag.TABLE)) 558: view = new HTMLTableView(element); 559: else if (tag.equals(HTML.Tag.TD)) 560: view = new ParagraphView(element); 561: 562: /* 563: else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR) 564: || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL)) 565: view = new ListView(element); 566: else if (tag.equals(HTML.Tag.IMG)) 567: view = new ImageView(element); 568: else if (tag.equals(HTML.Tag.HR)) 569: view = new HRuleView(element); 570: else if (tag.equals(HTML.Tag.BR)) 571: view = new BRView(element); 572: else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT) 573: || tag.equals(HTML.Tag.TEXTAREA)) 574: view = new FormView(element); 575: else if (tag.equals(HTML.Tag.OBJECT)) 576: view = new ObjectView(element); 577: else if (tag.equals(HTML.Tag.FRAMESET)) 578: view = new FrameSetView(element); 579: else if (tag.equals(HTML.Tag.FRAME)) 580: view = new FrameView(element); */ 581: } 582: if (view == null) 583: { 584: System.err.println("missing tag->view mapping for: " + element); 585: view = new NullView(element); 586: } 587: return view; 588: } 589: } 590: 591: /** 592: * The abstract HTML parser declaration. 593: */ 594: public abstract static class Parser 595: { 596: /** 597: * Parse the HTML text, calling various methods of the provided callback 598: * in response to the occurence of the corresponding HTML constructions. 599: * @param reader The reader to read the source HTML from. 600: * @param callback The callback to receive information about the parsed 601: * HTML structures 602: * @param ignoreCharSet If true, the parser ignores all charset information 603: * that may be present in HTML documents. 604: * @throws IOException, normally if the reader throws one. 605: */ 606: public abstract void parse(Reader reader, ParserCallback callback, 607: boolean ignoreCharSet) throws IOException; 608: } 609: 610: /** 611: * The "hook" that receives all information about the HTML document 612: * structure while parsing it. The methods are invoked by parser 613: * and should be normally overridden. 614: */ 615: public static class ParserCallback 616: { 617: /** 618: * If the tag does not occurs in the html stream directly, but 619: * is supposed by parser, the tag attribute set contains this additional 620: * attribute, having value Boolean.True. 621: */ 622: public static final Object IMPLIED = "_implied_"; 623: 624: /** 625: * Constructor 626: */ 627: public ParserCallback() 628: { 629: // Nothing to do here. 630: } 631: 632: /** 633: * The parser calls this method after it finishes parsing the document. 634: */ 635: public void flush() throws BadLocationException 636: { 637: // Nothing to do here. 638: } 639: 640: /** 641: * Handle HTML comment, present in the given position. 642: * @param comment the comment 643: * @position the position of the comment in the text being parsed. 644: */ 645: public void handleComment(char[] comment, int position) 646: { 647: // Nothing to do here. 648: } 649: 650: /** 651: * Notifies about the character sequences, used to separate lines in 652: * this document. The parser calls this method after it finishes 653: * parsing the document, but before flush(). 654: * @param end_of_line The "end of line sequence", one of: \r or \n or \r\n. 655: */ 656: public void handleEndOfLineString(String end_of_line) 657: { 658: // Nothing to do here. 659: } 660: 661: /** 662: * The method is called when the HTML closing tag ((like </table>) 663: * is found or if the parser concludes that the one should be present 664: * in the current position. 665: * @param tag The tag being handled 666: * @param position the tag position in the text being parsed. 667: */ 668: public void handleEndTag(HTML.Tag tag, int position) 669: { 670: // Nothing to do here. 671: } 672: 673: /** 674: * Handle the error. 675: * @param message The message, explaining the error. 676: * @param position The starting position of the fragment that has caused 677: * the error in the html document being parsed. 678: */ 679: public void handleError(String message, int position) 680: { 681: // Nothing to do here. 682: } 683: 684: /** 685: * Handle the tag with no content, like <br>. The method is 686: * called for the elements that, in accordance with the current DTD, 687: * has an empty content. 688: * @param tag The tag being handled. 689: * @param position The tag position in the text being parsed. 690: */ 691: public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes, 692: int position) 693: { 694: // Nothing to do here. 695: } 696: 697: /** 698: * The method is called when the HTML opening tag ((like <table>) 699: * is found or if the parser concludes that the one should be present 700: * in the current position. 701: * @param tag The tag being handled 702: * @param position The tag position in the text being parsed 703: */ 704: public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes, 705: int position) 706: { 707: // Nothing to do here. 708: } 709: 710: /** 711: * Handle the text section. 712: * @param text A section text. 713: * @param position The text position in the HTML document text being parsed. 714: */ 715: public void handleText(char[] text, int position) 716: { 717: // Nothing to do here. 718: } 719: } 720: 721: /** 722: * Use serialVersionUID (v1.4) for interoperability. 723: */ 724: private static final long serialVersionUID = 8751997116710384592L; 725: 726: /** 727: * Default cascading stylesheed file ("default.css"). 728: */ 729: public static final String DEFAULT_CSS = "default.css"; 730: 731: /** 732: * The <b>bold</b> action identifier. 733: */ 734: public static final String BOLD_ACTION = "html-bold-action"; 735: 736: /** 737: * The <i>italic</i> action identifier. 738: */ 739: public static final String ITALIC_ACTION = "html-italic-action"; 740: 741: /** 742: * The <font color="#FF0000">color</font> action indentifier 743: * (passing the color as an argument). 744: */ 745: public static final String COLOR_ACTION = "html-color-action"; 746: 747: /** 748: * The <font size="+1">increase</font> font action identifier. 749: */ 750: public static final String FONT_CHANGE_BIGGER = "html-font-bigger"; 751: 752: /** 753: * The <font size="-1">decrease</font> font action identifier. 754: */ 755: public static final String FONT_CHANGE_SMALLER = "html-font-smaller"; 756: 757: /** 758: * Align images at the bottom. 759: */ 760: public static final String IMG_ALIGN_BOTTOM = "html-image-align-bottom"; 761: 762: /** 763: * Align images at the middle. 764: */ 765: public static final String IMG_ALIGN_MIDDLE = "html-image-align-middle"; 766: 767: /** 768: * Align images at the top. 769: */ 770: public static final String IMG_ALIGN_TOP = "html-image-align-top"; 771: 772: /** 773: * Align images at the border. 774: */ 775: public static final String IMG_BORDER = "html-image-border"; 776: 777: /** 778: * The "logical style" action identifier, passing that style as parameter. 779: */ 780: public static final String LOGICAL_STYLE_ACTION = "html-logical-style-action"; 781: 782: /** 783: * The "ident paragraph left" action. 784: */ 785: public static final String PARA_INDENT_LEFT = "html-para-indent-left"; 786: 787: /** 788: * The "ident paragraph right" action. 789: */ 790: public static final String PARA_INDENT_RIGHT = "html-para-indent-right"; 791: 792: /** 793: * Actions for HTML 794: */ 795: private static final Action[] defaultActions = { 796: // FIXME: Add default actions for html 797: }; 798: 799: /** 800: * The current style sheet. 801: */ 802: StyleSheet styleSheet; 803: 804: /** 805: * The ViewFactory for HTMLFactory. 806: */ 807: HTMLFactory viewFactory; 808: 809: /** 810: * The Cursor for links. 811: */ 812: Cursor linkCursor; 813: 814: /** 815: * The default cursor. 816: */ 817: Cursor defaultCursor; 818: 819: /** 820: * The parser. 821: */ 822: Parser parser; 823: 824: /** 825: * The mouse listener used for links. 826: */ 827: LinkController mouseListener; 828: 829: /** 830: * Style context for this editor. 831: */ 832: StyleContext styleContext; 833: 834: /** The content type */ 835: String contentType = "text/html"; 836: 837: /** The input attributes defined by default.css */ 838: MutableAttributeSet inputAttributes; 839: 840: /** The editor pane used. */ 841: JEditorPane editorPane; 842: 843: /** 844: * Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet. 845: */ 846: public HTMLEditorKit() 847: { 848: super(); 849: styleContext = new StyleContext(); 850: styleSheet = new StyleSheet(); 851: styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS)); 852: // FIXME: Set inputAttributes with default.css 853: } 854: 855: /** 856: * Gets a factory suitable for producing views of any 857: * models that are produced by this kit. 858: * 859: * @return the view factory suitable for producing views. 860: */ 861: public ViewFactory getViewFactory() 862: { 863: if (viewFactory == null) 864: viewFactory = new HTMLFactory(); 865: return viewFactory; 866: } 867: 868: /** 869: * Create a text storage model for this type of editor. 870: * 871: * @return the model 872: */ 873: public Document createDefaultDocument() 874: { 875: HTMLDocument document = new HTMLDocument(getStyleSheet()); 876: document.setParser(getParser()); 877: return document; 878: } 879: 880: /** 881: * Get the parser that this editor kit uses for reading HTML streams. This 882: * method can be overridden to use the alternative parser. 883: * 884: * @return the HTML parser (by default, {@link ParserDelegator}). 885: */ 886: protected Parser getParser() 887: { 888: if (parser == null) 889: parser = new ParserDelegator(); 890: return parser; 891: } 892: 893: /** 894: * Inserts HTML into an existing document. 895: * 896: * @param doc - the Document to insert the HTML into. 897: * @param offset - where to begin inserting the HTML. 898: * @param html - the String to insert 899: * @param popDepth - the number of ElementSpec.EndTagTypes 900: * to generate before inserting 901: * @param pushDepth - the number of ElementSpec.StartTagTypes 902: * with a direction of ElementSpec.JoinNextDirection that 903: * should be generated before 904: * @param insertTag - the first tag to start inserting into document 905: * @throws IOException - on any I/O error 906: * @throws BadLocationException - if pos represents an invalid location 907: * within the document 908: */ 909: public void insertHTML(HTMLDocument doc, int offset, String html, 910: int popDepth, int pushDepth, HTML.Tag insertTag) 911: throws BadLocationException, IOException 912: { 913: Parser parser = getParser(); 914: if (offset < 0 || offset > doc.getLength()) 915: throw new BadLocationException("Bad location", offset); 916: if (parser == null) 917: throw new IOException("Parser is null."); 918: 919: ParserCallback pc = ((HTMLDocument) doc).getReader 920: (offset, popDepth, pushDepth, insertTag); 921: 922: // FIXME: What should ignoreCharSet be set to? 923: 924: // parser.parse inserts html into the buffer 925: parser.parse(new StringReader(html), pc, false); 926: pc.flush(); 927: } 928: 929: /** 930: * Inserts content from the given stream. Inserting HTML into a non-empty 931: * document must be inside the body Element, if you do not insert into 932: * the body an exception will be thrown. When inserting into a non-empty 933: * document all tags outside of the body (head, title) will be dropped. 934: * 935: * @param in - the stream to read from 936: * @param doc - the destination for the insertion 937: * @param pos - the location in the document to place the content 938: * @throws IOException - on any I/O error 939: * @throws BadLocationException - if pos represents an invalid location 940: * within the document 941: */ 942: public void read(Reader in, Document doc, int pos) throws IOException, 943: BadLocationException 944: { 945: if (doc instanceof HTMLDocument) 946: { 947: Parser parser = getParser(); 948: if (pos < 0 || pos > doc.getLength()) 949: throw new BadLocationException("Bad location", pos); 950: if (parser == null) 951: throw new IOException("Parser is null."); 952: 953: HTMLDocument hd = ((HTMLDocument) doc); 954: if (editorPane != null) 955: hd.setBase(editorPane.getPage()); 956: ParserCallback pc = hd.getReader(pos); 957: 958: // FIXME: What should ignoreCharSet be set to? 959: 960: // parser.parse inserts html into the buffer 961: parser.parse(in, pc, false); 962: pc.flush(); 963: } 964: else 965: // read in DefaultEditorKit is called. 966: // the string is inserted in the document as usual. 967: super.read(in, doc, pos); 968: } 969: 970: /** 971: * Writes content from a document to the given stream in 972: * an appropriate format. 973: * 974: * @param out - the stream to write to 975: * @param doc - the source for the write 976: * @param pos - the location in the document to get the content. 977: * @param len - the amount to write out 978: * @throws IOException - on any I/O error 979: * @throws BadLocationException - if pos represents an invalid location 980: * within the document 981: */ 982: public void write(Writer out, Document doc, int pos, int len) 983: throws IOException, BadLocationException 984: { 985: if (doc instanceof HTMLDocument) 986: { 987: // FIXME: Not implemented. Use HTMLWriter. 988: out.write(doc.getText(pos, len)); 989: } 990: else 991: super.write(out, doc, pos, len); 992: } 993: 994: /** 995: * Gets the content type that the kit supports. 996: * This kit supports the type text/html. 997: * 998: * @returns the content type supported. 999: */ 1000: public String getContentType() 1001: { 1002: return contentType; 1003: } 1004: 1005: /** 1006: * Creates a copy of the editor kit. 1007: * 1008: * @return a copy of this. 1009: */ 1010: public Object clone() 1011: { 1012: // FIXME: Need to clone all fields 1013: return (HTMLEditorKit) super.clone(); 1014: } 1015: 1016: /** 1017: * Copies the key/values in elements AttributeSet into set. 1018: * This does not copy component, icon, or element names attributes. 1019: * This is called anytime the caret moves over a different location. 1020: * 1021: * @param element - the element to create the input attributes for. 1022: * @param set - the set to copy the values into. 1023: */ 1024: protected void createInputAttributes(Element element, 1025: MutableAttributeSet set) 1026: { 1027: set.removeAttributes(set); 1028: set.addAttributes(element.getAttributes()); 1029: // FIXME: Not fully implemented. 1030: } 1031: 1032: /** 1033: * Called when this is installed into the JEditorPane. 1034: * 1035: * @param c - the JEditorPane installed into. 1036: */ 1037: public void install(JEditorPane c) 1038: { 1039: super.install(c); 1040: mouseListener = new LinkController(); 1041: c.addMouseListener(mouseListener); 1042: editorPane = c; 1043: // FIXME: need to set up hyperlinklistener object 1044: } 1045: 1046: /** 1047: * Called when the this is removed from the JEditorPane. 1048: * It unregisters any listeners. 1049: * 1050: * @param c - the JEditorPane being removed from. 1051: */ 1052: public void deinstall(JEditorPane c) 1053: { 1054: super.deinstall(c); 1055: c.removeMouseListener(mouseListener); 1056: mouseListener = null; 1057: editorPane = null; 1058: } 1059: 1060: /** 1061: * Gets the AccessibleContext associated with this. 1062: * 1063: * @return the AccessibleContext for this. 1064: */ 1065: public AccessibleContext getAccessibleContext() 1066: { 1067: // FIXME: Should return an instance of 1068: // javax.swing.text.html.AccessibleHTML$RootHTMLAccessibleContext 1069: // Not implemented yet. 1070: return null; 1071: } 1072: 1073: /** 1074: * Gets the action list. This list is supported by the superclass 1075: * augmented by the collection of actions defined locally for style 1076: * operations. 1077: * 1078: * @return an array of all the actions 1079: */ 1080: public Action[] getActions() 1081: { 1082: return TextAction.augmentList(super.getActions(), defaultActions); 1083: } 1084: 1085: /** 1086: * Returns the default cursor. 1087: * 1088: * @return the default cursor 1089: */ 1090: public Cursor getDefaultCursor() 1091: { 1092: if (defaultCursor == null) 1093: defaultCursor = Cursor.getDefaultCursor(); 1094: return defaultCursor; 1095: } 1096: 1097: /** 1098: * Returns the cursor for links. 1099: * 1100: * @return the cursor for links. 1101: */ 1102: public Cursor getLinkCursor() 1103: { 1104: if (linkCursor == null) 1105: linkCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR); 1106: return linkCursor; 1107: } 1108: 1109: /** 1110: * Sets the Cursor for links. 1111: * 1112: * @param cursor - the new cursor for links. 1113: */ 1114: public void setLinkCursor(Cursor cursor) 1115: { 1116: linkCursor = cursor; 1117: } 1118: 1119: /** 1120: * Sets the default cursor. 1121: * 1122: * @param cursor - the new default cursor. 1123: */ 1124: public void setDefaultCursor(Cursor cursor) 1125: { 1126: defaultCursor = cursor; 1127: } 1128: 1129: /** 1130: * Gets the input attributes used for the styled editing actions. 1131: * 1132: * @return the attribute set 1133: */ 1134: public MutableAttributeSet getInputAttributes() 1135: { 1136: return inputAttributes; 1137: } 1138: 1139: /** 1140: * Get the set of styles currently being used to render the HTML elements. 1141: * By default the resource specified by DEFAULT_CSS gets loaded, and is 1142: * shared by all HTMLEditorKit instances. 1143: * 1144: * @return the style sheet. 1145: */ 1146: public StyleSheet getStyleSheet() 1147: { 1148: if (styleSheet == null) 1149: { 1150: styleSheet = new StyleSheet(); 1151: styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS)); 1152: } 1153: return styleSheet; 1154: } 1155: 1156: /** 1157: * Set the set of styles to be used to render the various HTML elements. 1158: * These styles are specified in terms of CSS specifications. Each document 1159: * produced by the kit will have a copy of the sheet which it can add the 1160: * document specific styles to. By default, the StyleSheet specified is shared 1161: * by all HTMLEditorKit instances. 1162: * 1163: * @param s - the new style sheet 1164: */ 1165: public void setStyleSheet(StyleSheet s) 1166: { 1167: styleSheet = s; 1168: } 1169: }
GNU Classpath (0.91) |