FileDocCategorySizeDatePackage
HTMLEditorKit.javaAPI DocJava SE 6 API74097Tue Jun 10 00:27:00 BST 2008javax.swing.text.html

HTMLEditorKit

public class HTMLEditorKit extends StyledEditorKit implements Accessible
The Swing JEditorPane text component supports different kinds of content via a plug-in mechanism called an EditorKit. Because HTML is a very popular format of content, some support is provided by default. The default support is provided by this class, which supports HTML version 3.2 (with some extensions), and is migrating toward version 4.0. The <applet> tag is not supported, but some support is provided for the <object> tag.

There are several goals of the HTML EditorKit provided, that have an effect upon the way that HTML is modeled. These have influenced its design in a substantial way.

Support editing
It might seem fairly obvious that a plug-in for JEditorPane should provide editing support, but that fact has several design considerations. There are a substantial number of HTML documents that don't properly conform to an HTML specification. These must be normalized somewhat into a correct form if one is to edit them. Additionally, users don't like to be presented with an excessive amount of structure editing, so using traditional text editing gestures is preferred over using the HTML structure exactly as defined in the HTML document.

The modeling of HTML is provided by the class HTMLDocument. Its documention describes the details of how the HTML is modeled. The editing support leverages heavily off of the text package.

Extendable/Scalable
To maximize the usefulness of this kit, a great deal of effort has gone into making it extendable. These are some of the features.
  1. The parser is replacable. The default parser is the Hot Java parser which is DTD based. A different DTD can be used, or an entirely different parser can be used. To change the parser, reimplement the getParser method. The default parser is dynamically loaded when first asked for, so the class files will never be loaded if an alternative parser is used. The default parser is in a separate package called parser below this package.
  2. The parser drives the ParserCallback, which is provided by HTMLDocument. To change the callback, subclass HTMLDocument and reimplement the createDefaultDocument method to return document that produces a different reader. The reader controls how the document is structured. Although the Document provides HTML support by default, there is nothing preventing support of non-HTML tags that result in alternative element structures.
  3. The default view of the models are provided as a hierarchy of View implementations, so one can easily customize how a particular element is displayed or add capabilities for new kinds of elements by providing new View implementations. The default set of views are provided by the HTMLFactory class. This can be easily changed by subclassing or replacing the HTMLFactory and reimplementing the getViewFactory method to return the alternative factory.
  4. The View implementations work primarily off of CSS attributes, which are kept in the views. This makes it possible to have multiple views mapped over the same model that appear substantially different. This can be especially useful for printing. For most HTML attributes, the HTML attributes are converted to CSS attributes for display. This helps make the View implementations more general purpose

Asynchronous Loading
Larger documents involve a lot of parsing and take some time to load. By default, this kit produces documents that will be loaded asynchronously if loaded using JEditorPane.setPage. This is controlled by a property on the document. The method createDefaultDocument can be overriden to change this. The batching of work is done by the HTMLDocument.HTMLReader class. The actual work is done by the DefaultStyledDocument and AbstractDocument classes in the text package.

Customization from current LAF
HTML provides a well known set of features without exactly specifying the display characteristics. Swing has a theme mechanism for its look-and-feel implementations. It is desirable for the look-and-feel to feed display characteristics into the HTML views. An user with poor vision for example would want high contrast and larger than typical fonts.

The support for this is provided by the StyleSheet class. The presentation of the HTML can be heavily influenced by the setting of the StyleSheet property on the EditorKit.

Not lossy
An EditorKit has the ability to be read and save documents. It is generally the most pleasing to users if there is no loss of data between the two operation. The policy of the HTMLEditorKit will be to store things not recognized or not necessarily visible so they can be subsequently written out. The model of the HTML document should therefore contain all information discovered while reading the document. This is constrained in some ways by the need to support editing (i.e. incorrect documents sometimes must be normalized). The guiding principle is that information shouldn't be lost, but some might be synthesized to produce a more correct model or it might be rearranged.
author
Timothy Prinzing
version
1.136 04/07/06

Fields Summary
private JEditorPane
theEditor
public static final String
DEFAULT_CSS
Default Cascading Style Sheet file that sets up the tag views.
private AccessibleContext
accessibleContext
private static final Cursor
MoveCursor
private static final Cursor
DefaultCursor
private static final ViewFactory
defaultFactory
Shared factory for creating HTML Views.
MutableAttributeSet
input
private static StyleSheet
defaultStyles
private LinkController
linkHandler
private static Parser
defaultParser
private Cursor
defaultCursor
private Cursor
linkCursor
private boolean
isAutoFormSubmission
public static final String
BOLD_ACTION
The bold action identifier
public static final String
ITALIC_ACTION
The italic action identifier
public static final String
PARA_INDENT_LEFT
The paragraph left indent action identifier
public static final String
PARA_INDENT_RIGHT
The paragraph right indent action identifier
public static final String
FONT_CHANGE_BIGGER
The font size increase to next value action identifier
public static final String
FONT_CHANGE_SMALLER
The font size decrease to next value action identifier
public static final String
COLOR_ACTION
The Color choice action identifier The color is passed as an argument
public static final String
LOGICAL_STYLE_ACTION
The logical style choice action identifier The logical style is passed in as an argument
public static final String
IMG_ALIGN_TOP
Align images at the top.
public static final String
IMG_ALIGN_MIDDLE
Align images in the middle.
public static final String
IMG_ALIGN_BOTTOM
Align images at the bottom.
public static final String
IMG_BORDER
Align images at the border.
private static final String
INSERT_TABLE_HTML
HTML used when inserting tables.
private static final String
INSERT_UL_HTML
HTML used when inserting unordered lists.
private static final String
INSERT_OL_HTML
HTML used when inserting ordered lists.
private static final String
INSERT_HR_HTML
HTML used when inserting hr.
private static final String
INSERT_PRE_HTML
HTML used when inserting pre.
private static NavigateLinkAction
nextLinkAction
private static NavigateLinkAction
previousLinkAction
private static ActivateLinkAction
activateLinkAction
private static final Action[]
defaultActions
Constructors Summary
public HTMLEditorKit()
Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet.


    
Methods Summary
public java.lang.Objectclone()
Creates a copy of the editor kit.

return
the copy

	HTMLEditorKit o = (HTMLEditorKit)super.clone();
        if (o != null) {
            o.input = null;
            o.linkHandler = new LinkController();
        }
	return o;
    
public javax.swing.text.DocumentcreateDefaultDocument()
Create an uninitialized text storage model that is appropriate for this type of editor.

return
the model

	StyleSheet styles = getStyleSheet();
	StyleSheet ss = new StyleSheet();

	ss.addStyleSheet(styles);

	HTMLDocument doc = new HTMLDocument(ss);
	doc.setParser(getParser());
	doc.setAsynchronousLoadPriority(4);
	doc.setTokenThreshold(100);
	return doc;
    
protected voidcreateInputAttributes(javax.swing.text.Element element, javax.swing.text.MutableAttributeSet set)
Copies the key/values in elements AttributeSet into set. This does not copy component, icon, or element names attributes. Subclasses may wish to refine what is and what isn't copied here. But be sure to first remove all the attributes that are in set.

This is called anytime the caret moves over a different location.

	set.removeAttributes(set);
	set.addAttributes(element.getAttributes());
	set.removeAttribute(StyleConstants.ComposedTextAttribute);

	Object o = set.getAttribute(StyleConstants.NameAttribute);
	if (o instanceof HTML.Tag) {
	    HTML.Tag tag = (HTML.Tag)o;
	    // PENDING: we need a better way to express what shouldn't be
	    // copied when editing...
	    if(tag == HTML.Tag.IMG) {
		// Remove the related image attributes, src, width, height
		set.removeAttribute(HTML.Attribute.SRC);
		set.removeAttribute(HTML.Attribute.HEIGHT);
		set.removeAttribute(HTML.Attribute.WIDTH);
		set.addAttribute(StyleConstants.NameAttribute,
				 HTML.Tag.CONTENT);
	    }
	    else if (tag == HTML.Tag.HR || tag == HTML.Tag.BR) {
		// Don't copy HRs or BRs either.
		set.addAttribute(StyleConstants.NameAttribute,
				 HTML.Tag.CONTENT);
	    }
	    else if (tag == HTML.Tag.COMMENT) {
		// Don't copy COMMENTs either
		set.addAttribute(StyleConstants.NameAttribute,
				 HTML.Tag.CONTENT);
		set.removeAttribute(HTML.Attribute.COMMENT);
	    }
	    else if (tag == HTML.Tag.INPUT) {
		// or INPUT either
		set.addAttribute(StyleConstants.NameAttribute,
				 HTML.Tag.CONTENT);
		set.removeAttribute(HTML.Tag.INPUT);
	    }
	    else if (tag instanceof HTML.UnknownTag) {
		// Don't copy unknowns either:(
		set.addAttribute(StyleConstants.NameAttribute,
				 HTML.Tag.CONTENT);
		set.removeAttribute(HTML.Attribute.ENDTAG);
	    }
	}
    
public voiddeinstall(javax.swing.JEditorPane c)
Called when the kit is being removed from the JEditorPane. This is used to unregister any listeners that were attached.

param
c the JEditorPane

	c.removeMouseListener(linkHandler);
        c.removeMouseMotionListener(linkHandler);
	c.removeCaretListener(nextLinkAction);
	super.deinstall(c);
        theEditor = null;
    
public javax.accessibility.AccessibleContextgetAccessibleContext()
returns the AccessibleContext associated with this editor kit

return
the AccessibleContext associated with this editor kit
since
1.4

	if (theEditor == null) {
	    return null;
	}
	if (accessibleContext == null) {
	    AccessibleHTML a = new AccessibleHTML(theEditor);
	    accessibleContext = a.getAccessibleContext();
	}
	return accessibleContext;
    
public javax.swing.Action[]getActions()
Fetches the command list for the editor. This is the list of commands supported by the superclass augmented by the collection of commands defined locally for style operations.

return
the command list

	return TextAction.augmentList(super.getActions(), this.defaultActions);
    
private static java.lang.ObjectgetAttrValue(javax.swing.text.AttributeSet attr, javax.swing.text.html.HTML$Attribute key)

	Enumeration names = attr.getAttributeNames();
	while (names.hasMoreElements()) {
	    Object nextKey = names.nextElement();
	    Object nextVal = attr.getAttribute(nextKey);
	    if (nextVal instanceof AttributeSet) {
		Object value = getAttrValue((AttributeSet)nextVal, key);
		if (value != null) {
		    return value;
		}
	    } else if (nextKey == key) {
		return nextVal;
	    }	
	}
	return null;
    
private static intgetBodyElementStart(javax.swing.text.JTextComponent comp)

        Element rootElement = comp.getDocument().getRootElements()[0];
        for (int i = 0; i < rootElement.getElementCount(); i++) {
            Element currElement = rootElement.getElement(i); 
            if("body".equals(currElement.getName())) {
                return currElement.getStartOffset();
            }
        }
        return 0;
    
public java.lang.StringgetContentType()
Get the MIME type of the data that this kit represents support for. This kit supports the type text/html.

return
the type

	return "text/html";
    
public java.awt.CursorgetDefaultCursor()
Returns the default cursor.

since
1.3

	return defaultCursor;
    
public javax.swing.text.MutableAttributeSetgetInputAttributes()
Gets the input attributes used for the styled editing actions.

return
the attribute set

	if (input == null) {
	    input = getStyleSheet().addStyle(null, null);
	}
	return input;
    
public java.awt.CursorgetLinkCursor()
Returns the cursor to use over hyper links.

since
1.3

	return linkCursor;
    
protected javax.swing.text.html.HTMLEditorKit$ParsergetParser()
Fetch the parser to use for reading HTML streams. This can be reimplemented to provide a different parser. The default implementation is loaded dynamically to avoid the overhead of loading the default parser if it's not used. The default parser is the HotJava parser using an HTML 3.2 DTD.

	if (defaultParser == null) {
	    try {
                Class c = Class.forName("javax.swing.text.html.parser.ParserDelegator");
                defaultParser = (Parser) c.newInstance();
	    } catch (Throwable e) {
	    }
	}
	return defaultParser;
    
static java.io.InputStreamgetResourceAsStream(java.lang.String name)
Fetch a resource relative to the HTMLEditorKit classfile. If this is called on 1.2 the loading will occur under the protection of a doPrivileged call to allow the HTMLEditorKit to function when used in an applet.

param
name the name of the resource, relative to the HTMLEditorKit class
return
a stream representing the resource

	try {
            return ResourceLoader.getResourceAsStream(name);
	} catch (Throwable e) {
	    // If the class doesn't exist or we have some other 
	    // problem we just try to call getResourceAsStream directly.
	    return HTMLEditorKit.class.getResourceAsStream(name);
	}
    
public javax.swing.text.html.StyleSheetgetStyleSheet()
Get the set of styles currently being used to render the HTML elements. By default the resource specified by DEFAULT_CSS gets loaded, and is shared by all HTMLEditorKit instances.

	if (defaultStyles == null) {
	    defaultStyles = new StyleSheet();
	    try {
		InputStream is = HTMLEditorKit.getResourceAsStream(DEFAULT_CSS);
		Reader r = new BufferedReader(
		        new InputStreamReader(is, "ISO-8859-1"));
		defaultStyles.loadRules(r, null);
		r.close();
	    } catch (Throwable e) {
		// on error we simply have no styles... the html
		// will look mighty wrong but still function.
	    }
	}
	return defaultStyles;
    
public javax.swing.text.ViewFactorygetViewFactory()
Fetch a factory that is suitable for producing views of any models that are produced by this kit.

return
the factory

	return defaultFactory;
    
public voidinsertHTML(javax.swing.text.html.HTMLDocument doc, int offset, java.lang.String html, int popDepth, int pushDepth, javax.swing.text.html.HTML$Tag insertTag)
Inserts HTML into an existing document.

param
doc the document to insert into
param
offset the offset to insert HTML at
param
popDepth the number of ElementSpec.EndTagTypes to generate before inserting
param
pushDepth the number of ElementSpec.StartTagTypes with a direction of ElementSpec.JoinNextDirection that should be generated before inserting, but after the end tags have been generated
param
insertTag the first tag to start inserting into document
exception
RuntimeException (will eventually be a BadLocationException) if pos is invalid

	Parser p = getParser();
	if (p == null) {
	    throw new IOException("Can't load parser");
	}
	if (offset > doc.getLength()) {
	    throw new BadLocationException("Invalid location", offset);
	}

	ParserCallback receiver = doc.getReader(offset, popDepth, pushDepth,
						insertTag);
	Boolean ignoreCharset = (Boolean)doc.getProperty
	                        ("IgnoreCharsetDirective");
	p.parse(new StringReader(html), receiver, (ignoreCharset == null) ?
		false : ignoreCharset.booleanValue());
	receiver.flush();
    
public voidinstall(javax.swing.JEditorPane c)
Called when the kit is being installed into the a JEditorPane.

param
c the JEditorPane

	c.addMouseListener(linkHandler);
        c.addMouseMotionListener(linkHandler);
	c.addCaretListener(nextLinkAction);
	super.install(c);
        theEditor = c;
    
public booleanisAutoFormSubmission()
Indicates whether an html form submission is processed automatically or only FormSubmitEvent is fired.

return
true if html form submission is processed automatically, false otherwise.
see
#setAutoFormSubmission
since
1.5

        return isAutoFormSubmission;
    
public voidread(java.io.Reader in, javax.swing.text.Document doc, int pos)
Inserts content from the given stream. If doc is an instance of HTMLDocument, this will read HTML 3.2 text. Inserting HTML into a non-empty document must be inside the body Element, if you do not insert into the body an exception will be thrown. When inserting into a non-empty document all tags outside of the body (head, title) will be dropped.

param
in the stream to read from
param
doc the destination for the insertion
param
pos the location in the document to place the content
exception
IOException on any I/O error
exception
BadLocationException if pos represents an invalid location within the document
exception
RuntimeException (will eventually be a BadLocationException) if pos is invalid


	if (doc instanceof HTMLDocument) {
	    HTMLDocument hdoc = (HTMLDocument) doc;
	    Parser p = getParser();
	    if (p == null) {
		throw new IOException("Can't load parser");
	    }
	    if (pos > doc.getLength()) {
		throw new BadLocationException("Invalid location", pos);
	    }

	    ParserCallback receiver = hdoc.getReader(pos);
	    Boolean ignoreCharset = (Boolean)doc.getProperty("IgnoreCharsetDirective");
	    p.parse(in, receiver, (ignoreCharset == null) ? false : ignoreCharset.booleanValue());
	    receiver.flush();
	} else {
	    super.read(in, doc, pos);
	}
    
public voidsetAutoFormSubmission(boolean isAuto)
Specifies if an html form submission is processed automatically or only FormSubmitEvent is fired. By default it is set to true.

see
#isAutoFormSubmission
see
FormSubmitEvent
since
1.5

        isAutoFormSubmission = isAuto;
    
public voidsetDefaultCursor(java.awt.Cursor cursor)
Sets the default cursor.

since
1.3

	defaultCursor = cursor;
    
public voidsetLinkCursor(java.awt.Cursor cursor)
Sets the cursor to use over links.

since
1.3

	linkCursor = cursor;
    
public voidsetStyleSheet(javax.swing.text.html.StyleSheet s)
Set the set of styles to be used to render the various HTML elements. These styles are specified in terms of CSS specifications. Each document produced by the kit will have a copy of the sheet which it can add the document specific styles to. By default, the StyleSheet specified is shared by all HTMLEditorKit instances. This should be reimplemented to provide a finer granularity if desired.


                                                                                
        
	defaultStyles = s;
    
public voidwrite(java.io.Writer out, javax.swing.text.Document doc, int pos, int len)
Write content from a document to the given stream in a format appropriate for this kind of content handler.

param
out the stream to write to
param
doc the source for the write
param
pos the location in the document to fetch the content
param
len the amount to write out
exception
IOException on any I/O error
exception
BadLocationException if pos represents an invalid location within the document


	if (doc instanceof HTMLDocument) {
	    HTMLWriter w = new HTMLWriter(out, (HTMLDocument)doc, pos, len);
	    w.write();
	} else if (doc instanceof StyledDocument) {
	    MinimalHTMLWriter w = new MinimalHTMLWriter(out, (StyledDocument)doc, pos, len);
	    w.write();
	} else {
	    super.write(out, doc, pos, len);
	}