Frames | No Frames |
1: /* JEditorPane.java -- 2: Copyright (C) 2002, 2004, 2005, 2006, 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; 40: 41: import java.awt.Container; 42: import java.awt.Dimension; 43: import java.io.IOException; 44: import java.io.InputStream; 45: import java.io.InputStreamReader; 46: import java.io.Reader; 47: import java.io.StringReader; 48: import java.net.MalformedURLException; 49: import java.net.URL; 50: import java.util.HashMap; 51: 52: import javax.accessibility.AccessibleContext; 53: import javax.accessibility.AccessibleHyperlink; 54: import javax.accessibility.AccessibleHypertext; 55: import javax.accessibility.AccessibleStateSet; 56: import javax.accessibility.AccessibleText; 57: import javax.swing.event.HyperlinkEvent; 58: import javax.swing.event.HyperlinkListener; 59: import javax.swing.text.BadLocationException; 60: import javax.swing.text.DefaultEditorKit; 61: import javax.swing.text.Document; 62: import javax.swing.text.EditorKit; 63: import javax.swing.text.Element; 64: import javax.swing.text.JTextComponent; 65: import javax.swing.text.View; 66: import javax.swing.text.ViewFactory; 67: import javax.swing.text.WrappedPlainView; 68: import javax.swing.text.html.HTML; 69: import javax.swing.text.html.HTMLDocument; 70: import javax.swing.text.html.HTMLEditorKit; 71: 72: /** 73: * A powerful text editor component that can handle different types of 74: * content. 75: * 76: * The JEditorPane text component is driven by an instance of 77: * {@link EditorKit}. The editor kit is responsible for providing 78: * a default {@link Document} implementation, a mechanism for loading 79: * and saving documents of its supported content type and providing 80: * a set of {@link Action}s for manipulating the content. 81: * 82: * By default the following content types are supported: 83: * <ul> 84: * <li><code>text/plain</code>: Plain text, handled by 85: * {@link javax.swing.text.DefaultEditorKit}.</li> 86: * <li><code>text/html</code>: HTML 4.0 styled text, handled by 87: * {@link javax.swing.text.html.HTMLEditorKit}.</li> 88: * <li><code>text/rtf</code>: RTF text, handled by 89: * {@link javax.swing.text.rtf.RTFEditorKit}.</li> 90: * </ul> 91: * 92: * @author original author unknown 93: * @author Roman Kennke (roman@kennke.org) 94: * @author Anthony Balkissoon abalkiss at redhat dot com 95: */ 96: public class JEditorPane extends JTextComponent 97: { 98: /** 99: * Provides accessibility support for <code>JEditorPane</code>. 100: * 101: * @author Roman Kennke (kennke@aicas.com) 102: */ 103: protected class AccessibleJEditorPane extends AccessibleJTextComponent 104: { 105: 106: /** 107: * Creates a new <code>AccessibleJEditorPane</code> object. 108: */ 109: protected AccessibleJEditorPane() 110: { 111: super(); 112: } 113: 114: /** 115: * Returns a description of this <code>AccessibleJEditorPane</code>. If 116: * this property is not set, then this returns the content-type of the 117: * editor pane. 118: * 119: * @return a description of this AccessibleJEditorPane 120: */ 121: public String getAccessibleDescription() 122: { 123: String descr = super.getAccessibleDescription(); 124: if (descr == null) 125: return getContentType(); 126: else 127: return descr; 128: } 129: 130: /** 131: * Returns the accessible state of this <code>AccessibleJEditorPane</code>. 132: * 133: * @return the accessible state of this <code>AccessibleJEditorPane</code> 134: */ 135: public AccessibleStateSet getAccessibleStateSet() 136: { 137: AccessibleStateSet state = super.getAccessibleStateSet(); 138: // TODO: Figure out what state must be added here to the super's state. 139: return state; 140: } 141: } 142: 143: /** 144: * Provides accessibility support for <code>JEditorPane</code>s, when the 145: * editor kit is an instance of {@link HTMLEditorKit}. 146: * 147: * @author Roman Kennke (kennke@aicas.com) 148: */ 149: protected class AccessibleJEditorPaneHTML extends AccessibleJEditorPane 150: { 151: /** 152: * Returns the accessible text of the <code>JEditorPane</code>. This will 153: * be an instance of 154: * {@link JEditorPaneAccessibleHypertextSupport}. 155: * 156: * @return the accessible text of the <code>JEditorPane</code> 157: */ 158: public AccessibleText getAccessibleText() 159: { 160: return new JEditorPaneAccessibleHypertextSupport(); 161: } 162: } 163: 164: /** 165: * This is the accessible text that is returned by 166: * {@link AccessibleJEditorPaneHTML#getAccessibleText()}. 167: * 168: * @author Roman Kennke (kennke@aicas.com) 169: */ 170: protected class JEditorPaneAccessibleHypertextSupport 171: extends AccessibleJEditorPane implements AccessibleHypertext 172: { 173: 174: /** 175: * Creates a new JEditorPaneAccessibleHypertextSupport object. 176: */ 177: public JEditorPaneAccessibleHypertextSupport() 178: { 179: super(); 180: } 181: 182: /** 183: * The accessible representation of a HTML link. 184: * 185: * @author Roman Kennke (kennke@aicas.com) 186: */ 187: public class HTMLLink extends AccessibleHyperlink 188: { 189: 190: /** 191: * The element in the document that represents the link. 192: */ 193: Element element; 194: 195: /** 196: * Creates a new <code>HTMLLink</code>. 197: * 198: * @param el the link element 199: */ 200: public HTMLLink(Element el) 201: { 202: this.element = el; 203: } 204: 205: /** 206: * Returns <code>true</code> if this <code>HTMLLink</code> is still 207: * valid. A <code>HTMLLink</code> can become invalid when the document 208: * changes. 209: * 210: * @return <code>true</code> if this <code>HTMLLink</code> is still 211: * valid 212: */ 213: public boolean isValid() 214: { 215: // I test here if the element at our element's start offset is the 216: // same as the element in the document at this offset. If this is true, 217: // I consider the link valid, if not, then this link no longer 218: // represented by this HTMLLink and therefor invalid. 219: HTMLDocument doc = (HTMLDocument) getDocument(); 220: return doc.getCharacterElement(element.getStartOffset()) == element; 221: } 222: 223: /** 224: * Returns the number of AccessibleActions in this link object. In 225: * general, link have 1 AccessibleAction associated with them. There are 226: * special cases where links can have multiple actions associated, like 227: * in image maps. 228: * 229: * @return the number of AccessibleActions in this link object 230: */ 231: public int getAccessibleActionCount() 232: { 233: // TODO: Implement the special cases. 234: return 1; 235: } 236: 237: /** 238: * Performs the specified action on the link object. This ususally means 239: * activating the link. 240: * 241: * @return <code>true</code> if the action has been performed 242: * successfully, <code>false</code> otherwise 243: */ 244: public boolean doAccessibleAction(int i) 245: { 246: String href = (String) element.getAttributes().getAttribute("href"); 247: HTMLDocument doc = (HTMLDocument) getDocument(); 248: try 249: { 250: URL url = new URL(doc.getBase(), href); 251: setPage(url); 252: String desc = doc.getText(element.getStartOffset(), 253: element.getEndOffset() - element.getStartOffset()); 254: HyperlinkEvent ev = 255: new HyperlinkEvent(JEditorPane.this, 256: HyperlinkEvent.EventType.ACTIVATED, url, desc, 257: element); 258: fireHyperlinkUpdate(ev); 259: return true; 260: } 261: catch (Exception ex) 262: { 263: return false; 264: } 265: } 266: 267: /** 268: * Returns the description of the action at action index <code>i</code>. 269: * This method returns the text within the element associated with this 270: * link. 271: * 272: * @param i the action index 273: * 274: * @return the description of the action at action index <code>i</code> 275: */ 276: public String getAccessibleActionDescription(int i) 277: { 278: HTMLDocument doc = (HTMLDocument) getDocument(); 279: try 280: { 281: return doc.getText(element.getStartOffset(), 282: element.getEndOffset() - element.getStartOffset()); 283: } 284: catch (BadLocationException ex) 285: { 286: throw (AssertionError) 287: new AssertionError("BadLocationException must not be thrown " 288: + "here.") 289: .initCause(ex); 290: } 291: } 292: 293: /** 294: * Returns an {@link URL} object, that represents the action at action 295: * index <code>i</code>. 296: * 297: * @param i the action index 298: * 299: * @return an {@link URL} object, that represents the action at action 300: * index <code>i</code> 301: */ 302: public Object getAccessibleActionObject(int i) 303: { 304: String href = (String) element.getAttributes().getAttribute("href"); 305: HTMLDocument doc = (HTMLDocument) getDocument(); 306: try 307: { 308: URL url = new URL(doc.getBase(), href); 309: return url; 310: } 311: catch (MalformedURLException ex) 312: { 313: return null; 314: } 315: } 316: 317: /** 318: * Returns an object that represents the link anchor. For examples, if 319: * the link encloses a string, then a <code>String</code> object is 320: * returned, if the link encloses an <img> tag, then an 321: * <code>ImageIcon</code> object is returned. 322: * 323: * @return an object that represents the link anchor 324: */ 325: public Object getAccessibleActionAnchor(int i) 326: { 327: // TODO: This is only the String case. Implement all cases. 328: return getAccessibleActionDescription(i); 329: } 330: 331: /** 332: * Returns the start index of the hyperlink element. 333: * 334: * @return the start index of the hyperlink element 335: */ 336: public int getStartIndex() 337: { 338: return element.getStartOffset(); 339: } 340: 341: /** 342: * Returns the end index of the hyperlink element. 343: * 344: * @return the end index of the hyperlink element 345: */ 346: public int getEndIndex() 347: { 348: return element.getEndOffset(); 349: } 350: 351: } 352: 353: /** 354: * Returns the number of hyperlinks in the document. 355: * 356: * @return the number of hyperlinks in the document 357: */ 358: public int getLinkCount() 359: { 360: HTMLDocument doc = (HTMLDocument) getDocument(); 361: HTMLDocument.Iterator linkIter = doc.getIterator(HTML.Tag.A); 362: int count = 0; 363: while (linkIter.isValid()) 364: { 365: count++; 366: linkIter.next(); 367: } 368: return count; 369: } 370: 371: /** 372: * Returns the <code>i</code>-th hyperlink in the document or 373: * <code>null</code> if there is no hyperlink with the specified index. 374: * 375: * @param i the index of the hyperlink to return 376: * 377: * @return the <code>i</code>-th hyperlink in the document or 378: * <code>null</code> if there is no hyperlink with the specified 379: * index 380: */ 381: public AccessibleHyperlink getLink(int i) 382: { 383: HTMLDocument doc = (HTMLDocument) getDocument(); 384: HTMLDocument.Iterator linkIter = doc.getIterator(HTML.Tag.A); 385: int count = 0; 386: while (linkIter.isValid()) 387: { 388: count++; 389: if (count == i) 390: break; 391: linkIter.next(); 392: } 393: if (linkIter.isValid()) 394: { 395: int offset = linkIter.getStartOffset(); 396: // TODO: I fetch the element for the link via getCharacterElement(). 397: // I am not sure that this is correct, maybe we must use 398: // getParagraphElement()? 399: Element el = doc.getCharacterElement(offset); 400: HTMLLink link = new HTMLLink(el); 401: return link; 402: } 403: else 404: return null; 405: } 406: 407: /** 408: * Returns the index of the link element at the character position 409: * <code>c</code> within the document, or <code>-1</code> if there is no 410: * link at the specified position. 411: * 412: * @param c the character index from which to fetch the link index 413: * 414: * @return the index of the link element at the character position 415: * <code>c</code> within the document, or <code>-1</code> if there 416: * is no link at the specified position 417: */ 418: public int getLinkIndex(int c) 419: { 420: HTMLDocument doc = (HTMLDocument) getDocument(); 421: HTMLDocument.Iterator linkIter = doc.getIterator(HTML.Tag.A); 422: int count = 0; 423: while (linkIter.isValid()) 424: { 425: if (linkIter.getStartOffset() <= c && linkIter.getEndOffset() > c) 426: break; 427: count++; 428: linkIter.next(); 429: } 430: if (linkIter.isValid()) 431: return count; 432: else 433: return -1; 434: } 435: 436: /** 437: * Returns the link text of the link at index <code>i</code>, or 438: * <code>null</code>, if there is no link at the specified position. 439: * 440: * @param i the index of the link 441: * 442: * @return the link text of the link at index <code>i</code>, or 443: * <code>null</code>, if there is no link at the specified 444: * position 445: */ 446: public String getLinkText(int i) 447: { 448: HTMLDocument doc = (HTMLDocument) getDocument(); 449: HTMLDocument.Iterator linkIter = doc.getIterator(HTML.Tag.A); 450: int count = 0; 451: while (linkIter.isValid()) 452: { 453: count++; 454: if (count == i) 455: break; 456: linkIter.next(); 457: } 458: if (linkIter.isValid()) 459: { 460: int offset = linkIter.getStartOffset(); 461: // TODO: I fetch the element for the link via getCharacterElement(). 462: // I am not sure that this is correct, maybe we must use 463: // getParagraphElement()? 464: Element el = doc.getCharacterElement(offset); 465: try 466: { 467: String text = doc.getText(el.getStartOffset(), 468: el.getEndOffset() - el.getStartOffset()); 469: return text; 470: } 471: catch (BadLocationException ex) 472: { 473: throw (AssertionError) 474: new AssertionError("BadLocationException must not be thrown " 475: + "here.") 476: .initCause(ex); 477: } 478: } 479: else 480: return null; 481: } 482: } 483: 484: /** 485: * An EditorKit used for plain text. This is the default editor kit for 486: * JEditorPanes. 487: * 488: * @author Roman Kennke (kennke@aicas.com) 489: */ 490: private static class PlainEditorKit extends DefaultEditorKit 491: { 492: 493: /** 494: * Returns a ViewFactory that supplies WrappedPlainViews. 495: */ 496: public ViewFactory getViewFactory() 497: { 498: return new ViewFactory() 499: { 500: public View create(Element el) 501: { 502: return new WrappedPlainView(el); 503: } 504: }; 505: } 506: } 507: 508: private static final long serialVersionUID = 3140472492599046285L; 509: 510: private URL page; 511: private EditorKit editorKit; 512: 513: boolean focus_root; 514: 515: // A mapping between content types and registered EditorKit types 516: static HashMap registerMap; 517: 518: // A mapping between content types and used EditorKits 519: HashMap editorMap; 520: 521: public JEditorPane() 522: { 523: init(); 524: setEditorKit(createDefaultEditorKit()); 525: } 526: 527: public JEditorPane(String url) throws IOException 528: { 529: this(new URL(url)); 530: } 531: 532: public JEditorPane(String type, String text) 533: { 534: init(); 535: setEditorKit(createEditorKitForContentType(type)); 536: setText(text); 537: } 538: 539: public JEditorPane(URL url) throws IOException 540: { 541: init(); 542: setEditorKit(createEditorKitForContentType("text/html"));; 543: setPage(url); 544: } 545: 546: /** 547: * Called by the constructors to set up the default bindings for content 548: * types and EditorKits. 549: */ 550: void init() 551: { 552: editorMap = new HashMap(); 553: registerMap = new HashMap(); 554: registerEditorKitForContentType("application/rtf", 555: "javax.swing.text.rtf.RTFEditorKit"); 556: registerEditorKitForContentType("text/plain", 557: "javax.swing.JEditorPane$PlainEditorKit"); 558: registerEditorKitForContentType("text/html", 559: "javax.swing.text.html.HTMLEditorKit"); 560: registerEditorKitForContentType("text/rtf", 561: "javax.swing.text.rtf.RTFEditorKit"); 562: } 563: 564: protected EditorKit createDefaultEditorKit() 565: { 566: return new PlainEditorKit(); 567: } 568: 569: /** 570: * Creates and returns an EditorKit that is appropriate for the given 571: * content type. This is created using the default recognized types 572: * plus any EditorKit types that have been registered. 573: * 574: * @see #registerEditorKitForContentType(String, String) 575: * @see #registerEditorKitForContentType(String, String, ClassLoader) 576: * @param type the content type 577: * @return an EditorKit for use with the given content type 578: */ 579: public static EditorKit createEditorKitForContentType(String type) 580: { 581: // TODO: Have to handle the case where a ClassLoader was specified 582: // when the EditorKit was registered 583: EditorKit e = null; 584: String className = (String) registerMap.get(type); 585: if (className != null) 586: { 587: try 588: { 589: e = (EditorKit) Class.forName(className).newInstance(); 590: } 591: catch (Exception e2) 592: { 593: // TODO: Not sure what to do here. 594: } 595: } 596: return e; 597: } 598: 599: /** 600: * Sends a given <code>HyperlinkEvent</code> to all registered listeners. 601: * 602: * @param event the event to send 603: */ 604: public void fireHyperlinkUpdate(HyperlinkEvent event) 605: { 606: HyperlinkListener[] listeners = getHyperlinkListeners(); 607: 608: for (int index = 0; index < listeners.length; ++index) 609: listeners[index].hyperlinkUpdate(event); 610: } 611: 612: /** 613: * Returns the accessible context associated with this editor pane. 614: * 615: * @return the accessible context associated with this editor pane 616: */ 617: public AccessibleContext getAccessibleContext() 618: { 619: if (accessibleContext == null) 620: { 621: if (getEditorKit() instanceof HTMLEditorKit) 622: accessibleContext = new AccessibleJEditorPaneHTML(); 623: else 624: accessibleContext = new AccessibleJEditorPane(); 625: } 626: return accessibleContext; 627: } 628: 629: public final String getContentType() 630: { 631: return getEditorKit().getContentType(); 632: } 633: 634: /** 635: * Returns the EditorKit. If there is no EditorKit set this method 636: * calls createDefaultEditorKit() and setEditorKit() first. 637: */ 638: public EditorKit getEditorKit() 639: { 640: if (editorKit == null) 641: setEditorKit(createDefaultEditorKit()); 642: return editorKit; 643: } 644: 645: /** 646: * Returns the class name of the EditorKit associated with the given 647: * content type. 648: * 649: * @since 1.3 650: * @param type the content type 651: * @return the class name of the EditorKit associated with this content type 652: */ 653: public static String getEditorKitClassNameForContentType(String type) 654: { 655: return (String) registerMap.get(type); 656: } 657: 658: /** 659: * Returns the EditorKit to use for the given content type. If an 660: * EditorKit has been explicitly set via 661: * <code>setEditorKitForContentType</code> 662: * then it will be returned. Otherwise an attempt will be made to create 663: * an EditorKit from the default recognzied content types or any 664: * EditorKits that have been registered. If none can be created, a 665: * PlainEditorKit is created. 666: * 667: * @see #registerEditorKitForContentType(String, String) 668: * @see #registerEditorKitForContentType(String, String, ClassLoader) 669: * @param type the content type 670: * @return an appropriate EditorKit for the given content type 671: */ 672: public EditorKit getEditorKitForContentType(String type) 673: { 674: // First check if an EditorKit has been explicitly set. 675: EditorKit e = (EditorKit) editorMap.get(type); 676: // Then check to see if we can create one. 677: if (e == null) 678: e = createEditorKitForContentType(type); 679: // Otherwise default to PlainEditorKit. 680: if (e == null) 681: e = new PlainEditorKit(); 682: return e; 683: } 684: 685: /** 686: * Returns the preferred size for the JEditorPane. This is implemented to 687: * return the super's preferred size, unless one of 688: * {@link #getScrollableTracksViewportHeight()} or 689: * {@link #getScrollableTracksViewportWidth()} returns <code>true</code>, 690: * in which case the preferred width and/or height is replaced by the UI's 691: * minimum size. 692: * 693: * @return the preferred size for the JEditorPane 694: */ 695: public Dimension getPreferredSize() 696: { 697: Dimension pref = super.getPreferredSize(); 698: if (getScrollableTracksViewportWidth()) 699: pref.width = getUI().getMinimumSize(this).width; 700: if (getScrollableTracksViewportHeight()) 701: pref.height = getUI().getMinimumSize(this).height; 702: return pref; 703: } 704: 705: /** 706: * Returns <code>true</code> when a Viewport should force the height of 707: * this component to match the viewport height. This is implemented to return 708: * <code>true</code> when the parent is an instance of JViewport and 709: * the viewport height > the UI's minimum height. 710: * 711: * @return <code>true</code> when a Viewport should force the height of 712: * this component to match the viewport height 713: */ 714: public boolean getScrollableTracksViewportHeight() 715: { 716: // Tests show that this returns true when the parent is a JViewport 717: // and has a height > minimum UI height. 718: Container parent = getParent(); 719: return parent instanceof JViewport 720: && parent.getHeight() > getUI().getMinimumSize(this).height; 721: } 722: 723: /** 724: * Returns <code>true</code> when a Viewport should force the width of 725: * this component to match the viewport width. This is implemented to return 726: * <code>true</code> when the parent is an instance of JViewport and 727: * the viewport width > the UI's minimum width. 728: * 729: * @return <code>true</code> when a Viewport should force the width of 730: * this component to match the viewport width 731: */ 732: public boolean getScrollableTracksViewportWidth() 733: { 734: // Tests show that this returns true when the parent is a JViewport 735: // and has a width > minimum UI width. 736: Container parent = getParent(); 737: return parent != null && parent instanceof JViewport 738: && parent.getWidth() > getUI().getMinimumSize(this).width; 739: } 740: 741: public URL getPage() 742: { 743: return page; 744: } 745: 746: protected InputStream getStream(URL page) 747: throws IOException 748: { 749: return page.openStream(); 750: } 751: 752: public String getText() 753: { 754: return super.getText(); 755: } 756: 757: public String getUIClassID() 758: { 759: return "EditorPaneUI"; 760: } 761: 762: public boolean isFocusCycleRoot() 763: { 764: return focus_root; 765: } 766: 767: protected String paramString() 768: { 769: return "JEditorPane"; 770: } 771: 772: /** 773: * This method initializes from a stream. 774: */ 775: public void read(InputStream in, Object desc) throws IOException 776: { 777: EditorKit kit = getEditorKit(); 778: if (kit instanceof HTMLEditorKit && desc instanceof HTMLDocument) 779: { 780: Document doc = (Document) desc; 781: try 782: { 783: kit.read(in, doc, 0); 784: } 785: catch (BadLocationException ex) 786: { 787: assert false : "BadLocationException must not be thrown here."; 788: } 789: } 790: else 791: { 792: Reader inRead = new InputStreamReader(in); 793: super.read(inRead, desc); 794: } 795: } 796: 797: /** 798: * Establishes a binding between type and classname. This enables 799: * us to create an EditorKit later for the given content type. 800: * 801: * @param type the content type 802: * @param classname the name of the class that is associated with this 803: * content type 804: */ 805: public static void registerEditorKitForContentType(String type, 806: String classname) 807: { 808: registerMap.put(type, classname); 809: } 810: 811: /** 812: * Establishes the default bindings of type to classname. 813: */ 814: public static void registerEditorKitForContentType(String type, 815: String classname, 816: ClassLoader loader) 817: { 818: // TODO: Implement this properly. 819: } 820: 821: /** 822: * Replaces the currently selected content with new content represented 823: * by the given string. 824: */ 825: public void replaceSelection(String content) 826: { 827: // TODO: Implement this properly. 828: super.replaceSelection(content); 829: } 830: 831: /** 832: * Scrolls the view to the given reference location (that is, the value 833: * returned by the UL.getRef method for the URL being displayed). 834: */ 835: public void scrollToReference(String reference) 836: { 837: // TODO: Implement this properly. 838: } 839: 840: public final void setContentType(String type) 841: { 842: if (editorKit != null 843: && editorKit.getContentType().equals(type)) 844: return; 845: 846: EditorKit kit = getEditorKitForContentType(type); 847: 848: if (kit != null) 849: setEditorKit(kit); 850: } 851: 852: public void setEditorKit(EditorKit newValue) 853: { 854: if (editorKit == newValue) 855: return; 856: 857: if (editorKit != null) 858: editorKit.deinstall(this); 859: 860: EditorKit oldValue = editorKit; 861: editorKit = newValue; 862: 863: if (editorKit != null) 864: { 865: editorKit.install(this); 866: setDocument(editorKit.createDefaultDocument()); 867: } 868: 869: firePropertyChange("editorKit", oldValue, newValue); 870: invalidate(); 871: repaint(); 872: // Reset the accessibleContext since this depends on the editorKit. 873: accessibleContext = null; 874: } 875: 876: /** 877: * Explicitly sets an EditorKit to be used for the given content type. 878: * @param type the content type 879: * @param k the EditorKit to use for the given content type 880: */ 881: public void setEditorKitForContentType(String type, EditorKit k) 882: { 883: editorMap.put(type, k); 884: } 885: 886: /** 887: * Sets the current URL being displayed. 888: */ 889: public void setPage(String url) throws IOException 890: { 891: setPage(new URL(url)); 892: } 893: 894: /** 895: * Sets the current URL being displayed. 896: */ 897: public void setPage(URL page) throws IOException 898: { 899: if (page == null) 900: throw new IOException("invalid url"); 901: 902: try 903: { 904: this.page = page; 905: getEditorKit().read(page.openStream(), getDocument(), 0); 906: } 907: catch (BadLocationException e) 908: { 909: // Ignored. '0' is always a valid offset. 910: } 911: } 912: 913: /** 914: * Sets the text of the JEditorPane. The argument <code>t</code> 915: * is expected to be in the format of the current EditorKit. This removes 916: * the content of the current document and uses the EditorKit to read in the 917: * new text. This allows the EditorKit to handle the String rather than just 918: * inserting in plain text. 919: * 920: * @param t the text to display in this JEditorPane 921: */ 922: public void setText(String t) 923: { 924: try 925: { 926: // Remove the current content. 927: Document doc = getDocument(); 928: doc.remove(0, doc.getLength()); 929: if (t == null || t.equals("")) 930: return; 931: 932: // Let the EditorKit read the text into the Document. 933: getEditorKit().read(new StringReader(t), doc, 0); 934: } 935: catch (BadLocationException ble) 936: { 937: // TODO: Don't know what to do here. 938: } 939: catch (IOException ioe) 940: { 941: // TODO: Don't know what to do here. 942: } 943: } 944: 945: /** 946: * Add a <code>HyperlinkListener</code> object to this editor pane. 947: * 948: * @param listener the listener to add 949: */ 950: public void addHyperlinkListener(HyperlinkListener listener) 951: { 952: listenerList.add(HyperlinkListener.class, listener); 953: } 954: 955: /** 956: * Removes a <code>HyperlinkListener</code> object to this editor pane. 957: * 958: * @param listener the listener to remove 959: */ 960: public void removeHyperlinkListener(HyperlinkListener listener) 961: { 962: listenerList.remove(HyperlinkListener.class, listener); 963: } 964: 965: /** 966: * Returns all added <code>HyperlinkListener</code> objects. 967: * 968: * @return array of listeners 969: * 970: * @since 1.4 971: */ 972: public HyperlinkListener[] getHyperlinkListeners() 973: { 974: return (HyperlinkListener[]) getListeners(HyperlinkListener.class); 975: } 976: }