📄 htmldocument.java
字号:
/* * @(#)HTMLDocument.java 1.181 08/03/05 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */package javax.swing.text.html;import java.awt.Color;import java.awt.Component;import java.awt.font.TextAttribute;import java.util.*;import java.net.URL;import java.net.URLEncoder;import java.net.MalformedURLException;import java.io.*;import javax.swing.*;import javax.swing.event.*;import javax.swing.text.*;import javax.swing.undo.*;import java.text.Bidi;import sun.swing.SwingUtilities2;import static sun.swing.SwingUtilities2.IMPLIED_CR;/** * A document that models HTML. The purpose of this model * is to support both browsing and editing. As a result, * the structure described by an HTML document is not * exactly replicated by default. The element structure that * is modeled by default, is built by the class * <code>HTMLDocument.HTMLReader</code>, which implements * the <code>HTMLEditorKit.ParserCallback</code> protocol * that the parser expects. To change the structure one * can subclass <code>HTMLReader</code>, and reimplement the method * {@link #getReader(int)} to return the new reader * implementation. The documentation for <code>HTMLReader</code> * should be consulted for the details of * the default structure created. The intent is that * the document be non-lossy (although reproducing the * HTML format may result in a different format). * <p> * The document models only HTML, and makes no attempt to * store view attributes in it. The elements are identified * by the <code>StyleContext.NameAttribute</code> attribute, * which should always have a value of type <code>HTML.Tag</code> * that identifies the kind of element. Some of the elements * (such as comments) are synthesized. The <code>HTMLFactory</code> * uses this attribute to determine what kind of view to build. * <p> * This document supports incremental loading. The * <code>TokenThreshold</code> property controls how * much of the parse is buffered before trying to update * the element structure of the document. This property * is set by the <code>EditorKit</code> so that subclasses can disable * it. * <p> * The <code>Base</code> property determines the URL * against which relative URLs are resolved. * By default, this will be the * <code>Document.StreamDescriptionProperty</code> if * the value of the property is a URL. If a <BASE> * tag is encountered, the base will become the URL specified * by that tag. Because the base URL is a property, it * can of course be set directly. * <p> * The default content storage mechanism for this document * is a gap buffer (<code>GapContent</code>). * Alternatives can be supplied by using the constructor * that takes a <code>Content</code> implementation. * <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}. * * @author Timothy Prinzing * @author Scott Violet * @author Sunita Mani * @version 1.181 03/05/08 */public class HTMLDocument extends DefaultStyledDocument { /** * Constructs an HTML document using the default buffer size * and a default <code>StyleSheet</code>. This is a convenience * method for the constructor * <code>HTMLDocument(Content, StyleSheet)</code>. */ public HTMLDocument() { this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleSheet()); } /** * Constructs an HTML document with the default content * storage implementation and the specified style/attribute * storage mechanism. This is a convenience method for the * constructor * <code>HTMLDocument(Content, StyleSheet)</code>. * * @param styles the styles */ public HTMLDocument(StyleSheet styles) { this(new GapContent(BUFFER_SIZE_DEFAULT), styles); } /** * Constructs an HTML document with the given content * storage implementation and the given style/attribute * storage mechanism. * * @param c the container for the content * @param styles the styles */ public HTMLDocument(Content c, StyleSheet styles) { super(c, styles); } /** * Fetches the reader for the parser to use when loading the document * with HTML. This is implemented to return an instance of * <code>HTMLDocument.HTMLReader</code>. * Subclasses can reimplement this * method to change how the document gets structured if desired. * (For example, to handle custom tags, or structurally represent character * style elements.) * * @param pos the starting position * @return the reader used by the parser to load the document */ public HTMLEditorKit.ParserCallback getReader(int pos) { Object desc = getProperty(Document.StreamDescriptionProperty); if (desc instanceof URL) { setBase((URL)desc); } HTMLReader reader = new HTMLReader(pos); return reader; } /** * Returns the reader for the parser to use to load the document * with HTML. This is implemented to return an instance of * <code>HTMLDocument.HTMLReader</code>. * Subclasses can reimplement this * method to change how the document gets structured if desired. * (For example, to handle custom tags, or structurally represent character * style elements.) * <p>This is a convenience method for * <code>getReader(int, int, int, HTML.Tag, TRUE)</code>. * * @param popDepth the number of <code>ElementSpec.EndTagTypes</code> * to generate before inserting * @param pushDepth the number of <code>ElementSpec.StartTagTypes</code> * with a direction of <code>ElementSpec.JoinNextDirection</code> * that should be generated before inserting, * but after the end tags have been generated * @param insertTag the first tag to start inserting into document * @return the reader used by the parser to load the document */ public HTMLEditorKit.ParserCallback getReader(int pos, int popDepth, int pushDepth, HTML.Tag insertTag) { return getReader(pos, popDepth, pushDepth, insertTag, true); } /** * Fetches the reader for the parser to use to load the document * with HTML. This is implemented to return an instance of * HTMLDocument.HTMLReader. Subclasses can reimplement this * method to change how the document get structured if desired * (e.g. to handle custom tags, structurally represent character * style elements, etc.). * * @param popDepth the number of <code>ElementSpec.EndTagTypes</code> * to generate before inserting * @param pushDepth the number of <code>ElementSpec.StartTagTypes</code> * with a direction of <code>ElementSpec.JoinNextDirection</code> * that should be generated before inserting, * but after the end tags have been generated * @param insertTag the first tag to start inserting into document * @param insertInsertTag false if all the Elements after insertTag should * be inserted; otherwise insertTag will be inserted * @return the reader used by the parser to load the document */ HTMLEditorKit.ParserCallback getReader(int pos, int popDepth, int pushDepth, HTML.Tag insertTag, boolean insertInsertTag) { Object desc = getProperty(Document.StreamDescriptionProperty); if (desc instanceof URL) { setBase((URL)desc); } HTMLReader reader = new HTMLReader(pos, popDepth, pushDepth, insertTag, insertInsertTag, false, true); return reader; } /** * Returns the location to resolve relative URLs against. By * default this will be the document's URL if the document * was loaded from a URL. If a base tag is found and * can be parsed, it will be used as the base location. * * @return the base location */ public URL getBase() { return base; } /** * Sets the location to resolve relative URLs against. By * default this will be the document's URL if the document * was loaded from a URL. If a base tag is found and * can be parsed, it will be used as the base location. * <p>This also sets the base of the <code>StyleSheet</code> * to be <code>u</code> as well as the base of the document. * * @param u the desired base URL */ public void setBase(URL u) { base = u; getStyleSheet().setBase(u); } /** * Inserts new elements in bulk. This is how elements get created * in the document. The parsing determines what structure is needed * and creates the specification as a set of tokens that describe the * edit while leaving the document free of a write-lock. This method * can then be called in bursts by the reader to acquire a write-lock * for a shorter duration (i.e. while the document is actually being * altered). * * @param offset the starting offset * @param data the element data * @exception BadLocationException if the given position does not * represent a valid location in the associated document. */ protected void insert(int offset, ElementSpec[] data) throws BadLocationException { super.insert(offset, data); } /** * Updates document structure as a result of text insertion. This * will happen within a write lock. This implementation simply * parses the inserted content for line breaks and builds up a set * of instructions for the element buffer. * * @param chng a description of the document change * @param attr the attributes */ protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) { if(attr == null) { attr = contentAttributeSet; } // If this is the composed text element, merge the content attribute to it else if (attr.isDefined(StyleConstants.ComposedTextAttribute)) { ((MutableAttributeSet)attr).addAttributes(contentAttributeSet); } if (attr.isDefined(IMPLIED_CR)) { ((MutableAttributeSet)attr).removeAttribute(IMPLIED_CR); } super.insertUpdate(chng, attr); } /** * Replaces the contents of the document with the given * element specifications. This is called before insert if * the loading is done in bursts. This is the only method called * if loading the document entirely in one burst. * * @param data the new contents of the document */ protected void create(ElementSpec[] data) { super.create(data); } /** * Sets attributes for a paragraph. * <p> * This method is thread safe, although most Swing methods * are not. Please see * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How * to Use Threads</A> for more information. * * @param offset the offset into the paragraph (must be at least 0) * @param length the number of characters affected (must be at least 0) * @param s the attributes * @param replace whether to replace existing attributes, or merge them */ public void setParagraphAttributes(int offset, int length, AttributeSet s, boolean replace) { try { writeLock(); // Make sure we send out a change for the length of the paragraph. int end = Math.min(offset + length, getLength()); Element e = getParagraphElement(offset); offset = e.getStartOffset(); e = getParagraphElement(end); length = Math.max(0, e.getEndOffset() - offset); DefaultDocumentEvent changes = new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.CHANGE); AttributeSet sCopy = s.copyAttributes(); int lastEnd = Integer.MAX_VALUE; for (int pos = offset; pos <= end; pos = lastEnd) { Element paragraph = getParagraphElement(pos); if (lastEnd == paragraph.getEndOffset()) { lastEnd++; } else { lastEnd = paragraph.getEndOffset(); } MutableAttributeSet attr = (MutableAttributeSet) paragraph.getAttributes(); changes.addEdit(new AttributeUndoableEdit(paragraph, sCopy, replace)); if (replace) { attr.removeAttributes(attr); } attr.addAttributes(s); } changes.end(); fireChangedUpdate(changes); fireUndoableEditUpdate(new UndoableEditEvent(this, changes)); } finally { writeUnlock(); } } /** * Fetches the <code>StyleSheet</code> with the document-specific display * rules (CSS) that were specified in the HTML document itself. * * @return the <code>StyleSheet</code> */ public StyleSheet getStyleSheet() { return (StyleSheet) getAttributeContext(); } /** * Fetches an iterator for the specified HTML tag. * This can be used for things like iterating over the * set of anchors contained, or iterating over the input * elements. * * @param t the requested <code>HTML.Tag</code> * @return the <code>Iterator</code> for the given HTML tag * @see javax.swing.text.html.HTML.Tag */ public Iterator getIterator(HTML.Tag t) { if (t.isBlock()) { // TBD return null; } return new LeafIterator(t, this); } /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -