HTMLEditorKit.java revision 2896
2362N/A * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 0N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 0N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 0N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 0N/A * or visit www.oracle.com if you need additional information or have any 0N/A * The Swing JEditorPane text component supports different kinds 0N/A * of content via a plug-in mechanism called an EditorKit. Because 0N/A * HTML is a very popular format of content, some support is provided 0N/A * by default. The default support is provided by this class, which 0N/A * supports HTML version 3.2 (with some extensions), and is migrating 0N/A * toward version 4.0. 0N/A * The <applet> tag is not supported, but some support is provided 0N/A * for the <object> tag. 0N/A * There are several goals of the HTML EditorKit provided, that have 0N/A * an effect upon the way that HTML is modeled. These 0N/A * have influenced its design in a substantial way. 0N/A * 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 <code>HTMLDocument</code>. * Its documention describes the details of how the HTML is modeled. * The editing support leverages heavily off of the text package. * To maximize the usefulness of this kit, a great deal of effort * has gone into making it extendable. These are some of the * 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 * 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. * 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 <code>HTMLFactory</code> class. This can * be easily changed by subclassing or replacing the HTMLFactory * and reimplementing the getViewFactory method to return the alternative * 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 * 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 <code>JEditorPane.setPage</code>. * This is controlled by a property on the document. The method * <a href="#createDefaultDocument">createDefaultDocument</a> can * be overriden to change this. The batching of work is done * work is done by the <code>DefaultStyledDocument</code> and * <code>AbstractDocument</code> 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 <code>StyleSheet</code> * class. The presentation of the HTML can be heavily influenced * by the setting of the StyleSheet property on the EditorKit. * 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 * @author Timothy Prinzing * Constructs an HTMLEditorKit, creates a StyleContext, * and loads the style sheet. * Get the MIME type of the data that this * kit represents support for. This kit supports * Fetch a factory that is suitable for producing * views of any models that are produced by this * Create an uninitialized text storage model * that is appropriate for this type of editor. * Try to get an HTML parser from the document. If no parser is set for * the document, return the editor kit's default parser. It is an error * if no parser could be obtained from the editor kit. * Inserts content from the given stream. If <code>doc</code> 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 * @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) * 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 * @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) (
"IgnoreCharsetDirective");
* 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 * @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 * Called when the kit is being installed into the * @param c the JEditorPane * Called when the kit is being removed from the * JEditorPane. This is used to unregister any * listeners that were attached. * @param c the JEditorPane * Default Cascading Style Sheet file that sets * 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 * 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 // on error we simply have no styles... the html // will look mighty wrong but still function. * 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 * @return a stream representing the resource // If the class doesn't exist or we have some other // problem we just try to call getResourceAsStream directly. * 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 * Copies the key/values in <code>element</code>s AttributeSet into * <code>set</code>. 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 <code>set</code>.<p> * This is called anytime the caret moves over a different location. // PENDING: we need a better way to express what shouldn't be // copied when editing... // Remove the related image attributes, src, width, height // Don't copy HRs or BRs either. // Don't copy COMMENTs either // Don't copy unknowns either:( * Gets the input attributes used for the styled * @return the attribute set * Sets the default cursor. * Returns the default cursor. * Sets the cursor to use over links. * Returns the cursor to use over hyper links. * Indicates whether an html form submission is processed automatically * or only <code>FormSubmitEvent</code> is fired. * @return true if html form submission is processed automatically, * @see #setAutoFormSubmission * Specifies if an html form submission is processed * automatically or only <code>FormSubmitEvent</code> is fired. * By default it is set to true. * @see #isAutoFormSubmission * Creates a copy of the editor kit. * 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 // ----- Accessibility support ----- * returns the AccessibleContext associated with this editor kit * @return the AccessibleContext associated with this editor kit // --- variables ------------------------------------------ /** Shared factory for creating HTML Views. */ * Class to watch the associated component and fire * hyperlink events on it when appropriate. * If true, the current element (curElem) represents an image. /** This is used by viewToModel to avoid allocing a new array each * Called for a mouse click event. * If the component is read-only (ie a browser) then * the clicked event is used to drive an attempt to * follow the reference specified by a link. * @param e the mouse event * @see MouseListener#mouseClicked // track the moving of the mouse. // reference changed, fire event(s) * Returns a string anchor if the passed in element has a * USEMAP that contains the passed in location. * Returns true if the View representing <code>e</code> contains * the location <code>x</code>, <code>y</code>. <code>offset</code> * gives the offset into the Document to check for. * Calls linkActivated on the associated JEditorPane * if the given position represents a link.<p>This is implemented * to forward to the method with the same name, but with the following * @param pos the position * @param editor the editor pane * Calls linkActivated on the associated JEditorPane * if the given position represents a link. If this was the result * of a mouse click, <code>x</code> and * <code>y</code> will give the location of the mouse, otherwise * @param pos the position * @param html the editor pane * Creates and returns a new instance of HyperlinkEvent. If * <code>hdoc</code> is a frame document a HTMLFrameHyperlinkEvent // Following is a workaround for 1.2, in which // new URL("file://...", "#...") causes the filename to // fire an exited event on the old link // fire an entered event on the new link * Interface to be supported by the parser. This enables * providing a different parser while reusing some of the * implementation provided by this editor kit. public static abstract class Parser {
* Parse the given stream and drive the given callback * with the results of the parse. This method should * be implemented to be thread-safe. * The result of parsing drives these callback methods. * The open and close actions should be balanced. The * <code>flush</code> method will be the last method * called, to give the receiver a chance to flush any * pending data into the document. * <p>Refer to DocumentParser, the default parser used, for further * information on the contents of the AttributeSets, the positions, and * This is passed as an attribute in the attributeset to indicate * the element is implied eg, the string '<>foo<\t>' * contains an implied html element and an implied body element. * This is invoked after the stream has been parsed, but before * <code>flush</code>. <code>eol</code> will be one of \n, \r * or \r\n, which ever is encountered the most in parsing the * A factory to build views for HTML. The following * table describes what this factory will build by * <table summary="Describes the tag and view created by this factory by default"> * <th align=left>Tag<th align=left>View created * <td>HTML.Tag.CONTENT<td>InlineView * <td>HTML.Tag.MENU<td>ListView * <td>HTML.Tag.DIR<td>ListView * <td>HTML.Tag.UL<td>ListView * <td>HTML.Tag.OL<td>ListView * <td>HTML.Tag.LI<td>BlockView * <td>HTML.Tag.DL<td>BlockView * <td>HTML.Tag.DD<td>BlockView * <td>HTML.Tag.BODY<td>BlockView * <td>HTML.Tag.CENTER<td>BlockView * <td>HTML.Tag.DIV<td>BlockView * <td>HTML.Tag.BLOCKQUOTE<td>BlockView * <td>HTML.Tag.PRE<td>BlockView * <td>HTML.Tag.BLOCKQUOTE<td>BlockView * <td>HTML.Tag.PRE<td>BlockView * <td>HTML.Tag.IMG<td>ImageView * <td>HTML.Tag.HR<td>HRuleView * <td>HTML.Tag.BR<td>BRView * <td>HTML.Tag.INPUT<td>FormView * <td>HTML.Tag.SELECT<td>FormView * <td>HTML.Tag.TEXTAREA<td>FormView * <td>HTML.Tag.OBJECT<td>ObjectView * <td>HTML.Tag.FRAMESET<td>FrameSetView * <td>HTML.Tag.FRAME<td>FrameView * Creates a view from an element. * @param elem the element "no ROWS or COLS defined.");
// Make the head never visible, and never load its // children. For Cursor positioning, // getNextVisualPositionFrom is overriden to always return // the end offset of the element. // If we get here, it's either an element we don't know about // or something from StyledDocument that doesn't have a mapping to HTML. // default to text display // reimplement major axis requirements to indicate that the // block is flexible for the body element... so that it can // be stretched to fill the background properly. //try to use viewVisibleWidth if it is smaller than targetSpan //if parent == null unregister component listener * we keep weak reference to viewPort if and only if BodyBoxView is listening for ComponentEvents * only in that case cachedViewPort is not equal to null. * we need to keep this reference in order to remove BodyBoxView from viewPort listeners. // --- Action implementations ------------------------------ /** The bold action identifier /** The italic action identifier /** The paragraph left indent action identifier /** The paragraph right indent action identifier /** The font size increase to next value action identifier /** The font size decrease to next value action identifier /** The Color choice action identifier The color is passed as an argument /** The logical style choice action identifier The logical style is passed in as an argument * Align images at the top. * Align images in the middle. * Align images at the bottom. * Align images at the border. /** HTML used when inserting tables. */ /** HTML used when inserting unordered lists. */ /** HTML used when inserting ordered lists. */ /** HTML used when inserting hr. */ /** HTML used when inserting pre. */ // link navigation support * An abstract Action providing some convenience methods that may * be useful in inserting HTML into an existing document. * <p>NOTE: None of the convenience methods obtain a lock on the * document. If you have another thread modifying the text these * methods may have inconsistent behavior, or return the wrong thing. * @return HTMLDocument of <code>e</code>. * @return HTMLEditorKit for <code>e</code>. * Returns an array of the Elements that contain <code>offset</code>. * The first elements corresponds to the root. * Recursive method used by getElementsAt. * Returns number of elements, starting at the deepest leaf, needed * to get to an element representing <code>tag</code>. This will * return -1 if no elements is found representing <code>tag</code>, * or 0 if the parent of the leaf at <code>offset</code> represents * Returns the deepest element at <code>offset</code> matching * InsertHTMLTextAction can be used to insert an arbitrary string of HTML * into an existing HTML document. At least two HTML.Tags need to be * supplied. The first Tag, parentTag, identifies the parent in * the document to add the elements to. The second tag, addTag, * identifies the first tag that should be added to the document as * seen in the HTML string. One important thing to remember, is that * the parser is going to generate all the appropriate tags, even if * they aren't in the HTML string passed in.<p> * For example, lets say you wanted to create an action to insert * a table into the body. The parentTag would be HTML.Tag.BODY, * addTag would be HTML.Tag.TABLE, and the string could be something * like <table><tr><td></td></tr></table>. * <p>There is also an option to supply an alternate parentTag and * addTag. These will be checked for if there is no parentTag at * A cover for HTMLEditorKit.insertHTML. If an exception it * thrown it is wrapped in a RuntimeException and thrown. * This is invoked when inserting at a boundary. It determines * the number of pops, and then the number of pushes that need * to be performed, and then invokes insertHTML. * This is invoked when inserting at a boundary. It determines * the number of pops, and then the number of pushes that need * to be performed, and then invokes insertHTML. * @deprecated As of Java 2 platform v1.3, use insertAtBoundary // Find the common parent. // If inserting at the origin, the common parent is the // Determine how many pops to do. * If there is an Element with name <code>tag</code> at * <code>offset</code>, this will invoke either insertAtBoundary * or <code>insertHTML</code>. This returns true if there is * a match, and one of the inserts is invoked. * Called after an insertion to adjust the selection. * Inserts the HTML into the document. /** Tag to check for in the document. */ /** Tag in HTML to start adding tags from. */ /** Alternate Tag to check for in the document if parentTag is /** Alternate tag in HTML to start adding tags from if parentTag * is not found and alternateParentTag is found. */ /** True indicates the selection should be adjusted after an insert. */ * InsertHRAction is special, at actionPerformed time it will determine * the parent HTML.Tag based on the paragraph element at the selection * Inserts the HTML into the document. * Returns the object in an AttributeSet matching a key * Action to move the focus on the next or previous hypertext link * or object. TODO: This method relies on support from the * javax.accessibility package. The text package should support * keyboard navigation of text elements directly. * Create this action with the appropriate identifier. * Called when the caret position is updated. * @param e the caret event // TODO: The AccessibleContext for the editor should register // as a listener for CaretEvents and forward the events to // assistive technologies listening for such events. * The operation to perform when this action is triggered. // TODO: Should start successive iterations from the // current caret position. // highlight the next link or object after the current caret position }
else {
// focus forward * Moves the caret from mark to dot * A highlight painter that draws a one-pixel border around * Paints a portion of a highlight. * @param g the graphics context * @param offs0 the starting model offset >= 0 * @param offs1 the ending model offset >= offs1 * @param bounds the bounding box of the view, which is not * necessarily the region to paint. * @param view View painting for * @return region in which drawing occurred // Contained in view, can just use bounds. // Should only render part of View. // --- determine locations --- * Action to activate the hypertext link that has focus. * TODO: This method relies on support from the * javax.accessibility package. The text package should support * keyboard navigation of text elements directly. * Create this action with the appropriate identifier. * activates the hyperlink at offset * Invokes default action on the object in an element * Returns the root view for a document * Returns a view associated with an element * If possible acquires a lock on the Document. If a lock has been * obtained a key will be retured that should be passed to * Releases a lock previously obtained via <code>lock</code>. * The operation to perform when this action is triggered. // invoke the next link or object action * Move the caret to the beginning of the document. * @see DefaultEditorKit#beginAction * @see HTMLEditorKit#getActions /* Create this object with the appropriate identifier. */ /** The operation to perform when this action is triggered. */