summaryrefslogtreecommitdiff
path: root/javax/swing/text/html/HTMLDocument.java
diff options
context:
space:
mode:
Diffstat (limited to 'javax/swing/text/html/HTMLDocument.java')
-rw-r--r--javax/swing/text/html/HTMLDocument.java301
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();
+ }
+ }
+
}