📄 htmldocument.java
字号:
} } } return null; } /** * Verifies the document has an <code>HTMLEditorKit.Parser</code> set. * If <code>getParser</code> returns <code>null</code>, this will throw an * IllegalStateException. * * @throws IllegalStateException if the document does not have a Parser */ private void verifyParser() { if (getParser() == null) { throw new IllegalStateException("No HTMLEditorKit.Parser"); } } /** * Installs a default Parser if one has not been installed yet. */ private void installParserIfNecessary() { if (getParser() == null) { setParser(new HTMLEditorKit().getParser()); } } /** * Inserts a string of HTML into the document at the given position. * <code>parent</code> is used to identify the location to insert the * <code>html</code>. If <code>parent</code> is a leaf this can have * unexpected results. */ private void insertHTML(Element parent, int offset, String html, boolean wantsTrailingNewline) throws BadLocationException, IOException { if (parent != null && html != null) { HTMLEditorKit.Parser parser = getParser(); if (parser != null) { int lastOffset = Math.max(0, offset - 1); Element charElement = getCharacterElement(lastOffset); Element commonParent = parent; int pop = 0; int push = 0; if (parent.getStartOffset() > lastOffset) { while (commonParent != null && commonParent.getStartOffset() > lastOffset) { commonParent = commonParent.getParentElement(); push++; } if (commonParent == null) { throw new BadLocationException("No common parent", offset); } } while (charElement != null && charElement != commonParent) { pop++; charElement = charElement.getParentElement(); } if (charElement != null) { // Found it, do the insert. HTMLReader reader = new HTMLReader(offset, pop - 1, push, null, false, true, wantsTrailingNewline); parser.parse(new StringReader(html), reader, true); reader.flush(); } } } } /** * Removes child Elements of the passed in Element <code>e</code>. This * will do the necessary cleanup to ensure the element representing the * end character is correctly created. * <p>This is not a general purpose method, it assumes that <code>e</code> * will still have at least one child after the remove, and it assumes * the character at <code>e.getStartOffset() - 1</code> is a newline and * is of length 1. */ private void removeElements(Element e, int index, int count) throws BadLocationException { writeLock(); try { int start = e.getElement(index).getStartOffset(); int end = e.getElement(index + count - 1).getEndOffset(); if (end > getLength()) { removeElementsAtEnd(e, index, count, start, end); } else { removeElements(e, index, count, start, end); } } finally { writeUnlock(); } } /** * Called to remove child elements of <code>e</code> when one of the * elements to remove is representing the end character. * <p>Since the Content will not allow a removal to the end character * this will do a remove from <code>start - 1</code> to <code>end</code>. * The end Element(s) will be removed, and the element representing * <code>start - 1</code> to <code>start</code> will be recreated. This * Element has to be recreated as after the content removal its offsets * become <code>start - 1</code> to <code>start - 1</code>. */ private void removeElementsAtEnd(Element e, int index, int count, int start, int end) throws BadLocationException { // index must be > 0 otherwise no insert would have happened. boolean isLeaf = (e.getElement(index - 1).isLeaf()); DefaultDocumentEvent dde = new DefaultDocumentEvent( start - 1, end - start + 1, DocumentEvent. EventType.REMOVE); if (isLeaf) { Element endE = getCharacterElement(getLength()); // e.getElement(index - 1) should represent the newline. index--; if (endE.getParentElement() != e) { // The hiearchies don't match, we'll have to manually // recreate the leaf at e.getElement(index - 1) replace(dde, e, index, ++count, start, end, true, true); } else { // The hierarchies for the end Element and // e.getElement(index - 1), match, we can safely remove // the Elements and the end content will be aligned // appropriately. replace(dde, e, index, count, start, end, true, false); } } else { // Not a leaf, descend until we find the leaf representing // start - 1 and remove it. Element newLineE = e.getElement(index - 1); while (!newLineE.isLeaf()) { newLineE = newLineE.getElement(newLineE.getElementCount() - 1); } newLineE = newLineE.getParentElement(); replace(dde, e, index, count, start, end, false, false); replace(dde, newLineE, newLineE.getElementCount() - 1, 1, start, end, true, true); } postRemoveUpdate(dde); dde.end(); fireRemoveUpdate(dde); fireUndoableEditUpdate(new UndoableEditEvent(this, dde)); } /** * This is used by <code>removeElementsAtEnd</code>, it removes * <code>count</code> elements starting at <code>start</code> from * <code>e</code>. If <code>remove</code> is true text of length * <code>start - 1</code> to <code>end - 1</code> is removed. If * <code>create</code> is true a new leaf is created of length 1. */ private void replace(DefaultDocumentEvent dde, Element e, int index, int count, int start, int end, boolean remove, boolean create) throws BadLocationException { Element[] added; AttributeSet attrs = e.getElement(index).getAttributes(); Element[] removed = new Element[count]; for (int counter = 0; counter < count; counter++) { removed[counter] = e.getElement(counter + index); } if (remove) { UndoableEdit u = getContent().remove(start - 1, end - start); if (u != null) { dde.addEdit(u); } } if (create) { added = new Element[1]; added[0] = createLeafElement(e, attrs, start - 1, start); } else { added = new Element[0]; } dde.addEdit(new ElementEdit(e, index, removed, added)); ((AbstractDocument.BranchElement)e).replace( index, removed.length, added); } /** * Called to remove child Elements when the end is not touched. */ private void removeElements(Element e, int index, int count, int start, int end) throws BadLocationException { Element[] removed = new Element[count]; Element[] added = new Element[0]; for (int counter = 0; counter < count; counter++) { removed[counter] = e.getElement(counter + index); } DefaultDocumentEvent dde = new DefaultDocumentEvent (start, end - start, DocumentEvent.EventType.REMOVE); ((AbstractDocument.BranchElement)e).replace(index, removed.length, added); dde.addEdit(new ElementEdit(e, index, removed, added)); UndoableEdit u = getContent().remove(start, end - start); if (u != null) { dde.addEdit(u); } postRemoveUpdate(dde); dde.end(); fireRemoveUpdate(dde); if (u != null) { fireUndoableEditUpdate(new UndoableEditEvent(this, dde)); } } // These two are provided for inner class access. The are named different // than the super class as the super class implementations are final. void obtainLock() { writeLock(); } void releaseLock() { writeUnlock(); } // // Provided for inner class access. // /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireChangedUpdate(DocumentEvent e) { super.fireChangedUpdate(e); } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireUndoableEditUpdate(UndoableEditEvent e) { super.fireUndoableEditUpdate(e); } boolean hasBaseTag() { return hasBaseTag; } String getBaseTarget() { return baseTarget; } /* * state defines whether the document is a frame document * or not. */ private boolean frameDocument = false; private boolean preservesUnknownTags = true; /* * Used to store button groups for radio buttons in * a form. */ private HashMap radioButtonGroupsMap; /** * Document property for the number of tokens to buffer * before building an element subtree to represent them. */ static final String TokenThreshold = "token threshold"; private static final int MaxThreshold = 10000; private static final int StepThreshold = 5; /** * Document property key value. The value for the key will be a Vector * of Strings that are comments not found in the body. */ public static final String AdditionalComments = "AdditionalComments"; /** * Document property key value. The value for the key will be a * String indicating the default type of stylesheet links. */ /* public */ static final String StyleType = "StyleType"; /** * 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. */ URL base; /** * does the document have base tag */ boolean hasBaseTag = false; /** * BASE tag's TARGET attribute value */ private String baseTarget = null; /** * The parser that is used when inserting html into the existing * document. */ private HTMLEditorKit.Parser parser; /** * Used for inserts when a null AttributeSet is supplied. */ private static AttributeSet contentAttributeSet; /** * Property Maps are registered under, will be a Hashtable. */ static String MAP_PROPERTY = "__MAP__"; private static char[] NEWLINE; /** * I18N property key. * * @see AbstractDocument.I18NProperty */ private static final String I18NProperty = "i18n"; static { contentAttributeSet = new SimpleAttributeSet(); ((MutableAttributeSet)contentAttributeSet). addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT); NEWLINE = new char[1]; NEWLINE[0] = '\n'; } /** * An iterator to iterate over a particular type of * tag. The iterator is not thread safe. If reliable * access to the document is not already ensured by * the context under which the iterator is being used, * its use should be performed under the protection of * Document.render. */ public static abstract class Iterator { /** * Return the attributes for this tag.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -