2410 lines · 91.0 KB · Java
RawDownload
/* * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package javax.swing; import sun.swing.SwingUtilities2; import java.awt.*;import java.awt.event.*;import java.lang.reflect.*;import java.net.*;import java.util.*;import java.io.*;import java.util.*; import javax.swing.plaf.*;import javax.swing.text.*;import javax.swing.event.*;import javax.swing.text.html.*;import javax.accessibility.*; /** * A text component to edit various kinds of content. * You can find how-to information and examples of using editor panes in * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/text.html">Using Text Components</a>, * a section in <em>The Java Tutorial.</em> * * <p> * This component uses implementations of the * <code>EditorKit</code> to accomplish its behavior. It effectively * morphs into the proper kind of text editor for the kind * of content it is given.  The content type that editor is bound * to at any given time is determined by the <code>EditorKit</code> currently * installed.  If the content is set to a new URL, its type is used * to determine the <code>EditorKit</code> that should be used to * load the content. * <p> * By default, the following types of content are known: * <dl> * <dt><b>text/plain</b> * <dd>Plain text, which is the default the type given isn't * recognized.  The kit used in this case is an extension of * <code>DefaultEditorKit</code> that produces a wrapped plain text view. * <dt><b>text/html</b> * <dd>HTML text.  The kit used in this case is the class * <code>javax.swing.text.html.HTMLEditorKit</code> * which provides HTML 3.2 support. * <dt><b>text/rtf</b> * <dd>RTF text.  The kit used in this case is the class * <code>javax.swing.text.rtf.RTFEditorKit</code> * which provides a limited support of the Rich Text Format. * </dl> * <p> * There are several ways to load content into this component. * <ol> * <li> * The {@link #setText setText} method can be used to initialize * the component from a string.  In this case the current * <code>EditorKit</code> will be used, and the content type will be * expected to be of this type. * <li> * The {@link #read read} method can be used to initialize the * component from a <code>Reader</code>.  Note that if the content type is HTML, * relative references (e.g. for things like images) can't be resolved * unless the &lt;base&gt; tag is used or the <em>Base</em> property * on <code>HTMLDocument</code> is set. * In this case the current <code>EditorKit</code> will be used, * and the content type will be expected to be of this type. * <li> * The {@link #setPage setPage} method can be used to initialize * the component from a URL.  In this case, the content type will be * determined from the URL, and the registered <code>EditorKit</code> * for that content type will be set. * </ol> * <p> * Some kinds of content may provide hyperlink support by generating * hyperlink events.  The HTML <code>EditorKit</code> will generate * hyperlink events if the <code>JEditorPane</code> is <em>not editable</em> * (<code>JEditorPane.setEditable(false);</code> has been called). * If HTML frames are embedded in the document, the typical response would be * to change a portion of the current document.  The following code * fragment is a possible hyperlink listener implementation, that treats * HTML frame events specially, and simply displays any other activated * hyperlinks. * <code><pre> &nbsp;    class Hyperactive implements HyperlinkListener {&nbsp;&nbsp;        public void hyperlinkUpdate(HyperlinkEvent e) {&nbsp;            if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {&nbsp;                JEditorPane pane = (JEditorPane) e.getSource();&nbsp;                if (e instanceof HTMLFrameHyperlinkEvent) {&nbsp;                    HTMLFrameHyperlinkEvent  evt = (HTMLFrameHyperlinkEvent)e;&nbsp;                    HTMLDocument doc = (HTMLDocument)pane.getDocument();&nbsp;                    doc.processHTMLFrameHyperlinkEvent(evt);&nbsp;                } else {&nbsp;                    try {&nbsp;                        pane.setPage(e.getURL());&nbsp;                    } catch (Throwable t) {&nbsp;                        t.printStackTrace();&nbsp;                    }&nbsp;                }&nbsp;            }&nbsp;        }&nbsp;    }  * </pre></code> * <p> * For information on customizing how <b>text/html</b> is rendered please see * {@link #W3C_LENGTH_UNITS} and {@link #HONOR_DISPLAY_PROPERTIES} * <p> * Culturally dependent information in some documents is handled through * a mechanism called character encoding.  Character encoding is an * unambiguous mapping of the members of a character set (letters, ideographs, * digits, symbols, or control functions) to specific numeric code values. It * represents the way the file is stored. Example character encodings are * ISO-8859-1, ISO-8859-5, Shift-jis, Euc-jp, and UTF-8. When the file is * passed to an user agent (<code>JEditorPane</code>) it is converted to * the document character set (ISO-10646 aka Unicode). * <p> * There are multiple ways to get a character set mapping to happen * with <code>JEditorPane</code>. * <ol> * <li> * One way is to specify the character set as a parameter of the MIME * type.  This will be established by a call to the * {@link #setContentType setContentType} method.  If the content * is loaded by the {@link #setPage setPage} method the content * type will have been set according to the specification of the URL. * It the file is loaded directly, the content type would be expected to * have been set prior to loading. * <li> * Another way the character set can be specified is in the document itself. * This requires reading the document prior to determining the character set * that is desired.  To handle this, it is expected that the * <code>EditorKit</code>.read operation throw a * <code>ChangedCharSetException</code> which will * be caught.  The read is then restarted with a new Reader that uses * the character set specified in the <code>ChangedCharSetException</code> * (which is an <code>IOException</code>). * </ol> * <p> * <dl> * <dt><b><font size=+1>Newlines</font></b> * <dd> * For a discussion on how newlines are handled, see * <a href="text/DefaultEditorKit.html">DefaultEditorKit</a>. * </dl> * * <p> * <strong>Warning:</strong> Swing is not thread safe. For more * information see <a * href="package-summary.html#threading">Swing's Threading * Policy</a>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing.  As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @beaninfo *   attribute: isContainer false * description: A text component to edit various types of content. * * @author  Timothy Prinzing */public class JEditorPane extends JTextComponent {     /**     * Creates a new <code>JEditorPane</code>.     * The document model is set to <code>null</code>.     */    public JEditorPane() {        super();        setFocusCycleRoot(true);        setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {                public Component getComponentAfter(Container focusCycleRoot,                                                   Component aComponent) {                    if (focusCycleRoot != JEditorPane.this ||                        (!isEditable() && getComponentCount() > 0)) {                        return super.getComponentAfter(focusCycleRoot,                                                       aComponent);                    } else {                        Container rootAncestor = getFocusCycleRootAncestor();                        return (rootAncestor != null)                            ? rootAncestor.getFocusTraversalPolicy().                                  getComponentAfter(rootAncestor,                                                    JEditorPane.this)                            : null;                    }                }                public Component getComponentBefore(Container focusCycleRoot,                                                    Component aComponent) {                    if (focusCycleRoot != JEditorPane.this ||                        (!isEditable() && getComponentCount() > 0)) {                        return super.getComponentBefore(focusCycleRoot,                                                        aComponent);                    } else {                        Container rootAncestor = getFocusCycleRootAncestor();                        return (rootAncestor != null)                            ? rootAncestor.getFocusTraversalPolicy().                                  getComponentBefore(rootAncestor,                                                     JEditorPane.this)                            : null;                    }                }                public Component getDefaultComponent(Container focusCycleRoot)                {                    return (focusCycleRoot != JEditorPane.this ||                            (!isEditable() && getComponentCount() > 0))                        ? super.getDefaultComponent(focusCycleRoot)                        : null;                }                protected boolean accept(Component aComponent) {                    return (aComponent != JEditorPane.this)                        ? super.accept(aComponent)                        : false;                }            });        LookAndFeel.installProperty(this,                                    "focusTraversalKeysForward",                                    JComponent.                                    getManagingFocusForwardTraversalKeys());        LookAndFeel.installProperty(this,                                    "focusTraversalKeysBackward",                                    JComponent.                                    getManagingFocusBackwardTraversalKeys());    }     /**     * Creates a <code>JEditorPane</code> based on a specified URL for input.     *     * @param initialPage the URL     * @exception IOException if the URL is <code>null</code>     *          or cannot be accessed     */    public JEditorPane(URL initialPage) throws IOException {        this();        setPage(initialPage);    }     /**     * Creates a <code>JEditorPane</code> based on a string containing     * a URL specification.     *     * @param url the URL     * @exception IOException if the URL is <code>null</code> or     *          cannot be accessed     */    public JEditorPane(String url) throws IOException {        this();        setPage(url);    }     /**     * Creates a <code>JEditorPane</code> that has been initialized     * to the given text.  This is a convenience constructor that calls the     * <code>setContentType</code> and <code>setText</code> methods.     *     * @param type mime type of the given text     * @param text the text to initialize with; may be <code>null</code>     * @exception NullPointerException if the <code>type</code> parameter     *          is <code>null</code>     */    public JEditorPane(String type, String text) {        this();        setContentType(type);        setText(text);    }     /**     * Adds a hyperlink listener for notification of any changes, for example     * when a link is selected and entered.     *     * @param listener the listener     */    public synchronized void addHyperlinkListener(HyperlinkListener listener) {        listenerList.add(HyperlinkListener.class, listener);    }     /**     * Removes a hyperlink listener.     *     * @param listener the listener     */    public synchronized void removeHyperlinkListener(HyperlinkListener listener) {        listenerList.remove(HyperlinkListener.class, listener);    }     /**     * Returns an array of all the <code>HyperLinkListener</code>s added     * to this JEditorPane with addHyperlinkListener().     *     * @return all of the <code>HyperLinkListener</code>s added or an empty     *         array if no listeners have been added     * @since 1.4     */    public synchronized HyperlinkListener[] getHyperlinkListeners() {        return listenerList.getListeners(javax.swing.event.HyperlinkListener.class);    }     /**     * Notifies all listeners that have registered interest for     * notification on this event type.  This is normally called     * by the currently installed <code>EditorKit</code> if a content type     * that supports hyperlinks is currently active and there     * was activity with a link.  The listener list is processed     * last to first.     *     * @param e the event     * @see EventListenerList     */    public void fireHyperlinkUpdate(HyperlinkEvent e) {        // Guaranteed to return a non-null array        Object[] listeners = listenerList.getListenerList();        // Process the listeners last to first, notifying        // those that are interested in this event        for (int i = listeners.length-2; i>=0; i-=2) {            if (listeners[i]==HyperlinkListener.class) {                ((HyperlinkListener)listeners[i+1]).hyperlinkUpdate(e);            }        }    }      /**     * Sets the current URL being displayed.  The content type of the     * pane is set, and if the editor kit for the pane is     * non-<code>null</code>, then     * a new default document is created and the URL is read into it.     * If the URL contains and reference location, the location will     * be scrolled to by calling the <code>scrollToReference</code>     * method. If the desired URL is the one currently being displayed,     * the document will not be reloaded. To force a document     * reload it is necessary to clear the stream description property     * of the document. The following code shows how this can be done:     *     * <pre>     *   Document doc = jEditorPane.getDocument();     *   doc.putProperty(Document.StreamDescriptionProperty, null);     * </pre>     *     * If the desired URL is not the one currently being     * displayed, the <code>getStream</code> method is called to     * give subclasses control over the stream provided.     * <p>     * This may load either synchronously or asynchronously     * depending upon the document returned by the <code>EditorKit</code>.     * If the <code>Document</code> is of type     * <code>AbstractDocument</code> and has a value returned by     * <code>AbstractDocument.getAsynchronousLoadPriority</code>     * that is greater than or equal to zero, the page will be     * loaded on a separate thread using that priority.     * <p>     * If the document is loaded synchronously, it will be     * filled in with the stream prior to being installed into     * the editor with a call to <code>setDocument</code>, which     * is bound and will fire a property change event.  If an     * <code>IOException</code> is thrown the partially loaded     * document will     * be discarded and neither the document or page property     * change events will be fired.  If the document is     * successfully loaded and installed, a view will be     * built for it by the UI which will then be scrolled if     * necessary, and then the page property change event     * will be fired.     * <p>     * If the document is loaded asynchronously, the document     * will be installed into the editor immediately using a     * call to <code>setDocument</code> which will fire a     * document property change event, then a thread will be     * created which will begin doing the actual loading.     * In this case, the page property change event will not be     * fired by the call to this method directly, but rather will be     * fired when the thread doing the loading has finished.     * It will also be fired on the event-dispatch thread.     * Since the calling thread can not throw an <code>IOException</code>     * in the event of failure on the other thread, the page     * property change event will be fired when the other     * thread is done whether the load was successful or not.     *     * @param page the URL of the page     * @exception IOException for a <code>null</code> or invalid     *          page specification, or exception from the stream being read     * @see #getPage     * @beaninfo     *  description: the URL used to set content     *        bound: true     *       expert: true     */    public void setPage(URL page) throws IOException {        if (page == null) {            throw new IOException("invalid url");        }        URL loaded = getPage();          // reset scrollbar        if (!page.equals(loaded) && page.getRef() == null) {            scrollRectToVisible(new Rectangle(0,0,1,1));        }        boolean reloaded = false;        Object postData = getPostData();        if ((loaded == null) || !loaded.sameFile(page) || (postData != null)) {            // different url or POST method, load the new content             int p = getAsynchronousLoadPriority(getDocument());            if (p < 0) {                // open stream synchronously                InputStream in = getStream(page);                if (kit != null) {                    Document doc = initializeModel(kit, page);                     // At this point, one could either load up the model with no                    // view notifications slowing it down (i.e. best synchronous                    // behavior) or set the model and start to feed it on a separate                    // thread (best asynchronous behavior).                    p = getAsynchronousLoadPriority(doc);                    if (p >= 0) {                        // load asynchronously                        setDocument(doc);                        synchronized(this) {                            pageLoader = new PageLoader(doc, in, loaded, page);                            pageLoader.execute();                        }                        return;                    }                    read(in, doc);                    setDocument(doc);                    reloaded = true;                }            } else {                // we may need to cancel background loading                if (pageLoader != null) {                    pageLoader.cancel(true);                }                 // Do everything in a background thread.                // Model initialization is deferred to that thread, too.                pageLoader = new PageLoader(null, null, loaded, page);                pageLoader.execute();                return;            }        }        final String reference = page.getRef();        if (reference != null) {            if (!reloaded) {                scrollToReference(reference);            }            else {                // Have to scroll after painted.                SwingUtilities.invokeLater(new Runnable() {                    public void run() {                        scrollToReference(reference);                    }                });            }            getDocument().putProperty(Document.StreamDescriptionProperty, page);        }        firePropertyChange("page", loaded, page);    }     /**     * Create model and initialize document properties from page properties.     */    private Document initializeModel(EditorKit kit, URL page) {        Document doc = kit.createDefaultDocument();        if (pageProperties != null) {            // transfer properties discovered in stream to the            // document property collection.            for (Enumeration<String> e = pageProperties.keys(); e.hasMoreElements() ;) {                String key = e.nextElement();                doc.putProperty(key, pageProperties.get(key));            }            pageProperties.clear();

Lines 1–500 of 2410.