FileDocCategorySizeDatePackage
JEditorPane.javaAPI DocJava SE 6 API85415Tue Jun 10 00:26:36 BST 2008javax.swing

JEditorPane

public class JEditorPane extends JTextComponent
A text component to edit various kinds of content. You can find how-to information and examples of using editor panes in Using Text Components, a section in The Java Tutorial.

This component uses implementations of the EditorKit 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 EditorKit currently installed. If the content is set to a new URL, its type is used to determine the EditorKit that should be used to load the content.

By default, the following types of content are known:

text/plain
Plain text, which is the default the type given isn't recognized. The kit used in this case is an extension of DefaultEditorKit that produces a wrapped plain text view.
text/html
HTML text. The kit used in this case is the class javax.swing.text.html.HTMLEditorKit which provides HTML 3.2 support.
text/rtf
RTF text. The kit used in this case is the class javax.swing.text.rtf.RTFEditorKit which provides a limited support of the Rich Text Format.

There are several ways to load content into this component.

  1. The {@link #setText setText} method can be used to initialize the component from a string. In this case the current EditorKit will be used, and the content type will be expected to be of this type.
  2. The {@link #read read} method can be used to initialize the component from a Reader. Note that if the content type is HTML, relative references (e.g. for things like images) can't be resolved unless the <base> tag is used or the Base property on HTMLDocument is set. In this case the current EditorKit will be used, and the content type will be expected to be of this type.
  3. 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 EditorKit for that content type will be set.

Some kinds of content may provide hyperlink support by generating hyperlink events. The HTML EditorKit will generate hyperlink events if the JEditorPane is not editable (JEditorPane.setEditable(false); 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.


  class Hyperactive implements HyperlinkListener {
 
  public void hyperlinkUpdate(HyperlinkEvent e) {
  if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
  JEditorPane pane = (JEditorPane) e.getSource();
  if (e instanceof HTMLFrameHyperlinkEvent) {
  HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent)e;
  HTMLDocument doc = (HTMLDocument)pane.getDocument();
  doc.processHTMLFrameHyperlinkEvent(evt);
  } else {
  try {
  pane.setPage(e.getURL());
  } catch (Throwable t) {
  t.printStackTrace();
  }
  }
  }
  }
  }

For information on customizing how text/html is rendered please see {@link #W3C_LENGTH_UNITS} and {@link #HONOR_DISPLAY_PROPERTIES}

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 (JEditorPane) it is converted to the document character set (ISO-10646 aka Unicode).

There are multiple ways to get a character set mapping to happen with JEditorPane.

  1. One way is to specify the character set as a parameter of the MIME type. This will be established by a call to the setContentType method. If the content is loaded by the 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.
  2. 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 EditorKit.read operation throw a ChangedCharSetException which will be caught. The read is then restarted with a new Reader that uses the character set specified in the ChangedCharSetException (which is an IOException).

Newlines
For a discussion on how newlines are handled, see DefaultEditorKit.

Warning: Swing is not thread safe. For more information see Swing's Threading Policy.

Warning: 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 JavaBeansTM has been added to the java.beans package. Please see {@link java.beans.XMLEncoder}.

beaninfo
attribute: isContainer false description: A text component to edit various types of content.
author
Timothy Prinzing
version
1.139 08/08/06

Fields Summary
PageStream
loading
Stream currently loading asynchronously (potentially cancelable). Access to this variable should be synchronized.
private EditorKit
kit
Current content binding of the editor.
private boolean
isUserSetEditorKit
private Hashtable
pageProperties
static final String
PostDataProperty
Should be kept in sync with javax.swing.text.html.FormView counterpart.
private Hashtable
typeHandlers
Table of registered type handlers for this editor.
private static final Object
kitRegistryKey
private static final Object
kitTypeRegistryKey
private static final Object
kitLoaderRegistryKey
private static final String
uiClassID
public static final String
W3C_LENGTH_UNITS
Key for a client property used to indicate whether w3c compliant length units are used for html rendering.

By default this is not enabled; to enable it set the client {@link #putClientProperty property} with this name to Boolean.TRUE.

public static final String
HONOR_DISPLAY_PROPERTIES
Key for a client property used to indicate whether the default font and foreground color from the component are used if a font or foreground color is not specified in the styled text.

The default varies based on the look and feel; to enable it set the client {@link #putClientProperty property} with this name to Boolean.TRUE.

static final Map
defaultEditorKitMap
Constructors Summary
public JEditorPane()
Creates a new JEditorPane. The document model is set to null.

        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());
    
public JEditorPane(URL initialPage)
Creates a JEditorPane based on a specified URL for input.

param
initialPage the URL
exception
IOException if the URL is null or cannot be accessed

        this();
        setPage(initialPage);
    
public JEditorPane(String url)
Creates a JEditorPane based on a string containing a URL specification.

param
url the URL
exception
IOException if the URL is null or cannot be accessed

        this();
        setPage(url);
    
public JEditorPane(String type, String text)
Creates a JEditorPane that has been initialized to the given text. This is a convenience constructor that calls the setContentType and setText methods.

param
type mime type of the given text
param
text the text to initialize with; may be null
exception
NullPointerException if the type parameter is null

	this();
	setContentType(type);
	setText(text);
    
Methods Summary
public synchronized voidaddHyperlinkListener(javax.swing.event.HyperlinkListener listener)
Adds a hyperlink listener for notification of any changes, for example when a link is selected and entered.

param
listener the listener

        listenerList.add(HyperlinkListener.class, listener);
    
protected javax.swing.text.EditorKitcreateDefaultEditorKit()
Creates the default editor kit (PlainEditorKit) for when the component is first created.

return
the editor kit

        return new PlainEditorKit();
    
public static javax.swing.text.EditorKitcreateEditorKitForContentType(java.lang.String type)
Creates a handler for the given type from the default registry of editor kits. The registry is created if necessary. If the registered class has not yet been loaded, an attempt is made to dynamically load the prototype of the kit for the given type. If the type was registered with a ClassLoader, that ClassLoader will be used to load the prototype. If there was no registered ClassLoader, Class.forName will be used to load the prototype.

Once a prototype EditorKit instance is successfully located, it is cloned and the clone is returned.

param
type the content type
return
the editor kit, or null if there is nothing registered for the given type

        EditorKit k = null;
        Hashtable kitRegistry = getKitRegisty();
	k = (EditorKit) kitRegistry.get(type);
        if (k == null) {
            // try to dynamically load the support 
            String classname = (String) getKitTypeRegistry().get(type);
	    ClassLoader loader = (ClassLoader) getKitLoaderRegistry().get(type);
            try {
		Class c;
		if (loader != null) {
		    c = loader.loadClass(classname);
		} else {
                    // Will only happen if developer has invoked 
                    // registerEditorKitForContentType(type, class, null).
		    c = Class.forName(classname, true, Thread.currentThread().
                                      getContextClassLoader());
		}
                k = (EditorKit) c.newInstance();
                kitRegistry.put(type, k);
            } catch (Throwable e) {
                k = null;
            }
        }

        // create a copy of the prototype or null if there
        // is no prototype.
        if (k != null) {
            return (EditorKit) k.clone();
        }
        return null;
    
public voidfireHyperlinkUpdate(javax.swing.event.HyperlinkEvent e)
Notifies all listeners that have registered interest for notification on this event type. This is normally called by the currently installed EditorKit 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

        // 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);
            }          
        }
    
public javax.accessibility.AccessibleContextgetAccessibleContext()
Gets the AccessibleContext associated with this JEditorPane. For editor panes, the AccessibleContext takes the form of an AccessibleJEditorPane. A new AccessibleJEditorPane instance is created if necessary.

return
an AccessibleJEditorPane that serves as the AccessibleContext of this JEditorPane

        if (getEditorKit() instanceof HTMLEditorKit) {
            if (accessibleContext == null || accessibleContext.getClass() !=
                    AccessibleJEditorPaneHTML.class) {
                accessibleContext = new AccessibleJEditorPaneHTML();
            }
        } else if (accessibleContext == null || accessibleContext.getClass() !=
                       AccessibleJEditorPane.class) {
            accessibleContext = new AccessibleJEditorPane();
        } 
        return accessibleContext;
    
private intgetAsynchronousLoadPriority(javax.swing.text.Document doc)
Return load priority for the document or -1 if priority not supported.

        return (doc instanceof AbstractDocument ?
            ((AbstractDocument) doc).getAsynchronousLoadPriority() : -1);
    
public final java.lang.StringgetContentType()
Gets the type of content that this editor is currently set to deal with. This is defined to be the type associated with the currently installed EditorKit.

return
the content type, null if no editor kit set

        return (kit != null) ? kit.getContentType() : null;
    
public javax.swing.text.EditorKitgetEditorKit()
Fetches the currently installed kit for handling content. createDefaultEditorKit is called to set up a default if necessary.

return
the editor kit

        if (kit == null) {
            kit = createDefaultEditorKit();
            isUserSetEditorKit = false;
        }
        return kit;
    
public static java.lang.StringgetEditorKitClassNameForContentType(java.lang.String type)
Returns the currently registered EditorKit class name for the type type.

param
type the non-null content type
since
1.3

	return (String)getKitTypeRegistry().get(type);
    
public javax.swing.text.EditorKitgetEditorKitForContentType(java.lang.String type)
Fetches the editor kit to use for the given type of content. This is called when a type is requested that doesn't match the currently installed type. If the component doesn't have an EditorKit registered for the given type, it will try to create an EditorKit from the default EditorKit registry. If that fails, a PlainEditorKit is used on the assumption that all text documents can be represented as plain text.

This method can be reimplemented to use some other kind of type registry. This can be reimplemented to use the Java Activation Framework, for example.

param
type the non-null content type
return
the editor kit

        if (typeHandlers == null) {
            typeHandlers = new Hashtable(3);
        }
        EditorKit k = (EditorKit) typeHandlers.get(type);
        if (k == null) {
            k = createEditorKitForContentType(type);
            if (k != null) {
                setEditorKitForContentType(type, k);
            }
        }
        if (k == null) {
            k = createDefaultEditorKit();
        }
        return k;
    
public synchronized javax.swing.event.HyperlinkListener[]getHyperlinkListeners()
Returns an array of all the HyperLinkListeners added to this JEditorPane with addHyperlinkListener().

return
all of the HyperLinkListeners added or an empty array if no listeners have been added
since
1.4

        return (HyperlinkListener[])listenerList.getListeners(
                HyperlinkListener.class);
    
private static java.util.HashtablegetKitLoaderRegistry()

	loadDefaultKitsIfNecessary();
	return (Hashtable)SwingUtilities.appContextGet(kitLoaderRegistryKey);
    
private static java.util.HashtablegetKitRegisty()

	Hashtable ht = (Hashtable)SwingUtilities.appContextGet(kitRegistryKey);
	if (ht == null) {
	    ht = new Hashtable(3);
	    SwingUtilities.appContextPut(kitRegistryKey, ht);
	}
	return ht;
    
private static java.util.HashtablegetKitTypeRegistry()

	loadDefaultKitsIfNecessary();
	return (Hashtable)SwingUtilities.appContextGet(kitTypeRegistryKey);
    
public java.net.URLgetPage()
Gets the current URL being displayed. If a URL was not specified in the creation of the document, this will return null, and relative URL's will not be resolved.

return
the URL, or null if none

        return (URL) getDocument().getProperty(Document.StreamDescriptionProperty);
    
private java.lang.ObjectgetPostData()

        return getDocument().getProperty(PostDataProperty);
    
public java.awt.DimensiongetPreferredSize()
Returns the preferred size for the JEditorPane. The preferred size for JEditorPane is slightly altered from the preferred size of the superclass. If the size of the viewport has become smaller than the minimum size of the component, the scrollable definition for tracking width or height will turn to false. The default viewport layout will give the preferred size, and that is not desired in the case where the scrollable is tracking. In that case the normal preferred size is adjusted to the minimum size. This allows things like HTML tables to shrink down to their minimum size and then be laid out at their minimum size, refusing to shrink any further.

return
a Dimension containing the preferred size

	Dimension d = super.getPreferredSize();
	if (getParent() instanceof JViewport) {
	    JViewport port = (JViewport)getParent();
	    TextUI ui = getUI();
            int prefWidth = d.width;
            int prefHeight = d.height;
	    if (! getScrollableTracksViewportWidth()) {
		int w = port.getWidth();
		Dimension min = ui.getMinimumSize(this);
		if (w != 0 && w < min.width) {
                    // Only adjust to min if we have a valid size
		    prefWidth = min.width;
		}
	    }
	    if (! getScrollableTracksViewportHeight()) {
		int h = port.getHeight();
		Dimension min = ui.getMinimumSize(this);
		if (h != 0 && h < min.height) {
                    // Only adjust to min if we have a valid size
		    prefHeight = min.height;
		}
	    }
            if (prefWidth != d.width || prefHeight != d.height) {
                d = new Dimension(prefWidth, prefHeight);
            }
	}
	return d;
    
public booleangetScrollableTracksViewportHeight()
Returns true if a viewport should always force the height of this Scrollable to match the height of the viewport.

return
true if a viewport should force the Scrollable's height to match its own, false otherwise

	if (getParent() instanceof JViewport) {
	    JViewport port = (JViewport)getParent();
	    TextUI ui = getUI();
	    int h = port.getHeight();
	    Dimension min = ui.getMinimumSize(this);
	    if (h >= min.height) {
		Dimension max = ui.getMaximumSize(this);
		if (h <= max.height) {
		    return true;
		}
	    }
	}
	return false;
    
public booleangetScrollableTracksViewportWidth()
Returns true if a viewport should always force the width of this Scrollable to match the width of the viewport.

return
true if a viewport should force the Scrollables width to match its own, false otherwise

	if (getParent() instanceof JViewport) {
	    JViewport port = (JViewport)getParent();
	    TextUI ui = getUI();
	    int w = port.getWidth();
	    Dimension min = ui.getMinimumSize(this);
	    Dimension max = ui.getMaximumSize(this);
	    if ((w >= min.width) && (w <= max.width)) {
		return true;
	    }
	}
	return false;
    
protected java.io.InputStreamgetStream(java.net.URL page)
Fetches a stream for the given URL, which is about to be loaded by the setPage method. By default, this simply opens the URL and returns the stream. This can be reimplemented to do useful things like fetch the stream from a cache, monitor the progress of the stream, etc.

This method is expected to have the the side effect of establishing the content type, and therefore setting the appropriate EditorKit to use for loading the stream.

If this the stream was an http connection, redirects will be followed and the resulting URL will be set as the Document.StreamDescriptionProperty so that relative URL's can be properly resolved.

param
page the URL of the page

        final URLConnection conn = page.openConnection();
	if (conn instanceof HttpURLConnection) {
	    HttpURLConnection hconn = (HttpURLConnection) conn;
	    hconn.setInstanceFollowRedirects(false);
            Object postData = getPostData();
            if (postData != null) {
                handlePostData(hconn, postData);
            }
	    int response = hconn.getResponseCode();
	    boolean redirect = (response >= 300 && response <= 399);

	    /*
	     * In the case of a redirect, we want to actually change the URL
	     * that was input to the new, redirected URL
	     */
	    if (redirect) {
		String loc = conn.getHeaderField("Location");
		if (loc.startsWith("http", 0)) {
		    page = new URL(loc);
		} else {
		    page = new URL(page, loc);
		}
		return getStream(page);
	    }
	}

        // Connection properties handler should be forced to run on EDT,
        // as it instantiates the EditorKit.
        if (SwingUtilities.isEventDispatchThread()) {
            handleConnectionProperties(conn);
        } else {
            try {
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        handleConnectionProperties(conn);
                    }
                });
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }
        return conn.getInputStream();
    
public java.lang.StringgetText()
Returns the text contained in this TextComponent in terms of the content type of this editor. If an exception is thrown while attempting to retrieve the text, null will be returned. This is implemented to call JTextComponent.write with a StringWriter.

return
the text
see
#setText

	String txt;
	try {
	    StringWriter buf = new StringWriter();
	    write(buf);
	    txt = buf.toString();
        } catch (IOException ioe) {
            txt = null;
        }
        return txt;
    
public java.lang.StringgetUIClassID()
Gets the class ID for the UI.

return
the string "EditorPaneUI"
see
JComponent#getUIClassID
see
UIDefaults#getUI

        return uiClassID;
    
private voidhandleConnectionProperties(java.net.URLConnection conn)
Handle URL connection properties (most notably, content type).

	if (pageProperties == null) {
	    pageProperties = new Hashtable();
	}
	String type = conn.getContentType();
	if (type != null) {
	    setContentType(type);
	    pageProperties.put("content-type", type);
	}
        pageProperties.put(Document.StreamDescriptionProperty, conn.getURL());
	String enc = conn.getContentEncoding();
	if (enc != null) {
	    pageProperties.put("content-encoding", enc);
	}
    
private voidhandlePostData(java.net.HttpURLConnection conn, java.lang.Object postData)

        conn.setDoOutput(true);
        DataOutputStream os = null;
        try {
            conn.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            os = new DataOutputStream(conn.getOutputStream());
            os.writeBytes((String) postData);
        } finally {
            if (os != null) {
                os.close();
            }
        }
    
private javax.swing.text.DocumentinitializeModel(javax.swing.text.EditorKit kit, java.net.URL page)
Create model and initialize document properties from page properties.

        Document doc = kit.createDefaultDocument();
        if (pageProperties != null) {
            // transfer properties discovered in stream to the
            // document property collection.
            for (Enumeration e = pageProperties.keys(); e.hasMoreElements() ;) {
                Object key = e.nextElement();
                doc.putProperty(key, pageProperties.get(key));
            }
            pageProperties.clear();
        }
        if (doc.getProperty(Document.StreamDescriptionProperty) == null) {
            doc.putProperty(Document.StreamDescriptionProperty, page);
        }
        return doc;
    
private static voidloadDefaultKitsIfNecessary()
This is invoked every time the registries are accessed. Loading is done this way instead of via a static as the static is only called once when running in plugin resulting in the entries only appearing in the first applet.

	if (SwingUtilities.appContextGet(kitTypeRegistryKey) == null) {
            synchronized(defaultEditorKitMap) {
                if (defaultEditorKitMap.size() == 0) {
                    defaultEditorKitMap.put("text/plain",
                                            "javax.swing.JEditorPane$PlainEditorKit");
                    defaultEditorKitMap.put("text/html",
                                            "javax.swing.text.html.HTMLEditorKit");
                    defaultEditorKitMap.put("text/rtf",
                                            "javax.swing.text.rtf.RTFEditorKit");
                    defaultEditorKitMap.put("application/rtf",
                                            "javax.swing.text.rtf.RTFEditorKit");                    
                }
            }
	    Hashtable ht = new Hashtable();
	    SwingUtilities.appContextPut(kitTypeRegistryKey, ht);
	    ht = new Hashtable();
	    SwingUtilities.appContextPut(kitLoaderRegistryKey, ht);
            for (String key : defaultEditorKitMap.keySet()) {
                registerEditorKitForContentType(key,defaultEditorKitMap.get(key));
            }
            
	}
    
protected java.lang.StringparamString()
Returns a string representation of this JEditorPane. This method is intended to be used only for debugging purposes, and the content and format of the returned string may vary between implementations. The returned string may be empty but may not be null.

return
a string representation of this JEditorPane


                                                                     
       
        String kitString = (kit != null ?
			    kit.toString() : "");
        String typeHandlersString = (typeHandlers != null ?
				     typeHandlers.toString() : "");

        return super.paramString() +
        ",kit=" + kitString +
        ",typeHandlers=" + typeHandlersString;
    
public voidread(java.io.InputStream in, java.lang.Object desc)
This method initializes from a stream. If the kit is set to be of type HTMLEditorKit, and the desc parameter is an HTMLDocument, then it invokes the HTMLEditorKit to initiate the read. Otherwise it calls the superclass method which loads the model as plain text.

param
in the stream from which to read
param
desc an object describing the stream
exception
IOException as thrown by the stream being used to initialize
see
JTextComponent#read
see
#setDocument


	if (desc instanceof HTMLDocument && 
	    kit instanceof HTMLEditorKit) {
	    HTMLDocument hdoc = (HTMLDocument) desc;
	    setDocument(hdoc);
	    read(in, hdoc);
	} else {
	    String charset = (String) getClientProperty("charset");
	    Reader r = (charset != null) ? new InputStreamReader(in, charset) :
		new InputStreamReader(in);
	    super.read(r, desc);
	}
    
voidread(java.io.InputStream in, javax.swing.text.Document doc)
This method invokes the EditorKit to initiate a read. In the case where a ChangedCharSetException is thrown this exception will contain the new CharSet. Therefore the read operation is then restarted after building a new Reader with the new charset.

param
in the inputstream to use
param
doc the document to load

        if (! Boolean.TRUE.equals(doc.getProperty("IgnoreCharsetDirective"))) {
            final int READ_LIMIT = 1024 * 10;
            in = new BufferedInputStream(in, READ_LIMIT);
            in.mark(READ_LIMIT);
        }
	try {
	    String charset = (String) getClientProperty("charset");
	    Reader r = (charset != null) ? new InputStreamReader(in, charset) :
		new InputStreamReader(in);
	    kit.read(r, doc, 0);
	} catch (BadLocationException e) {
	    throw new IOException(e.getMessage());
	} catch (ChangedCharSetException changedCharSetException) {
	    String charSetSpec = changedCharSetException.getCharSetSpec();
	    if (changedCharSetException.keyEqualsCharSet()) {
		putClientProperty("charset", charSetSpec);
	    } else {
		setCharsetFromContentTypeParameters(charSetSpec);
	    }
            try {
                in.reset();
            } catch (IOException exception) {
                //mark was invalidated
                in.close();
                URL url = (URL)doc.getProperty(Document.StreamDescriptionProperty);
                if (url != null) {
                    URLConnection conn = url.openConnection();
                    in = conn.getInputStream();
                } else {
                    //there is nothing we can do to recover stream
                    throw changedCharSetException;
                }
            }
	    try {
		doc.remove(0, doc.getLength());
	    } catch (BadLocationException e) {}
	    doc.putProperty("IgnoreCharsetDirective", Boolean.valueOf(true));
	    read(in, doc);
	}
    
public static voidregisterEditorKitForContentType(java.lang.String type, java.lang.String classname)
Establishes the default bindings of type to classname. The class will be dynamically loaded later when actually needed, and can be safely changed before attempted uses to avoid loading unwanted classes. The prototype EditorKit will be loaded with Class.forName when registered with this method.

param
type the non-null content type
param
classname the class to load later

        registerEditorKitForContentType(type, classname,Thread.currentThread().
                                        getContextClassLoader());
    
public static voidregisterEditorKitForContentType(java.lang.String type, java.lang.String classname, java.lang.ClassLoader loader)
Establishes the default bindings of type to classname. The class will be dynamically loaded later when actually needed using the given ClassLoader, and can be safely changed before attempted uses to avoid loading unwanted classes.

param
type the non-null content type
param
classname the class to load later
param
loader the ClassLoader to use to load the name

        getKitTypeRegistry().put(type, classname);
	getKitLoaderRegistry().put(type, loader);
	getKitRegisty().remove(type);
    
public synchronized voidremoveHyperlinkListener(javax.swing.event.HyperlinkListener listener)
Removes a hyperlink listener.

param
listener the listener

        listenerList.remove(HyperlinkListener.class, listener);
    
public voidreplaceSelection(java.lang.String content)
Replaces the currently selected content with new content represented by the given string. If there is no selection this amounts to an insert of the given text. If there is no replacement text (i.e. the content string is empty or null) this amounts to a removal of the current selection. The replacement text will have the attributes currently defined for input. If the component is not editable, beep and return.

This method is thread safe, although most Swing methods are not. Please see How to Use Threads for more information.

param
content the content to replace the selection with. This value can be null

        if (! isEditable()) {
	    UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
            return;
        }
        EditorKit kit = getEditorKit();
	if(kit instanceof StyledEditorKit) {
            try {
		Document doc = getDocument();
                Caret caret = getCaret();
                int p0 = Math.min(caret.getDot(), caret.getMark());
                int p1 = Math.max(caret.getDot(), caret.getMark());
                if (doc instanceof AbstractDocument) {
                    ((AbstractDocument)doc).replace(p0, p1 - p0, content, 
                              ((StyledEditorKit)kit).getInputAttributes());
                }
                else {
                    if (p0 != p1) {
                        doc.remove(p0, p1 - p0);
                    }
                    if (content != null && content.length() > 0) {
                        doc.insertString(p0, content, ((StyledEditorKit)kit).
                                         getInputAttributes());
                    }
                }
            } catch (BadLocationException e) {
	        UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
            }
        }
        else {
	    super.replaceSelection(content);
	}
    
public voidscrollToReference(java.lang.String reference)
Scrolls the view to the given reference location (that is, the value returned by the UL.getRef method for the URL being displayed). By default, this method only knows how to locate a reference in an HTMLDocument. The implementation calls the scrollRectToVisible method to accomplish the actual scrolling. If scrolling to a reference location is needed for document types other than HTML, this method should be reimplemented. This method will have no effect if the component is not visible.

param
reference the named location to scroll to

	Document d = getDocument();
	if (d instanceof HTMLDocument) {
	    HTMLDocument doc = (HTMLDocument) d;
	    HTMLDocument.Iterator iter = doc.getIterator(HTML.Tag.A);
	    for (; iter.isValid(); iter.next()) {
		AttributeSet a = iter.getAttributes();
		String nm = (String) a.getAttribute(HTML.Attribute.NAME);
		if ((nm != null) && nm.equals(reference)) {
		    // found a matching reference in the document.
		    try {
			Rectangle r = modelToView(iter.getStartOffset());
			if (r != null) {
			    // the view is visible, scroll it to the 
			    // center of the current visible area.
			    Rectangle vis = getVisibleRect();
			    //r.y -= (vis.height / 2);
			    r.height = vis.height;
			    scrollRectToVisible(r);
			}
		    } catch (BadLocationException ble) {
		        UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
		    }
		}
	    }
	}
    
private voidsetCharsetFromContentTypeParameters(java.lang.String paramlist)
This method gets the charset information specified as part of the content type in the http header information.

	String charset = null;
	try {
	    // paramlist is handed to us with a leading ';', strip it.
	    int semi = paramlist.indexOf(';");
	    if (semi > -1 && semi < paramlist.length()-1) {
		paramlist = paramlist.substring(semi + 1);
	    }

	    if (paramlist.length() > 0) {
		// parse the paramlist into attr-value pairs & get the
		// charset pair's value
		HeaderParser hdrParser = new HeaderParser(paramlist);
		charset = hdrParser.findValue("charset");
		if (charset != null) {
		    putClientProperty("charset", charset);
		}
	    }
	}
	catch (IndexOutOfBoundsException e) {
	    // malformed parameter list, use charset we have
	}
	catch (NullPointerException e) {
	    // malformed parameter list, use charset we have
	}
	catch (Exception e) {
	    // malformed parameter list, use charset we have; but complain
	    System.err.println("JEditorPane.getCharsetFromContentTypeParameters failed on: " + paramlist);
	    e.printStackTrace();
	}
    
public final voidsetContentType(java.lang.String type)
Sets the type of content that this editor handles. This calls getEditorKitForContentType, and then setEditorKit if an editor kit can be successfully located. This is mostly convenience method that can be used as an alternative to calling setEditorKit directly.

If there is a charset definition specified as a parameter of the content type specification, it will be used when loading input streams using the associated EditorKit. For example if the type is specified as text/html; charset=EUC-JP the content will be loaded using the EditorKit registered for text/html and the Reader provided to the EditorKit to load unicode into the document will use the EUC-JP charset for translating to unicode. If the type is not recognized, the content will be loaded using the EditorKit registered for plain text, text/plain.

param
type the non-null mime type for the content editing support
see
#getContentType
beaninfo
description: the type of content
throws
NullPointerException if the type parameter is null

	// The type could have optional info is part of it,
	// for example some charset info.  We need to strip that
	// of and save it.
	int parm = type.indexOf(";");
	if (parm > -1) {
	    // Save the paramList.
	    String paramList = type.substring(parm);
	    // update the content type string.
	    type = type.substring(0, parm).trim();
	    if (type.toLowerCase().startsWith("text/")) {
		setCharsetFromContentTypeParameters(paramList);
	    }
	}
        if ((kit == null) || (! type.equals(kit.getContentType()))
                || !isUserSetEditorKit) { 
            EditorKit k = getEditorKitForContentType(type);
            if (k != null && k != kit) { 
                setEditorKit(k);
                isUserSetEditorKit = false;
            }
        }

    
public voidsetEditorKit(javax.swing.text.EditorKit kit)
Sets the currently installed kit for handling content. This is the bound property that establishes the content type of the editor. Any old kit is first deinstalled, then if kit is non-null, the new kit is installed, and a default document created for it. A PropertyChange event ("editorKit") is always fired when setEditorKit is called.

NOTE: This has the side effect of changing the model, because the EditorKit is the source of how a particular type of content is modeled. This method will cause setDocument to be called on behalf of the caller to ensure integrity of the internal state.

param
kit the desired editor behavior
see
#getEditorKit
beaninfo
description: the currently installed kit for handling content bound: true expert: true

        EditorKit old = this.kit;
        isUserSetEditorKit = true;
        if (old != null) {
            old.deinstall(this);
        }
        this.kit = kit;
        if (this.kit != null) {
            this.kit.install(this);
            setDocument(this.kit.createDefaultDocument());
        }
        firePropertyChange("editorKit", old, kit);
    
public voidsetEditorKitForContentType(java.lang.String type, javax.swing.text.EditorKit k)
Directly sets the editor kit to use for the given type. A look-and-feel implementation might use this in conjunction with createEditorKitForContentType to install handlers for content types with a look-and-feel bias.

param
type the non-null content type
param
k the editor kit to be set

        if (typeHandlers == null) {
            typeHandlers = new Hashtable(3);
        }
        typeHandlers.put(type, k);
    
public voidsetPage(java.lang.String url)
Sets the current URL being displayed.

param
url the URL for display
exception
IOException for a null or invalid URL specification

        if (url == null) {
            throw new IOException("invalid url");
        }
        URL page = new URL(url);
        setPage(page);
    
public voidsetPage(java.net.URL page)
Sets the current URL being displayed. The content type of the pane is set, and if the editor kit for the pane is non-null, 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 scrollToReference 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:
Document doc = jEditorPane.getDocument();
doc.putProperty(Document.StreamDescriptionProperty, null);
If the desired URL is not the one currently being displayed, the getStream method is called to give subclasses control over the stream provided.

This may load either synchronously or asynchronously depending upon the document returned by the EditorKit. If the Document is of type AbstractDocument and has a value returned by AbstractDocument.getAsynchronousLoadPriority that is greater than or equal to zero, the page will be loaded on a separate thread using that priority.

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 setDocument, which is bound and will fire a property change event. If an IOException 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.

If the document is loaded asynchronously, the document will be installed into the editor immediately using a call to setDocument 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 IOException 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 null 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

        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 ((postData == null) || (p < 0)) {
                // Either we do not have POST data, or should submit the data
                // 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).
                    synchronized(this) {
                        if (loading != null) {
                            // we are loading asynchronously, so we need to cancel
                            // the old stream.
                            loading.cancel();
                            loading = null;
                        }
                    }
                    p = getAsynchronousLoadPriority(doc);
                    if (p >= 0) {
                        // load asynchronously
                        setDocument(doc);
                        synchronized(this) {
                            loading = new PageStream(in);
                            Thread pl = new PageLoader(doc, loading, p, loaded, page);
                            pl.start();
                        }
                        return;
                    }
                    read(in, doc);
                    setDocument(doc);
                    reloaded = true;
                }
            } else {
                // We have POST data and should send it asynchronously.
                // Send (and subsequentally read) data in separate thread.
                // Model initialization is deferred to that thread, too.
                Thread pl = new PageLoader(null, null, p, loaded, page);
                pl.start();
                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);
    
public voidsetText(java.lang.String t)
Sets the text of this TextComponent to the specified content, which is expected to be in the format of the content type of this editor. For example, if the type is set to text/html the string should be specified in terms of HTML.

This is implemented to remove the contents of the current document, and replace them by parsing the given string using the current EditorKit. This gives the semantics of the superclass by not changing out the model, while supporting the content type currently set on this component. The assumption is that the previous content is relatively small, and that the previous content doesn't have side effects. Both of those assumptions can be violated and cause undesirable results. To avoid this, create a new document, getEditorKit().createDefaultDocument(), and replace the existing Document with the new one. You are then assured the previous Document won't have any lingering state.

  1. Leaving the existing model in place means that the old view will be torn down, and a new view created, where replacing the document would avoid the tear down of the old view.
  2. Some formats (such as HTML) can install things into the document that can influence future contents. HTML can have style information embedded that would influence the next content installed unexpectedly.

An alternative way to load this component with a string would be to create a StringReader and call the read method. In this case the model would be replaced after it was initialized with the contents of the string.

This method is thread safe, although most Swing methods are not. Please see How to Use Threads for more information.

param
t the new text to be set; if null the old text will be deleted
see
#getText
beaninfo
description: the text of this component

        try {
	    Document doc = getDocument();
	    doc.remove(0, doc.getLength());
	    if (t == null || t.equals("")) {
		return;
	    }
	    Reader r = new StringReader(t);
	    EditorKit kit = getEditorKit();
            kit.read(r, doc, 0);
        } catch (IOException ioe) {
	    UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
        } catch (BadLocationException ble) {
	    UIManager.getLookAndFeel().provideErrorFeedback(JEditorPane.this);
	}
    
private voidwriteObject(java.io.ObjectOutputStream s)
See readObject and writeObject in JComponent for more information about serialization in Swing.

        s.defaultWriteObject();
        if (getUIClassID().equals(uiClassID)) {
            byte count = JComponent.getWriteObjCounter(this);
            JComponent.setWriteObjCounter(this, --count);
            if (count == 0 && ui != null) {
                ui.installUI(this);
            }
        }