diff options
Diffstat (limited to 'javax/swing/text/html/HTMLDocument.java')
-rw-r--r-- | javax/swing/text/html/HTMLDocument.java | 301 |
1 files changed, 256 insertions, 45 deletions
diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java index ee59d7025..25b44615e 100644 --- a/javax/swing/text/html/HTMLDocument.java +++ b/javax/swing/text/html/HTMLDocument.java @@ -52,6 +52,8 @@ import java.util.Vector; import javax.swing.DefaultButtonModel; import javax.swing.JEditorPane; import javax.swing.JToggleButton; +import javax.swing.event.DocumentEvent; +import javax.swing.event.UndoableEditEvent; import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; @@ -89,7 +91,17 @@ public class HTMLDocument extends DefaultStyledDocument boolean preservesUnknownTags = true; int tokenThreshold = Integer.MAX_VALUE; HTMLEditorKit.Parser parser; - + + /** + * Indicates whether this document is inside a frame or not. + */ + private boolean frameDocument; + + /** + * Package private to avoid accessor methods. + */ + String baseTarget; + /** * Constructs an HTML document using the default buffer size and a default * StyleSheet. @@ -365,11 +377,119 @@ public class HTMLDocument extends DefaultStyledDocument } public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event) - throws NotImplementedException { - // TODO: Implement this properly. + String target = event.getTarget(); + Element el = event.getSourceElement(); + URL url = event.getURL(); + if (target.equals("_self")) + { + updateFrame(el, url); + } + else if (target.equals("_parent")) + { + updateFrameSet(el.getParentElement(), url); + } + else + { + Element targetFrame = findFrame(target); + if (targetFrame != null) + updateFrame(targetFrame, url); + } } - + + /** + * Finds the named frame inside this document. + * + * @param target the name to look for + * + * @return the frame if there is a matching frame, <code>null</code> + * otherwise + */ + private Element findFrame(String target) + { + ElementIterator i = new ElementIterator(this); + Element next = null; + while ((next = i.next()) != null) + { + AttributeSet atts = next.getAttributes(); + if (atts.getAttribute(StyleConstants.NameAttribute) == HTML.Tag.FRAME) + { + String name = (String) atts.getAttribute(HTML.Attribute.NAME); + if (name != null && name.equals(target)) + break; + } + } + return next; + } + + /** + * Updates the frame that is represented by the specified element to + * refer to the specified URL. + * + * @param el the element + * @param url the new url + */ + private void updateFrame(Element el, URL url) + { + try + { + writeLock(); + DefaultDocumentEvent ev = + new DefaultDocumentEvent(el.getStartOffset(), 1, + DocumentEvent.EventType.CHANGE); + AttributeSet elAtts = el.getAttributes(); + AttributeSet copy = elAtts.copyAttributes(); + MutableAttributeSet matts = (MutableAttributeSet) elAtts; + ev.addEdit(new AttributeUndoableEdit(el, copy, false)); + matts.removeAttribute(HTML.Attribute.SRC); + matts.addAttribute(HTML.Attribute.SRC, url.toString()); + ev.end(); + fireChangedUpdate(ev); + fireUndoableEditUpdate(new UndoableEditEvent(this, ev)); + } + finally + { + writeUnlock(); + } + } + + /** + * Updates the frameset that is represented by the specified element + * to create a frame that refers to the specified URL. + * + * @param el the element + * @param url the url + */ + private void updateFrameSet(Element el, URL url) + { + int start = el.getStartOffset(); + int end = el.getEndOffset(); + + StringBuilder html = new StringBuilder(); + html.append("<frame"); + if (url != null) + { + html.append(" src=\""); + html.append(url.toString()); + html.append("\""); + } + html.append('>'); + if (getParser() == null) + setParser(new HTMLEditorKit().getParser()); + try + { + setOuterHTML(el, html.toString()); + } + catch (BadLocationException ex) + { + ex.printStackTrace(); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } + /** * Gets an iterator for the given HTML.Tag. * @param t the requested HTML.Tag @@ -529,8 +649,13 @@ public class HTMLDocument extends DefaultStyledDocument */ protected MutableAttributeSet charAttr = new SimpleAttributeSet(); - protected Vector<ElementSpec> parseBuffer = new Vector<ElementSpec>(); - + protected Vector<ElementSpec> parseBuffer = new Vector<ElementSpec>(); + + /** + * The parse stack. It holds the current element tree path. + */ + private Stack<HTML.Tag> parseStack = new Stack<HTML.Tag>(); + /** * A stack for character attribute sets * */ @@ -577,16 +702,6 @@ public class HTMLDocument extends DefaultStyledDocument boolean inPreTag = false; /** - * True when we are inside a paragraph (P, H1-H6, P-IMPLIED). - */ - boolean inParagraph = false; - - /** - * True when we are currently inside an implied paragraph. - */ - boolean inImpliedParagraph = false; - - /** * This is true when we are inside a style tag. This will add text * content inside this style tag beeing parsed as CSS. * @@ -676,6 +791,10 @@ public class HTMLDocument extends DefaultStyledDocument // Put the old attribute set on the stack. pushCharacterStyle(); + // Initialize with link pseudo class. + if (t == HTML.Tag.A) + a.addAttribute(HTML.Attribute.PSEUDO_CLASS, "link"); + // Just add the attributes in <code>a</code>. charAttr.addAttribute(t, a.copyAttributes()); } @@ -828,7 +947,6 @@ public class HTMLDocument extends DefaultStyledDocument public void start(HTML.Tag t, MutableAttributeSet a) { super.start(t, a); - inParagraph = true; } /** @@ -838,7 +956,6 @@ public class HTMLDocument extends DefaultStyledDocument public void end(HTML.Tag t) { super.end(t); - inParagraph = false; } } @@ -954,20 +1071,9 @@ public class HTMLDocument extends DefaultStyledDocument * of tags associated with this Action. */ public void start(HTML.Tag t, MutableAttributeSet a) - throws NotImplementedException { - // FIXME: Implement. + baseTarget = (String) a.getAttribute(HTML.Attribute.TARGET); } - - /** - * Called when an end tag is seen for one of the types of tags associated - * with this Action. - */ - public void end(HTML.Tag t) - throws NotImplementedException - { - // FIXME: Implement. - } } class HeadAction extends BlockAction @@ -1529,9 +1635,12 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void blockOpen(HTML.Tag t, MutableAttributeSet attr) { - if (inImpliedParagraph) + if (inImpliedParagraph()) blockClose(HTML.Tag.IMPLIED); + // Push the new tag on top of the stack. + parseStack.push(t); + DefaultStyledDocument.ElementSpec element; AbstractDocument.AttributeContext ctx = getAttributeContext(); @@ -1543,6 +1652,34 @@ public class HTMLDocument extends DefaultStyledDocument } /** + * Returns true when we are currently inside a paragraph, either + * a real one or an implied, false otherwise. + * + * @return + */ + private boolean inParagraph() + { + boolean inParagraph = false; + if (! parseStack.isEmpty()) + { + HTML.Tag top = parseStack.peek(); + inParagraph = top == HTML.Tag.P || top == HTML.Tag.IMPLIED; + } + return inParagraph; + } + + private boolean inImpliedParagraph() + { + boolean inParagraph = false; + if (! parseStack.isEmpty()) + { + HTML.Tag top = parseStack.peek(); + inParagraph = top == HTML.Tag.IMPLIED; + } + return inParagraph; + } + + /** * Instructs the parse buffer to close the block element associated with * the given HTML.Tag * @@ -1552,13 +1689,12 @@ public class HTMLDocument extends DefaultStyledDocument { DefaultStyledDocument.ElementSpec element; - if (inImpliedParagraph) - { - inImpliedParagraph = false; - inParagraph = false; - if (t != HTML.Tag.IMPLIED) - blockClose(HTML.Tag.IMPLIED); - } + if (inImpliedParagraph() && t != HTML.Tag.IMPLIED) + blockClose(HTML.Tag.IMPLIED); + + // Pull the token from the stack. + if (! parseStack.isEmpty()) // Just to be sure. + parseStack.pop(); // If the previous tag is a start tag then we insert a synthetic // content tag. @@ -1602,11 +1738,9 @@ public class HTMLDocument extends DefaultStyledDocument protected void addContent(char[] data, int offs, int length, boolean generateImpliedPIfNecessary) { - if (generateImpliedPIfNecessary && (! inParagraph) && (! inPreTag)) + if (generateImpliedPIfNecessary && ! inParagraph()) { blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet()); - inParagraph = true; - inImpliedParagraph = true; } AbstractDocument.AttributeContext ctx = getAttributeContext(); @@ -1651,11 +1785,9 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a) { - if (t != HTML.Tag.FRAME && ! inParagraph && ! inImpliedParagraph) + if (t != HTML.Tag.FRAME && ! inParagraph()) { blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet()); - inParagraph = true; - inImpliedParagraph = true; } a.addAttribute(StyleConstants.NameAttribute, t); @@ -1666,7 +1798,7 @@ public class HTMLDocument extends DefaultStyledDocument DefaultStyledDocument.ElementSpec spec = new DefaultStyledDocument.ElementSpec(a.copyAttributes(), DefaultStyledDocument.ElementSpec.ContentType, - new char[] {' ', ' '}, 0, 2 ); + new char[] {' '}, 0, 1 ); parseBuffer.add(spec); } @@ -1955,4 +2087,83 @@ public void setOuterHTML(Element elem, String htmlText) } super.insertUpdate(evt, att); } + + /** + * Returns <code>true</code> when this document is inside a frame, + * <code>false</code> otherwise. + * + * @return <code>true</code> when this document is inside a frame, + * <code>false</code> otherwise + */ + boolean isFrameDocument() + { + return frameDocument; + } + + /** + * Set <code>true</code> when this document is inside a frame, + * <code>false</code> otherwise. + * + * @param frameDoc <code>true</code> when this document is inside a frame, + * <code>false</code> otherwise + */ + void setFrameDocument(boolean frameDoc) + { + frameDocument = frameDoc; + } + + /** + * Returns the target that is specified in the base tag, if this is the case. + * + * @return the target that is specified in the base tag, if this is the case + */ + String getBaseTarget() + { + return baseTarget; + } + + /** + * Updates the A tag's pseudo class value in response to a hyperlink + * action. + * + * @param el the corresponding element + * @param value the new value + */ + void updateSpecialClass(Element el, HTML.Attribute cl, String value) + { + try + { + writeLock(); + DefaultDocumentEvent ev = + new DefaultDocumentEvent(el.getStartOffset(), 1, + DocumentEvent.EventType.CHANGE); + AttributeSet elAtts = el.getAttributes(); + AttributeSet anchorAtts = (AttributeSet) elAtts.getAttribute(HTML.Tag.A); + if (anchorAtts != null) + { + AttributeSet copy = elAtts.copyAttributes(); + StyleSheet ss = getStyleSheet(); + if (value != null) + { + anchorAtts = ss.addAttribute(anchorAtts, cl, value); + } + else + { + anchorAtts = ss.removeAttribute(anchorAtts, cl); + } + MutableAttributeSet matts = (MutableAttributeSet) elAtts; + ev.addEdit(new AttributeUndoableEdit(el, copy, false)); + matts.removeAttribute(HTML.Tag.A); + matts.addAttribute(HTML.Tag.A, anchorAtts); + ev.end(); + fireChangedUpdate(ev); + fireUndoableEditUpdate(new UndoableEditEvent(this, ev)); + } + } + finally + { + writeUnlock(); + } + } + } |