jdk/src/share/classes/javax/swing/JEditorPane.java

Print this page




   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing;
  26 
  27 import sun.swing.SwingUtilities2;
  28 
  29 import java.awt.*;
  30 import java.awt.event.*;

  31 import java.lang.reflect.*;
  32 import java.net.*;
  33 import java.util.*;
  34 import java.io.*;
  35 import java.util.*;
  36 
  37 import javax.swing.plaf.*;
  38 import javax.swing.text.*;
  39 import javax.swing.event.*;
  40 import javax.swing.text.html.*;
  41 import javax.accessibility.*;
  42 import sun.reflect.misc.ReflectUtil;
  43 
  44 /**
  45  * A text component to edit various kinds of content.
  46  * You can find how-to information and examples of using editor panes in
  47  * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/text.html">Using Text Components</a>,
  48  * a section in <em>The Java Tutorial.</em>
  49  *
  50  * <p>
  51  * This component uses implementations of the
  52  * <code>EditorKit</code> to accomplish its behavior. It effectively
  53  * morphs into the proper kind of text editor for the kind
  54  * of content it is given.  The content type that editor is bound
  55  * to at any given time is determined by the <code>EditorKit</code> currently


 167  * <dd>
 168  * For a discussion on how newlines are handled, see
 169  * <a href="text/DefaultEditorKit.html">DefaultEditorKit</a>.
 170  * </dl>
 171  *
 172  * <p>
 173  * <strong>Warning:</strong> Swing is not thread safe. For more
 174  * information see <a
 175  * href="package-summary.html#threading">Swing's Threading
 176  * Policy</a>.
 177  * <p>
 178  * <strong>Warning:</strong>
 179  * Serialized objects of this class will not be compatible with
 180  * future Swing releases. The current serialization support is
 181  * appropriate for short term storage or RMI between applications running
 182  * the same version of Swing.  As of 1.4, support for long term storage
 183  * of all JavaBeans&trade;
 184  * has been added to the <code>java.beans</code> package.
 185  * Please see {@link java.beans.XMLEncoder}.
 186  *
 187  * @beaninfo
 188  *   attribute: isContainer false
 189  * description: A text component to edit various types of content.
 190  *
 191  * @author  Timothy Prinzing
 192  * @since 1.2
 193  */


 194 @SuppressWarnings("serial") // Same-version serialization only
 195 public class JEditorPane extends JTextComponent {
 196 
 197     /**
 198      * Creates a new <code>JEditorPane</code>.
 199      * The document model is set to <code>null</code>.
 200      */
 201     public JEditorPane() {
 202         super();
 203         setFocusCycleRoot(true);
 204         setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
 205                 public Component getComponentAfter(Container focusCycleRoot,
 206                                                    Component aComponent) {
 207                     if (focusCycleRoot != JEditorPane.this ||
 208                         (!isEditable() && getComponentCount() > 0)) {
 209                         return super.getComponentAfter(focusCycleRoot,
 210                                                        aComponent);
 211                     } else {
 212                         Container rootAncestor = getFocusCycleRootAncestor();
 213                         return (rootAncestor != null)


 306         listenerList.add(HyperlinkListener.class, listener);
 307     }
 308 
 309     /**
 310      * Removes a hyperlink listener.
 311      *
 312      * @param listener the listener
 313      */
 314     public synchronized void removeHyperlinkListener(HyperlinkListener listener) {
 315         listenerList.remove(HyperlinkListener.class, listener);
 316     }
 317 
 318     /**
 319      * Returns an array of all the <code>HyperLinkListener</code>s added
 320      * to this JEditorPane with addHyperlinkListener().
 321      *
 322      * @return all of the <code>HyperLinkListener</code>s added or an empty
 323      *         array if no listeners have been added
 324      * @since 1.4
 325      */

 326     public synchronized HyperlinkListener[] getHyperlinkListeners() {
 327         return listenerList.getListeners(javax.swing.event.HyperlinkListener.class);
 328     }
 329 
 330     /**
 331      * Notifies all listeners that have registered interest for
 332      * notification on this event type.  This is normally called
 333      * by the currently installed <code>EditorKit</code> if a content type
 334      * that supports hyperlinks is currently active and there
 335      * was activity with a link.  The listener list is processed
 336      * last to first.
 337      *
 338      * @param e the event
 339      * @see EventListenerList
 340      */
 341     public void fireHyperlinkUpdate(HyperlinkEvent e) {
 342         // Guaranteed to return a non-null array
 343         Object[] listeners = listenerList.getListenerList();
 344         // Process the listeners last to first, notifying
 345         // those that are interested in this event


 394      * will be fired.
 395      * <p>
 396      * If the document is loaded asynchronously, the document
 397      * will be installed into the editor immediately using a
 398      * call to <code>setDocument</code> which will fire a
 399      * document property change event, then a thread will be
 400      * created which will begin doing the actual loading.
 401      * In this case, the page property change event will not be
 402      * fired by the call to this method directly, but rather will be
 403      * fired when the thread doing the loading has finished.
 404      * It will also be fired on the event-dispatch thread.
 405      * Since the calling thread can not throw an <code>IOException</code>
 406      * in the event of failure on the other thread, the page
 407      * property change event will be fired when the other
 408      * thread is done whether the load was successful or not.
 409      *
 410      * @param page the URL of the page
 411      * @exception IOException for a <code>null</code> or invalid
 412      *          page specification, or exception from the stream being read
 413      * @see #getPage
 414      * @beaninfo
 415      *  description: the URL used to set content
 416      *        bound: true
 417      *       expert: true
 418      */


 419     public void setPage(URL page) throws IOException {
 420         if (page == null) {
 421             throw new IOException("invalid url");
 422         }
 423         URL loaded = getPage();
 424 
 425 
 426         // reset scrollbar
 427         if (!page.equals(loaded) && page.getRef() == null) {
 428             scrollRectToVisible(new Rectangle(0,0,1,1));
 429         }
 430         boolean reloaded = false;
 431         Object postData = getPostData();
 432         if ((loaded == null) || !loaded.sameFile(page) || (postData != null)) {
 433             // different url or POST method, load the new content
 434 
 435             int p = getAsynchronousLoadPriority(getDocument());
 436             if (p < 0) {
 437                 // open stream synchronously
 438                 InputStream in = getStream(page);


 876      *
 877      * @param url the URL for display
 878      * @exception IOException for a <code>null</code> or invalid URL
 879      *          specification
 880      */
 881     public void setPage(String url) throws IOException {
 882         if (url == null) {
 883             throw new IOException("invalid url");
 884         }
 885         URL page = new URL(url);
 886         setPage(page);
 887     }
 888 
 889     /**
 890      * Gets the class ID for the UI.
 891      *
 892      * @return the string "EditorPaneUI"
 893      * @see JComponent#getUIClassID
 894      * @see UIDefaults#getUI
 895      */

 896     public String getUIClassID() {
 897         return uiClassID;
 898     }
 899 
 900     /**
 901      * Creates the default editor kit (<code>PlainEditorKit</code>) for when
 902      * the component is first created.
 903      *
 904      * @return the editor kit
 905      */
 906     protected EditorKit createDefaultEditorKit() {
 907         return new PlainEditorKit();
 908     }
 909 
 910     /**
 911      * Fetches the currently installed kit for handling content.
 912      * <code>createDefaultEditorKit</code> is called to set up a default
 913      * if necessary.
 914      *
 915      * @return the editor kit


 941      * be successfully located.  This is mostly convenience method
 942      * that can be used as an alternative to calling
 943      * <code>setEditorKit</code> directly.
 944      * <p>
 945      * If there is a charset definition specified as a parameter
 946      * of the content type specification, it will be used when
 947      * loading input streams using the associated <code>EditorKit</code>.
 948      * For example if the type is specified as
 949      * <code>text/html; charset=EUC-JP</code> the content
 950      * will be loaded using the <code>EditorKit</code> registered for
 951      * <code>text/html</code> and the Reader provided to
 952      * the <code>EditorKit</code> to load unicode into the document will
 953      * use the <code>EUC-JP</code> charset for translating
 954      * to unicode.  If the type is not recognized, the content
 955      * will be loaded using the <code>EditorKit</code> registered
 956      * for plain text, <code>text/plain</code>.
 957      *
 958      * @param type the non-<code>null</code> mime type for the content editing
 959      *   support
 960      * @see #getContentType
 961      * @beaninfo
 962      *  description: the type of content
 963      * @throws NullPointerException if the <code>type</code> parameter
 964      *          is <code>null</code>
 965      */


 966     public final void setContentType(String type) {
 967         // The type could have optional info is part of it,
 968         // for example some charset info.  We need to strip that
 969         // of and save it.
 970         int parm = type.indexOf(';');
 971         if (parm > -1) {
 972             // Save the paramList.
 973             String paramList = type.substring(parm);
 974             // update the content type string.
 975             type = type.substring(0, parm).trim();
 976             if (type.toLowerCase().startsWith("text/")) {
 977                 setCharsetFromContentTypeParameters(paramList);
 978             }
 979         }
 980         if ((kit == null) || (! type.equals(kit.getContentType()))
 981                 || !isUserSetEditorKit) {
 982             EditorKit k = getEditorKitForContentType(type);
 983             if (k != null && k != kit) {
 984                 setEditorKit(k);
 985                 isUserSetEditorKit = false;


1027 
1028     /**
1029      * Sets the currently installed kit for handling
1030      * content.  This is the bound property that
1031      * establishes the content type of the editor.
1032      * Any old kit is first deinstalled, then if kit is
1033      * non-<code>null</code>,
1034      * the new kit is installed, and a default document created for it.
1035      * A <code>PropertyChange</code> event ("editorKit") is always fired when
1036      * <code>setEditorKit</code> is called.
1037      * <p>
1038      * <em>NOTE: This has the side effect of changing the model,
1039      * because the <code>EditorKit</code> is the source of how a
1040      * particular type
1041      * of content is modeled.  This method will cause <code>setDocument</code>
1042      * to be called on behalf of the caller to ensure integrity
1043      * of the internal state.</em>
1044      *
1045      * @param kit the desired editor behavior
1046      * @see #getEditorKit
1047      * @beaninfo
1048      *  description: the currently installed kit for handling content
1049      *        bound: true
1050      *       expert: true
1051      */


1052     public void setEditorKit(EditorKit kit) {
1053         EditorKit old = this.kit;
1054         isUserSetEditorKit = true;
1055         if (old != null) {
1056             old.deinstall(this);
1057         }
1058         this.kit = kit;
1059         if (this.kit != null) {
1060             this.kit.install(this);
1061             setDocument(this.kit.createDefaultDocument());
1062         }
1063         firePropertyChange("editorKit", old, kit);
1064     }
1065 
1066     /**
1067      * Fetches the editor kit to use for the given type
1068      * of content.  This is called when a type is requested
1069      * that doesn't match the currently installed type.
1070      * If the component doesn't have an <code>EditorKit</code> registered
1071      * for the given type, it will try to create an


1395      * previous <code>Document</code> won't have any lingering state.
1396      * <ol>
1397      * <li>
1398      * Leaving the existing model in place means that the old view will be
1399      * torn down, and a new view created, where replacing the document would
1400      * avoid the tear down of the old view.
1401      * <li>
1402      * Some formats (such as HTML) can install things into the document that
1403      * can influence future contents.  HTML can have style information embedded
1404      * that would influence the next content installed unexpectedly.
1405      * </ol>
1406      * <p>
1407      * An alternative way to load this component with a string would be to
1408      * create a StringReader and call the read method.  In this case the model
1409      * would be replaced after it was initialized with the contents of the
1410      * string.
1411      *
1412      * @param t the new text to be set; if <code>null</code> the old
1413      *    text will be deleted
1414      * @see #getText
1415      * @beaninfo
1416      * description: the text of this component
1417      */


1418     public void setText(String t) {
1419         try {
1420             Document doc = getDocument();
1421             doc.remove(0, doc.getLength());
1422             if (t == null || t.equals("")) {
1423                 return;
1424             }
1425             Reader r = new StringReader(t);
1426             EditorKit kit = getEditorKit();
1427             kit.read(r, doc, 0);
1428         } catch (IOException ioe) {
1429             UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
1430         } catch (BadLocationException ble) {
1431             UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
1432         }
1433     }
1434 
1435     /**
1436      * Returns the text contained in this <code>TextComponent</code>
1437      * in terms of the


1447         String txt;
1448         try {
1449             StringWriter buf = new StringWriter();
1450             write(buf);
1451             txt = buf.toString();
1452         } catch (IOException ioe) {
1453             txt = null;
1454         }
1455         return txt;
1456     }
1457 
1458     // --- Scrollable  ----------------------------------------
1459 
1460     /**
1461      * Returns true if a viewport should always force the width of this
1462      * <code>Scrollable</code> to match the width of the viewport.
1463      *
1464      * @return true if a viewport should force the Scrollables width to
1465      * match its own, false otherwise
1466      */

1467     public boolean getScrollableTracksViewportWidth() {
1468         Container parent = SwingUtilities.getUnwrappedParent(this);
1469         if (parent instanceof JViewport) {
1470             JViewport port = (JViewport) parent;
1471             TextUI ui = getUI();
1472             int w = port.getWidth();
1473             Dimension min = ui.getMinimumSize(this);
1474             Dimension max = ui.getMaximumSize(this);
1475             if ((w >= min.width) && (w <= max.width)) {
1476                 return true;
1477             }
1478         }
1479         return false;
1480     }
1481 
1482     /**
1483      * Returns true if a viewport should always force the height of this
1484      * <code>Scrollable</code> to match the height of the viewport.
1485      *
1486      * @return true if a viewport should force the
1487      *          <code>Scrollable</code>'s height to match its own,
1488      *          false otherwise
1489      */

1490     public boolean getScrollableTracksViewportHeight() {
1491         Container parent = SwingUtilities.getUnwrappedParent(this);
1492         if (parent instanceof JViewport) {
1493             JViewport port = (JViewport) parent;
1494             TextUI ui = getUI();
1495             int h = port.getHeight();
1496             Dimension min = ui.getMinimumSize(this);
1497             if (h >= min.height) {
1498                 Dimension max = ui.getMaximumSize(this);
1499                 if (h <= max.height) {
1500                     return true;
1501                 }
1502             }
1503         }
1504         return false;
1505     }
1506 
1507     // --- Serialization ------------------------------------
1508 
1509     /**


1607         return super.paramString() +
1608         ",kit=" + kitString +
1609         ",typeHandlers=" + typeHandlersString;
1610     }
1611 
1612 
1613 /////////////////
1614 // Accessibility support
1615 ////////////////
1616 
1617 
1618     /**
1619      * Gets the AccessibleContext associated with this JEditorPane.
1620      * For editor panes, the AccessibleContext takes the form of an
1621      * AccessibleJEditorPane.
1622      * A new AccessibleJEditorPane instance is created if necessary.
1623      *
1624      * @return an AccessibleJEditorPane that serves as the
1625      *         AccessibleContext of this JEditorPane
1626      */

1627     public AccessibleContext getAccessibleContext() {
1628         if (getEditorKit() instanceof HTMLEditorKit) {
1629             if (accessibleContext == null || accessibleContext.getClass() !=
1630                     AccessibleJEditorPaneHTML.class) {
1631                 accessibleContext = new AccessibleJEditorPaneHTML();
1632             }
1633         } else if (accessibleContext == null || accessibleContext.getClass() !=
1634                        AccessibleJEditorPane.class) {
1635             accessibleContext = new AccessibleJEditorPane();
1636         }
1637         return accessibleContext;
1638     }
1639 
1640     /**
1641      * This class implements accessibility support for the
1642      * <code>JEditorPane</code> class.  It provides an implementation of the
1643      * Java Accessibility API appropriate to editor pane user-interface
1644      * elements.
1645      * <p>
1646      * <strong>Warning:</strong>




   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing;
  26 


  27 import java.awt.*;
  28 import java.beans.JavaBean;
  29 import java.beans.BeanProperty;
  30 import java.lang.reflect.*;
  31 import java.net.*;
  32 import java.util.*;
  33 import java.io.*;

  34 
  35 import javax.swing.plaf.*;
  36 import javax.swing.text.*;
  37 import javax.swing.event.*;
  38 import javax.swing.text.html.*;
  39 import javax.accessibility.*;
  40 import sun.reflect.misc.ReflectUtil;
  41 
  42 /**
  43  * A text component to edit various kinds of content.
  44  * You can find how-to information and examples of using editor panes in
  45  * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/text.html">Using Text Components</a>,
  46  * a section in <em>The Java Tutorial.</em>
  47  *
  48  * <p>
  49  * This component uses implementations of the
  50  * <code>EditorKit</code> to accomplish its behavior. It effectively
  51  * morphs into the proper kind of text editor for the kind
  52  * of content it is given.  The content type that editor is bound
  53  * to at any given time is determined by the <code>EditorKit</code> currently


 165  * <dd>
 166  * For a discussion on how newlines are handled, see
 167  * <a href="text/DefaultEditorKit.html">DefaultEditorKit</a>.
 168  * </dl>
 169  *
 170  * <p>
 171  * <strong>Warning:</strong> Swing is not thread safe. For more
 172  * information see <a
 173  * href="package-summary.html#threading">Swing's Threading
 174  * Policy</a>.
 175  * <p>
 176  * <strong>Warning:</strong>
 177  * Serialized objects of this class will not be compatible with
 178  * future Swing releases. The current serialization support is
 179  * appropriate for short term storage or RMI between applications running
 180  * the same version of Swing.  As of 1.4, support for long term storage
 181  * of all JavaBeans&trade;
 182  * has been added to the <code>java.beans</code> package.
 183  * Please see {@link java.beans.XMLEncoder}.
 184  *




 185  * @author  Timothy Prinzing
 186  * @since 1.2
 187  */
 188 @JavaBean(defaultProperty = "UIClassID", description = "A text component to edit various types of content.")
 189 @SwingContainer(false)
 190 @SuppressWarnings("serial") // Same-version serialization only
 191 public class JEditorPane extends JTextComponent {
 192 
 193     /**
 194      * Creates a new <code>JEditorPane</code>.
 195      * The document model is set to <code>null</code>.
 196      */
 197     public JEditorPane() {
 198         super();
 199         setFocusCycleRoot(true);
 200         setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
 201                 public Component getComponentAfter(Container focusCycleRoot,
 202                                                    Component aComponent) {
 203                     if (focusCycleRoot != JEditorPane.this ||
 204                         (!isEditable() && getComponentCount() > 0)) {
 205                         return super.getComponentAfter(focusCycleRoot,
 206                                                        aComponent);
 207                     } else {
 208                         Container rootAncestor = getFocusCycleRootAncestor();
 209                         return (rootAncestor != null)


 302         listenerList.add(HyperlinkListener.class, listener);
 303     }
 304 
 305     /**
 306      * Removes a hyperlink listener.
 307      *
 308      * @param listener the listener
 309      */
 310     public synchronized void removeHyperlinkListener(HyperlinkListener listener) {
 311         listenerList.remove(HyperlinkListener.class, listener);
 312     }
 313 
 314     /**
 315      * Returns an array of all the <code>HyperLinkListener</code>s added
 316      * to this JEditorPane with addHyperlinkListener().
 317      *
 318      * @return all of the <code>HyperLinkListener</code>s added or an empty
 319      *         array if no listeners have been added
 320      * @since 1.4
 321      */
 322     @BeanProperty(bound = false)
 323     public synchronized HyperlinkListener[] getHyperlinkListeners() {
 324         return listenerList.getListeners(javax.swing.event.HyperlinkListener.class);
 325     }
 326 
 327     /**
 328      * Notifies all listeners that have registered interest for
 329      * notification on this event type.  This is normally called
 330      * by the currently installed <code>EditorKit</code> if a content type
 331      * that supports hyperlinks is currently active and there
 332      * was activity with a link.  The listener list is processed
 333      * last to first.
 334      *
 335      * @param e the event
 336      * @see EventListenerList
 337      */
 338     public void fireHyperlinkUpdate(HyperlinkEvent e) {
 339         // Guaranteed to return a non-null array
 340         Object[] listeners = listenerList.getListenerList();
 341         // Process the listeners last to first, notifying
 342         // those that are interested in this event


 391      * will be fired.
 392      * <p>
 393      * If the document is loaded asynchronously, the document
 394      * will be installed into the editor immediately using a
 395      * call to <code>setDocument</code> which will fire a
 396      * document property change event, then a thread will be
 397      * created which will begin doing the actual loading.
 398      * In this case, the page property change event will not be
 399      * fired by the call to this method directly, but rather will be
 400      * fired when the thread doing the loading has finished.
 401      * It will also be fired on the event-dispatch thread.
 402      * Since the calling thread can not throw an <code>IOException</code>
 403      * in the event of failure on the other thread, the page
 404      * property change event will be fired when the other
 405      * thread is done whether the load was successful or not.
 406      *
 407      * @param page the URL of the page
 408      * @exception IOException for a <code>null</code> or invalid
 409      *          page specification, or exception from the stream being read
 410      * @see #getPage




 411      */
 412     @BeanProperty(expert = true, description
 413             = "the URL used to set content")
 414     public void setPage(URL page) throws IOException {
 415         if (page == null) {
 416             throw new IOException("invalid url");
 417         }
 418         URL loaded = getPage();
 419 
 420 
 421         // reset scrollbar
 422         if (!page.equals(loaded) && page.getRef() == null) {
 423             scrollRectToVisible(new Rectangle(0,0,1,1));
 424         }
 425         boolean reloaded = false;
 426         Object postData = getPostData();
 427         if ((loaded == null) || !loaded.sameFile(page) || (postData != null)) {
 428             // different url or POST method, load the new content
 429 
 430             int p = getAsynchronousLoadPriority(getDocument());
 431             if (p < 0) {
 432                 // open stream synchronously
 433                 InputStream in = getStream(page);


 871      *
 872      * @param url the URL for display
 873      * @exception IOException for a <code>null</code> or invalid URL
 874      *          specification
 875      */
 876     public void setPage(String url) throws IOException {
 877         if (url == null) {
 878             throw new IOException("invalid url");
 879         }
 880         URL page = new URL(url);
 881         setPage(page);
 882     }
 883 
 884     /**
 885      * Gets the class ID for the UI.
 886      *
 887      * @return the string "EditorPaneUI"
 888      * @see JComponent#getUIClassID
 889      * @see UIDefaults#getUI
 890      */
 891     @BeanProperty(bound = false)
 892     public String getUIClassID() {
 893         return uiClassID;
 894     }
 895 
 896     /**
 897      * Creates the default editor kit (<code>PlainEditorKit</code>) for when
 898      * the component is first created.
 899      *
 900      * @return the editor kit
 901      */
 902     protected EditorKit createDefaultEditorKit() {
 903         return new PlainEditorKit();
 904     }
 905 
 906     /**
 907      * Fetches the currently installed kit for handling content.
 908      * <code>createDefaultEditorKit</code> is called to set up a default
 909      * if necessary.
 910      *
 911      * @return the editor kit


 937      * be successfully located.  This is mostly convenience method
 938      * that can be used as an alternative to calling
 939      * <code>setEditorKit</code> directly.
 940      * <p>
 941      * If there is a charset definition specified as a parameter
 942      * of the content type specification, it will be used when
 943      * loading input streams using the associated <code>EditorKit</code>.
 944      * For example if the type is specified as
 945      * <code>text/html; charset=EUC-JP</code> the content
 946      * will be loaded using the <code>EditorKit</code> registered for
 947      * <code>text/html</code> and the Reader provided to
 948      * the <code>EditorKit</code> to load unicode into the document will
 949      * use the <code>EUC-JP</code> charset for translating
 950      * to unicode.  If the type is not recognized, the content
 951      * will be loaded using the <code>EditorKit</code> registered
 952      * for plain text, <code>text/plain</code>.
 953      *
 954      * @param type the non-<code>null</code> mime type for the content editing
 955      *   support
 956      * @see #getContentType


 957      * @throws NullPointerException if the <code>type</code> parameter
 958      *          is <code>null</code>
 959      */
 960     @BeanProperty(bound = false, description
 961             = "the type of content")
 962     public final void setContentType(String type) {
 963         // The type could have optional info is part of it,
 964         // for example some charset info.  We need to strip that
 965         // of and save it.
 966         int parm = type.indexOf(';');
 967         if (parm > -1) {
 968             // Save the paramList.
 969             String paramList = type.substring(parm);
 970             // update the content type string.
 971             type = type.substring(0, parm).trim();
 972             if (type.toLowerCase().startsWith("text/")) {
 973                 setCharsetFromContentTypeParameters(paramList);
 974             }
 975         }
 976         if ((kit == null) || (! type.equals(kit.getContentType()))
 977                 || !isUserSetEditorKit) {
 978             EditorKit k = getEditorKitForContentType(type);
 979             if (k != null && k != kit) {
 980                 setEditorKit(k);
 981                 isUserSetEditorKit = false;


1023 
1024     /**
1025      * Sets the currently installed kit for handling
1026      * content.  This is the bound property that
1027      * establishes the content type of the editor.
1028      * Any old kit is first deinstalled, then if kit is
1029      * non-<code>null</code>,
1030      * the new kit is installed, and a default document created for it.
1031      * A <code>PropertyChange</code> event ("editorKit") is always fired when
1032      * <code>setEditorKit</code> is called.
1033      * <p>
1034      * <em>NOTE: This has the side effect of changing the model,
1035      * because the <code>EditorKit</code> is the source of how a
1036      * particular type
1037      * of content is modeled.  This method will cause <code>setDocument</code>
1038      * to be called on behalf of the caller to ensure integrity
1039      * of the internal state.</em>
1040      *
1041      * @param kit the desired editor behavior
1042      * @see #getEditorKit




1043      */
1044     @BeanProperty(expert = true, description
1045             = "the currently installed kit for handling content")
1046     public void setEditorKit(EditorKit kit) {
1047         EditorKit old = this.kit;
1048         isUserSetEditorKit = true;
1049         if (old != null) {
1050             old.deinstall(this);
1051         }
1052         this.kit = kit;
1053         if (this.kit != null) {
1054             this.kit.install(this);
1055             setDocument(this.kit.createDefaultDocument());
1056         }
1057         firePropertyChange("editorKit", old, kit);
1058     }
1059 
1060     /**
1061      * Fetches the editor kit to use for the given type
1062      * of content.  This is called when a type is requested
1063      * that doesn't match the currently installed type.
1064      * If the component doesn't have an <code>EditorKit</code> registered
1065      * for the given type, it will try to create an


1389      * previous <code>Document</code> won't have any lingering state.
1390      * <ol>
1391      * <li>
1392      * Leaving the existing model in place means that the old view will be
1393      * torn down, and a new view created, where replacing the document would
1394      * avoid the tear down of the old view.
1395      * <li>
1396      * Some formats (such as HTML) can install things into the document that
1397      * can influence future contents.  HTML can have style information embedded
1398      * that would influence the next content installed unexpectedly.
1399      * </ol>
1400      * <p>
1401      * An alternative way to load this component with a string would be to
1402      * create a StringReader and call the read method.  In this case the model
1403      * would be replaced after it was initialized with the contents of the
1404      * string.
1405      *
1406      * @param t the new text to be set; if <code>null</code> the old
1407      *    text will be deleted
1408      * @see #getText


1409      */
1410     @BeanProperty(bound = false, description
1411             = "the text of this component")
1412     public void setText(String t) {
1413         try {
1414             Document doc = getDocument();
1415             doc.remove(0, doc.getLength());
1416             if (t == null || t.equals("")) {
1417                 return;
1418             }
1419             Reader r = new StringReader(t);
1420             EditorKit kit = getEditorKit();
1421             kit.read(r, doc, 0);
1422         } catch (IOException ioe) {
1423             UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
1424         } catch (BadLocationException ble) {
1425             UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
1426         }
1427     }
1428 
1429     /**
1430      * Returns the text contained in this <code>TextComponent</code>
1431      * in terms of the


1441         String txt;
1442         try {
1443             StringWriter buf = new StringWriter();
1444             write(buf);
1445             txt = buf.toString();
1446         } catch (IOException ioe) {
1447             txt = null;
1448         }
1449         return txt;
1450     }
1451 
1452     // --- Scrollable  ----------------------------------------
1453 
1454     /**
1455      * Returns true if a viewport should always force the width of this
1456      * <code>Scrollable</code> to match the width of the viewport.
1457      *
1458      * @return true if a viewport should force the Scrollables width to
1459      * match its own, false otherwise
1460      */
1461     @BeanProperty(bound = false)
1462     public boolean getScrollableTracksViewportWidth() {
1463         Container parent = SwingUtilities.getUnwrappedParent(this);
1464         if (parent instanceof JViewport) {
1465             JViewport port = (JViewport) parent;
1466             TextUI ui = getUI();
1467             int w = port.getWidth();
1468             Dimension min = ui.getMinimumSize(this);
1469             Dimension max = ui.getMaximumSize(this);
1470             if ((w >= min.width) && (w <= max.width)) {
1471                 return true;
1472             }
1473         }
1474         return false;
1475     }
1476 
1477     /**
1478      * Returns true if a viewport should always force the height of this
1479      * <code>Scrollable</code> to match the height of the viewport.
1480      *
1481      * @return true if a viewport should force the
1482      *          <code>Scrollable</code>'s height to match its own,
1483      *          false otherwise
1484      */
1485     @BeanProperty(bound = false)
1486     public boolean getScrollableTracksViewportHeight() {
1487         Container parent = SwingUtilities.getUnwrappedParent(this);
1488         if (parent instanceof JViewport) {
1489             JViewport port = (JViewport) parent;
1490             TextUI ui = getUI();
1491             int h = port.getHeight();
1492             Dimension min = ui.getMinimumSize(this);
1493             if (h >= min.height) {
1494                 Dimension max = ui.getMaximumSize(this);
1495                 if (h <= max.height) {
1496                     return true;
1497                 }
1498             }
1499         }
1500         return false;
1501     }
1502 
1503     // --- Serialization ------------------------------------
1504 
1505     /**


1603         return super.paramString() +
1604         ",kit=" + kitString +
1605         ",typeHandlers=" + typeHandlersString;
1606     }
1607 
1608 
1609 /////////////////
1610 // Accessibility support
1611 ////////////////
1612 
1613 
1614     /**
1615      * Gets the AccessibleContext associated with this JEditorPane.
1616      * For editor panes, the AccessibleContext takes the form of an
1617      * AccessibleJEditorPane.
1618      * A new AccessibleJEditorPane instance is created if necessary.
1619      *
1620      * @return an AccessibleJEditorPane that serves as the
1621      *         AccessibleContext of this JEditorPane
1622      */
1623     @BeanProperty(bound = false)
1624     public AccessibleContext getAccessibleContext() {
1625         if (getEditorKit() instanceof HTMLEditorKit) {
1626             if (accessibleContext == null || accessibleContext.getClass() !=
1627                     AccessibleJEditorPaneHTML.class) {
1628                 accessibleContext = new AccessibleJEditorPaneHTML();
1629             }
1630         } else if (accessibleContext == null || accessibleContext.getClass() !=
1631                        AccessibleJEditorPane.class) {
1632             accessibleContext = new AccessibleJEditorPane();
1633         }
1634         return accessibleContext;
1635     }
1636 
1637     /**
1638      * This class implements accessibility support for the
1639      * <code>JEditorPane</code> class.  It provides an implementation of the
1640      * Java Accessibility API appropriate to editor pane user-interface
1641      * elements.
1642      * <p>
1643      * <strong>Warning:</strong>