summaryrefslogtreecommitdiffstats
path: root/libjava/classpath/javax/swing/text/html/HTMLDocument.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/text/html/HTMLDocument.java')
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLDocument.java931
1 files changed, 749 insertions, 182 deletions
diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
index 0bfc338df45..f3d3ce3faaf 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLDocument.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
@@ -39,19 +39,22 @@ exception statement from your version. */
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.MalformedURLException;
import java.net.URL;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
import java.util.Vector;
+import javax.swing.ButtonGroup;
+import javax.swing.DefaultButtonModel;
import javax.swing.JEditorPane;
+import javax.swing.ListSelectionModel;
import javax.swing.event.DocumentEvent;
-import javax.swing.event.HyperlinkEvent.EventType;
+import javax.swing.event.UndoableEditEvent;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
@@ -60,6 +63,7 @@ import javax.swing.text.Element;
import javax.swing.text.ElementIterator;
import javax.swing.text.GapContent;
import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.PlainDocument;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTML.Tag;
@@ -87,16 +91,24 @@ public class HTMLDocument extends DefaultStyledDocument
boolean preservesUnknownTags = true;
int tokenThreshold = Integer.MAX_VALUE;
HTMLEditorKit.Parser parser;
- StyleSheet styleSheet;
- AbstractDocument.Content content;
-
+
+ /**
+ * 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.
*/
public HTMLDocument()
{
- this(null);
+ this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleSheet());
}
/**
@@ -119,14 +131,7 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public HTMLDocument(AbstractDocument.Content c, StyleSheet styles)
{
- this.content = c;
- if (styles == null)
- {
- styles = new StyleSheet();
- styles.importStyleSheet(getClass().getResource(HTMLEditorKit.
- DEFAULT_CSS));
- }
- this.styleSheet = styles;
+ super(c, styles);
}
/**
@@ -137,7 +142,7 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public StyleSheet getStyleSheet()
{
- return styleSheet;
+ return (StyleSheet) getAttributeContext();
}
/**
@@ -191,8 +196,6 @@ public class HTMLDocument extends DefaultStyledDocument
protected Element createLeafElement(Element parent, AttributeSet a, int p0,
int p1)
{
- RunElement el = new RunElement(parent, a, p0, p1);
- el.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT);
return new RunElement(parent, a, p0, p1);
}
@@ -269,7 +272,7 @@ public class HTMLDocument extends DefaultStyledDocument
public void setBase(URL u)
{
baseURL = u;
- styleSheet.setBase(u);
+ getStyleSheet().setBase(u);
}
/**
@@ -374,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
@@ -461,6 +572,8 @@ public class HTMLDocument extends DefaultStyledDocument
String name = null;
if (tag != null)
name = tag.toString();
+ if (name == null)
+ name = super.getName();
return name;
}
}
@@ -497,6 +610,8 @@ public class HTMLDocument extends DefaultStyledDocument
String name = null;
if (tag != null)
name = tag.toString();
+ if (name == null)
+ name = super.getName();
return name;
}
@@ -518,24 +633,33 @@ public class HTMLDocument extends DefaultStyledDocument
* @author Anthony Balkissoon abalkiss at redhat dot com
*/
public class HTMLReader extends HTMLEditorKit.ParserCallback
- {
+ {
+ /**
+ * The maximum token threshold. We don't grow it larger than this.
+ */
+ private static final int MAX_THRESHOLD = 10000;
+
+ /**
+ * The threshold growth factor.
+ */
+ private static final int GROW_THRESHOLD = 5;
+
/**
* Holds the current character attribute set *
*/
protected MutableAttributeSet charAttr = new SimpleAttributeSet();
- protected Vector parseBuffer = new Vector();
-
+ 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 *
*/
Stack charAttrStack = new Stack();
-
- /**
- * The parse stack. This stack holds HTML.Tag objects that reflect the
- * current position in the parsing process.
- */
- Stack parseStack = new Stack();
/** A mapping between HTML.Tag objects and the actions that handle them **/
HashMap tagToAction;
@@ -571,13 +695,68 @@ public class HTMLDocument extends DefaultStyledDocument
/** A temporary variable that helps with the printing out of debug information **/
boolean debug = false;
-
- void print (String line)
- {
- if (debug)
- System.out.println (line);
- }
-
+
+ /**
+ * This is true when we are inside a pre tag.
+ */
+ boolean inPreTag = false;
+
+ /**
+ * This is true when we are inside a style tag. This will add text
+ * content inside this style tag beeing parsed as CSS.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ boolean inStyleTag = false;
+
+ /**
+ * This is true when we are inside a &lt;textarea&gt; tag. Any text
+ * content will then be added to the text area.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ boolean inTextArea = false;
+
+ /**
+ * This contains all stylesheets that are somehow read, either
+ * via embedded style tags, or via linked stylesheets. The
+ * elements will be String objects containing a stylesheet each.
+ */
+ ArrayList styles;
+
+ /**
+ * The document model for a textarea.
+ *
+ * This is package private to avoid accessor methods.
+ */
+ ResetablePlainDocument textAreaDocument;
+
+ /**
+ * The current model of a select tag. Can be a ComboBoxModel or a
+ * ListModel depending on the type of the select box.
+ */
+ Object selectModel;
+
+ /**
+ * The current option beeing read.
+ */
+ Option option;
+
+ /**
+ * The current number of options in the current select model.
+ */
+ int numOptions;
+
+ /**
+ * The current button groups mappings.
+ */
+ HashMap buttonGroups;
+
+ /**
+ * The token threshold. This gets increased while loading.
+ */
+ private int threshold;
+
public class TagAction
{
/**
@@ -633,13 +812,12 @@ public class HTMLDocument extends DefaultStyledDocument
// Put the old attribute set on the stack.
pushCharacterStyle();
- // Translate tag.. return if succesful.
- if(CharacterAttributeTranslator.translateTag(charAttr, t, a))
- return;
+ // 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>.
- if (a != null)
- charAttr.addAttribute(t, a.copyAttributes());
+ charAttr.addAttribute(t, a.copyAttributes());
}
/**
@@ -651,7 +829,11 @@ public class HTMLDocument extends DefaultStyledDocument
popCharacterStyle();
}
}
-
+
+ /**
+ * Processes elements that make up forms: &lt;input&gt;, &lt;textarea&gt;,
+ * &lt;select&gt; and &lt;option&gt;.
+ */
public class FormAction extends SpecialAction
{
/**
@@ -659,10 +841,73 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("FormAction.start not implemented");
+ if (t == HTML.Tag.INPUT)
+ {
+ String type = (String) a.getAttribute(HTML.Attribute.TYPE);
+ if (type == null)
+ {
+ type = "text"; // Default to 'text' when nothing was specified.
+ a.addAttribute(HTML.Attribute.TYPE, type);
+ }
+ setModel(type, a);
+ }
+ else if (t == HTML.Tag.TEXTAREA)
+ {
+ inTextArea = true;
+ textAreaDocument = new ResetablePlainDocument();
+ a.addAttribute(StyleConstants.ModelAttribute, textAreaDocument);
+ }
+ else if (t == HTML.Tag.SELECT)
+ {
+ int size = HTML.getIntegerAttributeValue(a, HTML.Attribute.SIZE,
+ 1);
+ boolean multi = a.getAttribute(HTML.Attribute.MULTIPLE) != null;
+ if (size > 1 || multi)
+ {
+ SelectListModel m = new SelectListModel();
+ if (multi)
+ m.getSelectionModel().setSelectionMode(ListSelectionModel
+ .MULTIPLE_INTERVAL_SELECTION);
+ selectModel = m;
+ }
+ else
+ {
+ selectModel = new SelectComboBoxModel();
+ }
+ a.addAttribute(StyleConstants.ModelAttribute, selectModel);
+ }
+ if (t == HTML.Tag.OPTION)
+ {
+ option = new Option(a);
+ if (selectModel instanceof SelectListModel)
+ {
+ SelectListModel m = (SelectListModel) selectModel;
+ m.addElement(option);
+ if (option.isSelected())
+ {
+ m.getSelectionModel().addSelectionInterval(numOptions,
+ numOptions);
+ m.addInitialSelection(numOptions);
+ }
+ }
+ else if (selectModel instanceof SelectComboBoxModel)
+ {
+ SelectComboBoxModel m = (SelectComboBoxModel) selectModel;
+ m.addElement(option);
+ if (option.isSelected())
+ {
+ m.setSelectedItem(option);
+ m.setInitialSelection(option);
+ }
+ }
+ numOptions++;
+ }
+ else
+ {
+ // Build the element.
+ super.start(t, a);
+ }
}
/**
@@ -670,13 +915,106 @@ public class HTMLDocument extends DefaultStyledDocument
* with this Action.
*/
public void end(HTML.Tag t)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("FormAction.end not implemented");
+ if (t == HTML.Tag.OPTION)
+ {
+ option = null;
+ }
+ else
+ {
+ if (t == HTML.Tag.TEXTAREA)
+ {
+ inTextArea = false;
+ }
+ else if (t == HTML.Tag.SELECT)
+ {
+ selectModel = null;
+ numOptions = 0;
+ }
+ // Finish the element.
+ super.end(t);
+ }
+ }
+
+ private void setModel(String type, MutableAttributeSet attrs)
+ {
+ if (type.equals("submit") || type.equals("reset")
+ || type.equals("image"))
+ {
+ // Create button.
+ attrs.addAttribute(StyleConstants.ModelAttribute,
+ new DefaultButtonModel());
+ }
+ else if (type.equals("text") || type.equals("password"))
+ {
+ String text = (String) attrs.getAttribute(HTML.Attribute.VALUE);
+ ResetablePlainDocument doc = new ResetablePlainDocument();
+ if (text != null)
+ {
+ doc.setInitialText(text);
+ try
+ {
+ doc.insertString(0, text, null);
+ }
+ catch (BadLocationException ex)
+ {
+ // Shouldn't happen.
+ assert false;
+ }
+ }
+ attrs.addAttribute(StyleConstants.ModelAttribute, doc);
+ }
+ else if (type.equals("file"))
+ {
+ attrs.addAttribute(StyleConstants.ModelAttribute,
+ new PlainDocument());
+ }
+ else if (type.equals("checkbox") || type.equals("radio"))
+ {
+ ResetableToggleButtonModel model =
+ new ResetableToggleButtonModel();
+ if (attrs.getAttribute(HTML.Attribute.SELECTED) != null)
+ {
+ model.setSelected(true);
+ model.setInitial(true);
+ }
+ if (type.equals("radio"))
+ {
+ String name = (String) attrs.getAttribute(HTML.Attribute.NAME);
+ if (name != null)
+ {
+ if (buttonGroups == null)
+ buttonGroups = new HashMap();
+ ButtonGroup group = (ButtonGroup) buttonGroups.get(name);
+ if (group == null)
+ {
+ group = new ButtonGroup();
+ buttonGroups.put(name, group);
+ }
+ model.setGroup(group);
+ }
+ }
+ attrs.addAttribute(StyleConstants.ModelAttribute, model);
+ }
+ }
+ }
+
+ /**
+ * Called for form tags.
+ */
+ class FormTagAction
+ extends BlockAction
+ {
+ /**
+ * Clears the button group mapping.
+ */
+ public void end(HTML.Tag t)
+ {
+ super.end(t);
+ buttonGroups = null;
}
}
-
+
/**
* This action indicates that the content between starting and closing HTML
* elements (like script - /script) should not be visible. The content is
@@ -707,7 +1045,10 @@ public class HTMLDocument extends DefaultStyledDocument
blockClose(t);
}
}
-
+
+ /**
+ * Handles &lt;isindex&gt; tags.
+ */
public class IsindexAction extends TagAction
{
/**
@@ -715,10 +1056,10 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("IsindexAction.start not implemented");
+ blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
+ addSpecialElement(t, a);
+ blockClose(HTML.Tag.IMPLIED);
}
}
@@ -730,7 +1071,7 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void start(HTML.Tag t, MutableAttributeSet a)
{
- blockOpen(t, a);
+ super.start(t, a);
}
/**
@@ -739,10 +1080,13 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void end(HTML.Tag t)
{
- blockClose(t);
+ super.end(t);
}
}
-
+
+ /**
+ * This action is performed when a &lt;pre&gt; tag is parsed.
+ */
public class PreAction extends BlockAction
{
/**
@@ -750,11 +1094,11 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("PreAction.start not implemented");
- super.start(t, a);
+ inPreTag = true;
+ blockOpen(t, a);
+ a.addAttribute(CSS.Attribute.WHITE_SPACE, "pre");
+ blockOpen(HTML.Tag.IMPLIED, a);
}
/**
@@ -762,11 +1106,10 @@ public class HTMLDocument extends DefaultStyledDocument
* with this Action.
*/
public void end(HTML.Tag t)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("PreAction.end not implemented");
- super.end(t);
+ blockClose(HTML.Tag.IMPLIED);
+ inPreTag = false;
+ blockClose(t);
}
}
@@ -798,7 +1141,6 @@ public class HTMLDocument extends DefaultStyledDocument
throws NotImplementedException
{
// FIXME: Implement.
- print ("AreaAction.start not implemented");
}
/**
@@ -809,10 +1151,44 @@ public class HTMLDocument extends DefaultStyledDocument
throws NotImplementedException
{
// FIXME: Implement.
- print ("AreaAction.end not implemented");
}
}
-
+
+ /**
+ * Converts HTML tags to CSS attributes.
+ */
+ class ConvertAction
+ extends TagAction
+ {
+
+ public void start(HTML.Tag tag, MutableAttributeSet atts)
+ {
+ pushCharacterStyle();
+ charAttr.addAttribute(tag, atts.copyAttributes());
+ StyleSheet styleSheet = getStyleSheet();
+ // TODO: Add other tags here.
+ if (tag == HTML.Tag.FONT)
+ {
+ String color = (String) atts.getAttribute(HTML.Attribute.COLOR);
+ if (color != null)
+ styleSheet.addCSSAttribute(charAttr, CSS.Attribute.COLOR, color);
+ String face = (String) atts.getAttribute(HTML.Attribute.FACE);
+ if (face != null)
+ styleSheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_FAMILY,
+ face);
+ String size = (String) atts.getAttribute(HTML.Attribute.SIZE);
+ if (size != null)
+ styleSheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_SIZE,
+ size);
+ }
+ }
+
+ public void end(HTML.Tag tag)
+ {
+ popCharacterStyle();
+ }
+ }
+
class BaseAction extends TagAction
{
/**
@@ -820,22 +1196,9 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("BaseAction.start not implemented");
+ 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.
- print ("BaseAction.end not implemented");
- }
}
class HeadAction extends BlockAction
@@ -848,7 +1211,6 @@ public class HTMLDocument extends DefaultStyledDocument
throws NotImplementedException
{
// FIXME: Implement.
- print ("HeadAction.start not implemented: "+t);
super.start(t, a);
}
@@ -857,37 +1219,87 @@ public class HTMLDocument extends DefaultStyledDocument
* with this Action.
*/
public void end(HTML.Tag t)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("HeadAction.end not implemented: "+t);
+ // We read in all the stylesheets that are embedded or referenced
+ // inside the header.
+ if (styles != null)
+ {
+ int numStyles = styles.size();
+ for (int i = 0; i < numStyles; i++)
+ {
+ String style = (String) styles.get(i);
+ getStyleSheet().addRule(style);
+ }
+ }
super.end(t);
- }
+ }
}
- class LinkAction extends TagAction
+ class LinkAction extends HiddenAction
{
/**
* This method is called when a start tag is seen for one of the types
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("LinkAction.start not implemented");
+ super.start(t, a);
+ String type = (String) a.getAttribute(HTML.Attribute.TYPE);
+ if (type == null)
+ type = "text/css";
+ if (type.equals("text/css"))
+ {
+ String rel = (String) a.getAttribute(HTML.Attribute.REL);
+ String media = (String) a.getAttribute(HTML.Attribute.MEDIA);
+ String title = (String) a.getAttribute(HTML.Attribute.TITLE);
+ if (media == null)
+ media = "all";
+ else
+ media = media.toLowerCase();
+ if (rel != null)
+ {
+ rel = rel.toLowerCase();
+ if ((media.indexOf("all") != -1
+ || media.indexOf("screen") != -1)
+ && (rel.equals("stylesheet")))
+ {
+ String href = (String) a.getAttribute(HTML.Attribute.HREF);
+ URL url = null;
+ try
+ {
+ url = new URL(baseURL, href);
+ }
+ catch (MalformedURLException ex)
+ {
+ try
+ {
+ url = new URL(href);
+ }
+ catch (MalformedURLException ex2)
+ {
+ url = null;
+ }
+ }
+ if (url != null)
+ {
+ try
+ {
+ getStyleSheet().importStyleSheet(url);
+ }
+ catch (Exception ex)
+ {
+ // Don't let exceptions and runtime exceptions
+ // in CSS parsing disprupt the HTML parsing
+ // process. But inform the user/developer
+ // on the console about it.
+ ex.printStackTrace();
+ }
+ }
+ }
+ }
+ }
}
- /**
- * 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.
- print ("LinkAction.end not implemented");
- }
}
class MapAction extends TagAction
@@ -900,7 +1312,6 @@ public class HTMLDocument extends DefaultStyledDocument
throws NotImplementedException
{
// FIXME: Implement.
- print ("MapAction.start not implemented");
}
/**
@@ -911,7 +1322,6 @@ public class HTMLDocument extends DefaultStyledDocument
throws NotImplementedException
{
// FIXME: Implement.
- print ("MapAction.end not implemented");
}
}
@@ -925,7 +1335,6 @@ public class HTMLDocument extends DefaultStyledDocument
throws NotImplementedException
{
// FIXME: Implement.
- print ("MetaAction.start not implemented");
}
/**
@@ -936,10 +1345,9 @@ public class HTMLDocument extends DefaultStyledDocument
throws NotImplementedException
{
// FIXME: Implement.
- print ("MetaAction.end not implemented");
}
}
-
+
class StyleAction extends TagAction
{
/**
@@ -947,10 +1355,8 @@ public class HTMLDocument extends DefaultStyledDocument
* of tags associated with this Action.
*/
public void start(HTML.Tag t, MutableAttributeSet a)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("StyleAction.start not implemented");
+ inStyleTag = true;
}
/**
@@ -958,10 +1364,8 @@ public class HTMLDocument extends DefaultStyledDocument
* with this Action.
*/
public void end(HTML.Tag t)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("StyleAction.end not implemented");
+ inStyleTag = false;
}
}
@@ -975,7 +1379,6 @@ public class HTMLDocument extends DefaultStyledDocument
throws NotImplementedException
{
// FIXME: Implement.
- print ("TitleAction.start not implemented");
}
/**
@@ -986,7 +1389,6 @@ public class HTMLDocument extends DefaultStyledDocument
throws NotImplementedException
{
// FIXME: Implement.
- print ("TitleAction.end not implemented");
}
}
@@ -998,13 +1400,11 @@ public class HTMLDocument extends DefaultStyledDocument
public HTMLReader(int offset, int popDepth, int pushDepth,
HTML.Tag insertTag)
{
- print ("HTMLReader created with pop: "+popDepth
- + " push: "+pushDepth + " offset: "+offset
- + " tag: "+insertTag);
this.insertTag = insertTag;
this.offset = offset;
this.popDepth = popDepth;
this.pushDepth = pushDepth;
+ threshold = getTokenThreshold();
initTags();
}
@@ -1028,7 +1428,7 @@ public class HTMLDocument extends DefaultStyledDocument
StyleAction styleAction = new StyleAction();
TitleAction titleAction = new TitleAction();
-
+ ConvertAction convertAction = new ConvertAction();
tagToAction.put(HTML.Tag.A, characterAction);
tagToAction.put(HTML.Tag.ADDRESS, characterAction);
tagToAction.put(HTML.Tag.APPLET, hiddenAction);
@@ -1051,8 +1451,8 @@ public class HTMLDocument extends DefaultStyledDocument
tagToAction.put(HTML.Tag.DL, blockAction);
tagToAction.put(HTML.Tag.DT, paragraphAction);
tagToAction.put(HTML.Tag.EM, characterAction);
- tagToAction.put(HTML.Tag.FONT, characterAction);
- tagToAction.put(HTML.Tag.FORM, blockAction);
+ tagToAction.put(HTML.Tag.FONT, convertAction);
+ tagToAction.put(HTML.Tag.FORM, new FormTagAction());
tagToAction.put(HTML.Tag.FRAME, specialAction);
tagToAction.put(HTML.Tag.FRAMESET, blockAction);
tagToAction.put(HTML.Tag.H1, paragraphAction);
@@ -1142,18 +1542,28 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void flush() throws BadLocationException
{
- DefaultStyledDocument.ElementSpec[] elements;
- elements = new DefaultStyledDocument.ElementSpec[parseBuffer.size()];
- parseBuffer.copyInto(elements);
- parseBuffer.removeAllElements();
- if (offset == 0)
- create(elements);
- else
- insert(offset, elements);
+ flushImpl();
+ }
- offset += HTMLDocument.this.getLength() - offset;
+ /**
+ * Flushes the buffer and handle partial inserts.
+ *
+ */
+ private void flushImpl()
+ throws BadLocationException
+ {
+ int oldLen = getLength();
+ int size = parseBuffer.size();
+ ElementSpec[] elems = new ElementSpec[size];
+ parseBuffer.copyInto(elems);
+ if (oldLen == 0)
+ create(elems);
+ else
+ insert(offset, elems);
+ parseBuffer.removeAllElements();
+ offset += getLength() - oldLen;
}
-
+
/**
* This method is called by the parser to indicate a block of
* text was encountered. Should insert the text appropriately.
@@ -1163,8 +1573,24 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void handleText(char[] data, int pos)
{
- if (data != null && data.length > 0)
- addContent(data, 0, data.length);
+ if (shouldInsert() && data != null && data.length > 0)
+ {
+ if (inTextArea)
+ textAreaContent(data);
+ else if (inPreTag)
+ preContent(data);
+ else if (option != null)
+ option.setLabel(new String(data));
+ else if (inStyleTag)
+ {
+ if (styles == null)
+ styles = new ArrayList();
+ styles.add(new String(data));
+ }
+ else
+ addContent(data, 0, data.length);
+
+ }
}
/**
@@ -1214,8 +1640,7 @@ public class HTMLDocument extends DefaultStyledDocument
TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
if (action != null)
{
- action.start(HTML.Tag.COMMENT,
- htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET);
+ action.start(HTML.Tag.COMMENT, new SimpleAttributeSet());
action.end(HTML.Tag.COMMENT);
}
}
@@ -1277,7 +1702,6 @@ public class HTMLDocument extends DefaultStyledDocument
public void handleEndOfLineString(String eol)
{
// FIXME: Implement.
- print ("HTMLReader.handleEndOfLineString not implemented yet");
}
/**
@@ -1287,22 +1711,48 @@ public class HTMLDocument extends DefaultStyledDocument
* @param data the text to add to the textarea
*/
protected void textAreaContent(char[] data)
- throws NotImplementedException
{
- // FIXME: Implement.
- print ("HTMLReader.textAreaContent not implemented yet");
+ try
+ {
+ int offset = textAreaDocument.getLength();
+ String text = new String(data);
+ textAreaDocument.setInitialText(text);
+ textAreaDocument.insertString(offset, text, null);
+ }
+ catch (BadLocationException ex)
+ {
+ // Must not happen as we insert at a model location that we
+ // got from the document itself.
+ assert false;
+ }
}
/**
* Adds the given text that was encountered in a <PRE> element.
- *
+ * This adds synthesized lines to hold the text runs.
+ *
* @param data the text
*/
protected void preContent(char[] data)
- throws NotImplementedException
{
- // FIXME: Implement
- print ("HTMLReader.preContent not implemented yet");
+ int start = 0;
+ for (int i = 0; i < data.length; i++)
+ {
+ if (data[i] == '\n')
+ {
+ addContent(data, start, i - start + 1);
+ blockClose(HTML.Tag.IMPLIED);
+ MutableAttributeSet atts = new SimpleAttributeSet();
+ atts.addAttribute(CSS.Attribute.WHITE_SPACE, "pre");
+ blockOpen(HTML.Tag.IMPLIED, atts);
+ start = i + 1;
+ }
+ }
+ if (start < data.length)
+ {
+ // Add remaining last line.
+ addContent(data, start, data.length - start);
+ }
}
/**
@@ -1314,17 +1764,48 @@ public class HTMLDocument extends DefaultStyledDocument
*/
protected void blockOpen(HTML.Tag t, MutableAttributeSet attr)
{
- printBuffer();
- DefaultStyledDocument.ElementSpec element;
+ 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();
AttributeSet copy = attr.copyAttributes();
copy = ctx.addAttribute(copy, StyleConstants.NameAttribute, t);
element = new DefaultStyledDocument.ElementSpec(copy,
DefaultStyledDocument.ElementSpec.StartTagType);
parseBuffer.addElement(element);
- printBuffer();
+ }
+
+ /**
+ * 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;
}
/**
@@ -1335,32 +1816,29 @@ public class HTMLDocument extends DefaultStyledDocument
*/
protected void blockClose(HTML.Tag t)
{
- printBuffer();
DefaultStyledDocument.ElementSpec element;
+ 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.
DefaultStyledDocument.ElementSpec prev;
- prev = (DefaultStyledDocument.ElementSpec)
- parseBuffer.get(parseBuffer.size() - 1);
- if (prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType)
+ prev = parseBuffer.size() > 0 ? (DefaultStyledDocument.ElementSpec)
+ parseBuffer.get(parseBuffer.size() - 1) : null;
+ if (prev != null &&
+ prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType)
{
- AbstractDocument.AttributeContext ctx = getAttributeContext();
- AttributeSet attributes = ctx.getEmptySet();
- attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute,
- HTML.Tag.CONTENT);
- element = new DefaultStyledDocument.ElementSpec(attributes,
- DefaultStyledDocument.ElementSpec.ContentType,
- new char[0], 0, 0);
- parseBuffer.add(element);
+ addContent(new char[]{' '}, 0, 1);
}
element = new DefaultStyledDocument.ElementSpec(null,
DefaultStyledDocument.ElementSpec.EndTagType);
parseBuffer.addElement(element);
- printBuffer();
- if (parseStack.size() > 0)
- parseStack.pop();
}
/**
@@ -1389,6 +1867,11 @@ public class HTMLDocument extends DefaultStyledDocument
protected void addContent(char[] data, int offs, int length,
boolean generateImpliedPIfNecessary)
{
+ if (generateImpliedPIfNecessary && ! inParagraph())
+ {
+ blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
+ }
+
AbstractDocument.AttributeContext ctx = getAttributeContext();
DefaultStyledDocument.ElementSpec element;
AttributeSet attributes = null;
@@ -1405,16 +1888,16 @@ public class HTMLDocument extends DefaultStyledDocument
DefaultStyledDocument.ElementSpec.ContentType,
data, offs, length);
- printBuffer();
// Add the element to the buffer
parseBuffer.addElement(element);
- printBuffer();
- if (parseBuffer.size() > HTMLDocument.this.getTokenThreshold())
+ if (parseBuffer.size() > threshold)
{
+ if (threshold <= MAX_THRESHOLD)
+ threshold *= GROW_THRESHOLD;
try
{
- flush();
+ flushImpl();
}
catch (BadLocationException ble)
{
@@ -1431,29 +1914,23 @@ public class HTMLDocument extends DefaultStyledDocument
*/
protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a)
{
+ if (t != HTML.Tag.FRAME && ! inParagraph())
+ {
+ blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
+ }
+
a.addAttribute(StyleConstants.NameAttribute, t);
- // Migrate from the rather htmlAttributeSet to the faster, lighter and
- // unchangeable alternative implementation.
- AttributeSet copy = a.copyAttributes();
-
// 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,
+ new DefaultStyledDocument.ElementSpec(a.copyAttributes(),
DefaultStyledDocument.ElementSpec.ContentType,
- new char[] {' ', ' '}, 0, 2 );
+ new char[] {' '}, 0, 1 );
parseBuffer.add(spec);
}
- void printBuffer()
- {
- print ("\n*********BUFFER**********");
- for (int i = 0; i < parseBuffer.size(); i ++)
- print (" "+parseBuffer.get(i));
- print ("***************************");
- }
}
/**
@@ -1533,10 +2010,6 @@ public class HTMLDocument extends DefaultStyledDocument
}
};
- // Set the parent HTML tag.
- reader.parseStack.push(parent.getAttributes().getAttribute(
- StyleConstants.NameAttribute));
-
return reader;
}
@@ -1728,4 +2201,98 @@ public void setOuterHTML(Element elem, String htmlText)
// TODO charset
getParser().parse(new StringReader(htmlText), reader, true);
}
+
+ /**
+ * Overridden to tag content with the synthetic HTML.Tag.CONTENT
+ * tag.
+ */
+ protected void insertUpdate(DefaultDocumentEvent evt, AttributeSet att)
+ {
+ if (att == null)
+ {
+ SimpleAttributeSet sas = new SimpleAttributeSet();
+ sas.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT);
+ att = sas;
+ }
+ 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();
+ }
+ }
+
}
OpenPOWER on IntegriCloud