diff options
Diffstat (limited to 'libjava/classpath/javax/swing/text/html/HTMLDocument.java')
-rw-r--r-- | libjava/classpath/javax/swing/text/html/HTMLDocument.java | 370 |
1 files changed, 224 insertions, 146 deletions
diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java index e714a857b61..0bfc338df45 100644 --- a/libjava/classpath/javax/swing/text/html/HTMLDocument.java +++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java @@ -40,14 +40,18 @@ package javax.swing.text.html; import gnu.classpath.NotImplementedException; import gnu.javax.swing.text.html.CharacterAttributeTranslator; +import gnu.javax.swing.text.html.parser.htmlAttributeSet; import java.io.IOException; +import java.io.StringReader; import java.net.URL; import java.util.HashMap; import java.util.Stack; import java.util.Vector; import javax.swing.JEditorPane; +import javax.swing.event.DocumentEvent; +import javax.swing.event.HyperlinkEvent.EventType; import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; @@ -515,19 +519,23 @@ public class HTMLDocument extends DefaultStyledDocument */ public class HTMLReader extends HTMLEditorKit.ParserCallback { - /** Holds the current character attribute set **/ + /** + * Holds the current character attribute set * + */ protected MutableAttributeSet charAttr = new SimpleAttributeSet(); protected Vector parseBuffer = new Vector(); - /** A stack for character attribute sets **/ + /** + * A stack for character attribute sets * + */ Stack charAttrStack = new Stack(); /** * The parse stack. This stack holds HTML.Tag objects that reflect the * current position in the parsing process. */ - private Stack parseStack = new Stack(); + Stack parseStack = new Stack(); /** A mapping between HTML.Tag objects and the actions that handle them **/ HashMap tagToAction; @@ -535,10 +543,31 @@ public class HTMLDocument extends DefaultStyledDocument /** Tells us whether we've received the '</html>' tag yet **/ boolean endHTMLEncountered = false; - /** Variables related to the constructor with explicit insertTag **/ - int popDepth, pushDepth, offset; + /** + * Related to the constructor with explicit insertTag + */ + int popDepth; + + /** + * Related to the constructor with explicit insertTag + */ + int pushDepth; + + /** + * Related to the constructor with explicit insertTag + */ + int offset; + + /** + * The tag (inclusve), after that the insertion should start. + */ HTML.Tag insertTag; - boolean insertTagEncountered = false; + + /** + * This variable becomes true after the insert tag has been encountered. + */ + boolean insertTagEncountered; + /** A temporary variable that helps with the printing out of debug information **/ boolean debug = false; @@ -1139,8 +1168,21 @@ public class HTMLDocument extends DefaultStyledDocument } /** - * This method is called by the parser and should route the call to - * the proper handler for the tag. + * Checks if the HTML tag should be inserted. The tags before insert tag (if + * specified) are not inserted. Also, the tags after the end of the html are + * not inserted. + * + * @return true if the tag should be inserted, false otherwise. + */ + private boolean shouldInsert() + { + return ! endHTMLEncountered + && (insertTagEncountered || insertTag == null); + } + + /** + * This method is called by the parser and should route the call to the + * proper handler for the tag. * * @param t the HTML.Tag * @param a the attribute set @@ -1148,13 +1190,15 @@ public class HTMLDocument extends DefaultStyledDocument */ public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) { - // Don't call the Action if we've already seen </html>. - if (endHTMLEncountered) - return; - - TagAction action = (TagAction) tagToAction.get(t); - if (action != null) - action.start(t, a); + if (t == insertTag) + insertTagEncountered = true; + + if (shouldInsert()) + { + TagAction action = (TagAction) tagToAction.get(t); + if (action != null) + action.start(t, a); + } } /** @@ -1165,42 +1209,41 @@ public class HTMLDocument extends DefaultStyledDocument */ public void handleComment(char[] data, int pos) { - // Don't call the Action if we've already seen </html>. - if (endHTMLEncountered) - return; - - TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT); - if (action != null) + if (shouldInsert()) { - action.start(HTML.Tag.COMMENT, new SimpleAttributeSet()); - action.end (HTML.Tag.COMMENT); + TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT); + if (action != null) + { + action.start(HTML.Tag.COMMENT, + htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET); + action.end(HTML.Tag.COMMENT); + } } } /** - * This method is called by the parser and should route the call to - * the proper handler for the tag. + * This method is called by the parser and should route the call to the + * proper handler for the tag. * * @param t the HTML.Tag * @param pos the position at which the tag was encountered */ public void handleEndTag(HTML.Tag t, int pos) { - // Don't call the Action if we've already seen </html>. - if (endHTMLEncountered) - return; - - // If this is the </html> tag we need to stop calling the Actions - if (t == HTML.Tag.HTML) - endHTMLEncountered = true; - - TagAction action = (TagAction) tagToAction.get(t); - if (action != null) - action.end(t); + if (shouldInsert()) + { + // If this is the </html> tag we need to stop calling the Actions + if (t == HTML.Tag.HTML) + endHTMLEncountered = true; + + TagAction action = (TagAction) tagToAction.get(t); + if (action != null) + action.end(t); + } } /** - * This is a callback from the parser that should be routed to the + * This is a callback from the parser that should be routed to the * appropriate handler for the tag. * * @param t the HTML.Tag that was encountered @@ -1209,15 +1252,17 @@ public class HTMLDocument extends DefaultStyledDocument */ public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) { - // Don't call the Action if we've already seen </html>. - if (endHTMLEncountered) - return; - - TagAction action = (TagAction) tagToAction.get (t); - if (action != null) + if (t == insertTag) + insertTagEncountered = true; + + if (shouldInsert()) { - action.start(t, a); - action.end(t); + TagAction action = (TagAction) tagToAction.get(t); + if (action != null) + { + action.start(t, a); + action.end(t); + } } } @@ -1230,7 +1275,6 @@ public class HTMLDocument extends DefaultStyledDocument * @since 1.3 */ public void handleEndOfLineString(String eol) - throws NotImplementedException { // FIXME: Implement. print ("HTMLReader.handleEndOfLineString not implemented yet"); @@ -1273,16 +1317,6 @@ public class HTMLDocument extends DefaultStyledDocument printBuffer(); DefaultStyledDocument.ElementSpec element; - // If the previous tag is content and the parent is p-implied, then - // we must also close the p-implied. - if (parseStack.size() > 0 && parseStack.peek() == HTML.Tag.IMPLIED) - { - element = new DefaultStyledDocument.ElementSpec(null, - DefaultStyledDocument.ElementSpec.EndTagType); - parseBuffer.addElement(element); - parseStack.pop(); - } - parseStack.push(t); AbstractDocument.AttributeContext ctx = getAttributeContext(); AttributeSet copy = attr.copyAttributes(); @@ -1320,16 +1354,6 @@ public class HTMLDocument extends DefaultStyledDocument new char[0], 0, 0); parseBuffer.add(element); } - // If the previous tag is content and the parent is p-implied, then - // we must also close the p-implied. - else if (parseStack.peek() == HTML.Tag.IMPLIED) - { - element = new DefaultStyledDocument.ElementSpec(null, - DefaultStyledDocument.ElementSpec.EndTagType); - parseBuffer.addElement(element); - if (parseStack.size() > 0) - parseStack.pop(); - } element = new DefaultStyledDocument.ElementSpec(null, DefaultStyledDocument.ElementSpec.EndTagType); @@ -1369,27 +1393,6 @@ public class HTMLDocument extends DefaultStyledDocument DefaultStyledDocument.ElementSpec element; AttributeSet attributes = null; - // Content must always be embedded inside a paragraph element, - // so we create this if the previous element is not one of - // <p>, <h1> .. <h6>. - boolean createImpliedParagraph = false; - HTML.Tag parent = (HTML.Tag) parseStack.peek(); - if (parent != HTML.Tag.P && parent != HTML.Tag.H1 - && parent != HTML.Tag.H2 - && parent != HTML.Tag.H3 && parent != HTML.Tag.H4 - && parent != HTML.Tag.H5 && parent != HTML.Tag.H6 - && parent != HTML.Tag.TD) - { - attributes = ctx.getEmptySet(); - attributes = ctx.addAttribute(attributes, - StyleConstants.NameAttribute, - HTML.Tag.IMPLIED); - element = new DefaultStyledDocument.ElementSpec(attributes, - DefaultStyledDocument.ElementSpec.StartTagType); - parseBuffer.add(element); - parseStack.push(HTML.Tag.IMPLIED); - } - // Copy the attribute set, don't use the same object because // it may change if (charAttr != null) @@ -1433,14 +1436,14 @@ public class HTMLDocument extends DefaultStyledDocument // Migrate from the rather htmlAttributeSet to the faster, lighter and // unchangeable alternative implementation. AttributeSet copy = a.copyAttributes(); - - // TODO: Figure out why we must always insert this single character - // (otherwise the element does not appear). Either fix or add explaining - // comment or at least report a normal bug. - DefaultStyledDocument.ElementSpec spec; - spec = new DefaultStyledDocument.ElementSpec(copy, - DefaultStyledDocument.ElementSpec.ContentType, - new char[] {' '}, 0, 1 ); + + // The two spaces are required because some special elements like HR + // must be broken. At least two characters are needed to break into the + // two parts. + DefaultStyledDocument.ElementSpec spec = + new DefaultStyledDocument.ElementSpec(copy, + DefaultStyledDocument.ElementSpec.ContentType, + new char[] {' ', ' '}, 0, 2 ); parseBuffer.add(spec); } @@ -1481,7 +1484,61 @@ public class HTMLDocument extends DefaultStyledDocument HTML.Tag insertTag) { return new HTMLReader(pos, popDepth, pushDepth, insertTag); - } + } + + /** + * Gets the reader for the parser to use when inserting the HTML fragment into + * the document. Checks if the parser is present, sets the parent in the + * element stack and removes any actions for BODY (it can be only one body in + * a HTMLDocument). + * + * @param pos - the starting position + * @param popDepth - the number of EndTagTypes to generate before inserting + * @param pushDepth - the number of StartTagTypes with a direction of + * 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 + * @param parent the element that will be the parent in the document. HTML + * parsing includes checks for the parent, so it must be available. + * @return - the reader + * @throws IllegalStateException if the parsert is not set. + */ + public HTMLEditorKit.ParserCallback getInsertingReader(int pos, int popDepth, + int pushDepth, + HTML.Tag insertTag, + final Element parent) + throws IllegalStateException + { + if (parser == null) + throw new IllegalStateException("Parser has not been set"); + + HTMLReader reader = new HTMLReader(pos, popDepth, pushDepth, insertTag) + { + /** + * Ignore BODY. + */ + public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) + { + if (t != HTML.Tag.BODY) + super.handleStartTag(t, a, pos); + } + + /** + * Ignore BODY. + */ + public void handleEndTag(HTML.Tag t, int pos) + { + if (t != HTML.Tag.BODY) + super.handleEndTag(t, pos); + } + }; + + // Set the parent HTML tag. + reader.parseStack.push(parent.getAttributes().getAttribute( + StyleConstants.NameAttribute)); + + return reader; + } /** * Gets the child element that contains the attribute with the value or null. @@ -1490,8 +1547,8 @@ public class HTMLDocument extends DefaultStyledDocument * @param e - the element to begin search at * @param attribute - the desired attribute * @param value - the desired value - * @return the element found with the attribute and value specified or null - * if it is not found. + * @return the element found with the attribute and value specified or null if + * it is not found. */ public Element getElement(Element e, Object attribute, Object value) { @@ -1516,16 +1573,17 @@ public class HTMLDocument extends DefaultStyledDocument } /** - * Returns the element that has the given id Attribute. If it is not found, - * null is returned. This method works on an Attribute, not a character tag. - * This is not thread-safe. + * Returns the element that has the given id Attribute (for instance, <p id + * ='my paragraph >'). If it is not found, null is returned. The HTML tag, + * having this attribute, is not checked by this method and can be any. The + * method is not thread-safe. * - * @param attrId - the Attribute id to look for + * @param attrId - the value of the attribute id to look for * @return the element that has the given id. */ public Element getElement(String attrId) { - return getElement(getDefaultRootElement(), HTML.getAttributeKey(attrId), + return getElement(getDefaultRootElement(), HTML.Attribute.ID, attrId); } @@ -1542,22 +1600,30 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set */ public void setInnerHTML(Element elem, String htmlText) - throws BadLocationException, IOException, NotImplementedException + throws BadLocationException, IOException { if (elem.isLeaf()) throw new IllegalArgumentException("Element is a leaf"); - if (parser == null) - throw new IllegalStateException("Parser has not been set"); - // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? - System.out.println("setInnerHTML not implemented"); + + int start = elem.getStartOffset(); + int end = elem.getEndOffset(); + + HTMLEditorKit.ParserCallback reader = getInsertingReader( + end, 0, 0, HTML.Tag.BODY, elem); + + // TODO charset + getParser().parse(new StringReader(htmlText), reader, true); + + // Remove the previous content + remove(start, end - start); } /** - * Replaces the given element in the parent with the string. When replacing - * a leaf, this will attempt to make sure there is a newline present if one is - * needed. This may result in an additional element being inserted. - * This will be seen as at least two events, n inserts followed by a remove. - * The HTMLEditorKit.Parser must be set. + * Replaces the given element in the parent with the string. When replacing a + * leaf, this will attempt to make sure there is a newline present if one is + * needed. This may result in an additional element being inserted. This will + * be seen as at least two events, n inserts followed by a remove. The + * HTMLEditorKit.Parser must be set. * * @param elem - the branch element whose parent will be replaced * @param htmlText - the string to be parsed and assigned to elem @@ -1565,18 +1631,25 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IOException * @throws IllegalStateException - if parser is not set */ - public void setOuterHTML(Element elem, String htmlText) - throws BadLocationException, IOException, NotImplementedException - { - if (parser == null) - throw new IllegalStateException("Parser has not been set"); - // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? - System.out.println("setOuterHTML not implemented"); - } +public void setOuterHTML(Element elem, String htmlText) + throws BadLocationException, IOException + { + // Remove the current element: + int start = elem.getStartOffset(); + int end = elem.getEndOffset(); + + remove(start, end-start); + + HTMLEditorKit.ParserCallback reader = getInsertingReader( + start, 0, 0, HTML.Tag.BODY, elem); + + // TODO charset + getParser().parse(new StringReader(htmlText), reader, true); + } /** - * Inserts the string before the start of the given element. - * The parser must be set. + * Inserts the string before the start of the given element. The parser must + * be set. * * @param elem - the element to be the root for the new text. * @param htmlText - the string to be parsed and assigned to elem @@ -1585,18 +1658,19 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if parser has not been set */ public void insertBeforeStart(Element elem, String htmlText) - throws BadLocationException, IOException, NotImplementedException + throws BadLocationException, IOException { - if (parser == null) - throw new IllegalStateException("Parser has not been set"); - // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? - System.out.println("insertBeforeStart not implemented"); + HTMLEditorKit.ParserCallback reader = getInsertingReader( + elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem); + + // TODO charset + getParser().parse(new StringReader(htmlText), reader, true); } /** - * Inserts the string at the end of the element. If elem's children - * are leaves, and the character at elem.getEndOffset() - 1 is a newline, - * then it will be inserted before the newline. The parser must be set. + * Inserts the string at the end of the element. If elem's children are + * leaves, and the character at elem.getEndOffset() - 1 is a newline, then it + * will be inserted before the newline. The parser must be set. * * @param elem - the element to be the root for the new text * @param htmlText - the text to insert @@ -1605,12 +1679,14 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if parser is not set */ public void insertBeforeEnd(Element elem, String htmlText) - throws BadLocationException, IOException, NotImplementedException + throws BadLocationException, IOException { - if (parser == null) - throw new IllegalStateException("Parser has not been set"); - // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? - System.out.println("insertBeforeEnd not implemented"); + HTMLEditorKit.ParserCallback reader = getInsertingReader( + elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem); + + // TODO charset + getParser().parse(new StringReader(htmlText), reader, true); + } /** @@ -1624,12 +1700,13 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if parser is not set */ public void insertAfterEnd(Element elem, String htmlText) - throws BadLocationException, IOException, NotImplementedException + throws BadLocationException, IOException { - if (parser == null) - throw new IllegalStateException("Parser has not been set"); - // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? - System.out.println("insertAfterEnd not implemented"); + HTMLEditorKit.ParserCallback reader = getInsertingReader( + elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem); + + // TODO charset + getParser().parse(new StringReader(htmlText), reader, true); } /** @@ -1643,11 +1720,12 @@ public class HTMLDocument extends DefaultStyledDocument * @throws IllegalStateException - if parser is not set */ public void insertAfterStart(Element elem, String htmlText) - throws BadLocationException, IOException, NotImplementedException + throws BadLocationException, IOException { - if (parser == null) - throw new IllegalStateException("Parser has not been set"); - // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? - System.out.println("insertAfterStart not implemented"); + HTMLEditorKit.ParserCallback reader = getInsertingReader( + elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem); + + // TODO charset + getParser().parse(new StringReader(htmlText), reader, true); } } |