Source for javax.swing.JEditorPane

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