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