mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			2299 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			2299 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			Java
		
	
	
	
/* HTMLDocument.java --
 | 
						|
   Copyright (C) 2005  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package javax.swing.text.html;
 | 
						|
 | 
						|
import gnu.classpath.NotImplementedException;
 | 
						|
 | 
						|
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.UndoableEditEvent;
 | 
						|
import javax.swing.text.AbstractDocument;
 | 
						|
import javax.swing.text.AttributeSet;
 | 
						|
import javax.swing.text.BadLocationException;
 | 
						|
import javax.swing.text.DefaultStyledDocument;
 | 
						|
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;
 | 
						|
 | 
						|
/**
 | 
						|
 * Represents the HTML document that is constructed by defining the text and
 | 
						|
 * other components (images, buttons, etc) in HTML language. This class can
 | 
						|
 * becomes the default document for {@link JEditorPane} after setting its
 | 
						|
 * content type to "text/html". HTML document also serves as an intermediate
 | 
						|
 * data structure when it is needed to parse HTML and then obtain the content of
 | 
						|
 * the certain types of tags. This class also has methods for modifying the HTML
 | 
						|
 * content.
 | 
						|
 *
 | 
						|
 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
 | 
						|
 * @author Anthony Balkissoon (abalkiss@redhat.com)
 | 
						|
 * @author Lillian Angel (langel@redhat.com)
 | 
						|
 */
 | 
						|
public class HTMLDocument extends DefaultStyledDocument
 | 
						|
{
 | 
						|
  /** A key for document properies.  The value for the key is
 | 
						|
   * a Vector of Strings of comments not found in the body.
 | 
						|
   */
 | 
						|
  public static final String AdditionalComments = "AdditionalComments";
 | 
						|
  URL baseURL = null;
 | 
						|
  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.
 | 
						|
   */
 | 
						|
  public HTMLDocument()
 | 
						|
  {
 | 
						|
    this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleSheet());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Constructs an HTML document with the default content storage
 | 
						|
   * implementation and the specified style/attribute storage mechanism.
 | 
						|
   *
 | 
						|
   * @param styles - the style sheet
 | 
						|
   */
 | 
						|
  public HTMLDocument(StyleSheet styles)
 | 
						|
  {
 | 
						|
   this(new GapContent(BUFFER_SIZE_DEFAULT), styles);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Constructs an HTML document with the given content storage implementation
 | 
						|
   * and the given style/attribute storage mechanism.
 | 
						|
   *
 | 
						|
   * @param c - the document's content
 | 
						|
   * @param styles - the style sheet
 | 
						|
   */
 | 
						|
  public HTMLDocument(AbstractDocument.Content c, StyleSheet styles)
 | 
						|
  {
 | 
						|
    super(c, styles);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the style sheet with the document display rules (CSS) that were specified
 | 
						|
   * in the HTML document.
 | 
						|
   *
 | 
						|
   * @return - the style sheet
 | 
						|
   */
 | 
						|
  public StyleSheet getStyleSheet()
 | 
						|
  {
 | 
						|
    return (StyleSheet) getAttributeContext();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method creates a root element for the new document.
 | 
						|
   *
 | 
						|
   * @return the new default root
 | 
						|
   */
 | 
						|
  protected AbstractElement createDefaultRoot()
 | 
						|
  {
 | 
						|
    AbstractDocument.AttributeContext ctx = getAttributeContext();
 | 
						|
 | 
						|
    // Create html element.
 | 
						|
    AttributeSet atts = ctx.getEmptySet();
 | 
						|
    atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.HTML);
 | 
						|
    BranchElement html = (BranchElement) createBranchElement(null, atts);
 | 
						|
 | 
						|
    // Create body element.
 | 
						|
    atts = ctx.getEmptySet();
 | 
						|
    atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.BODY);
 | 
						|
    BranchElement body = (BranchElement) createBranchElement(html, atts);
 | 
						|
    html.replace(0, 0, new Element[] { body });
 | 
						|
 | 
						|
    // Create p element.
 | 
						|
    atts = ctx.getEmptySet();
 | 
						|
    atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.P);
 | 
						|
    BranchElement p = (BranchElement) createBranchElement(body, atts);
 | 
						|
    body.replace(0, 0, new Element[] { p });
 | 
						|
 | 
						|
    // Create an empty leaf element.
 | 
						|
    atts = ctx.getEmptySet();
 | 
						|
    atts = ctx.addAttribute(atts, StyleConstants.NameAttribute,
 | 
						|
                            HTML.Tag.CONTENT);
 | 
						|
    Element leaf = createLeafElement(p, atts, 0, 1);
 | 
						|
    p.replace(0, 0, new Element[]{ leaf });
 | 
						|
 | 
						|
    return html;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method returns an HTMLDocument.RunElement object attached to
 | 
						|
   * parent representing a run of text from p0 to p1. The run has
 | 
						|
   * attributes described by a.
 | 
						|
   *
 | 
						|
   * @param parent - the parent element
 | 
						|
   * @param a - the attributes for the element
 | 
						|
   * @param p0 - the beginning of the range >= 0
 | 
						|
   * @param p1 - the end of the range >= p0
 | 
						|
   *
 | 
						|
   * @return the new element
 | 
						|
   */
 | 
						|
  protected Element createLeafElement(Element parent, AttributeSet a, int p0,
 | 
						|
                                      int p1)
 | 
						|
  {
 | 
						|
    return new RunElement(parent, a, p0, p1);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This method returns an HTMLDocument.BlockElement object representing the
 | 
						|
   * attribute set a and attached to parent.
 | 
						|
   *
 | 
						|
   * @param parent - the parent element
 | 
						|
   * @param a - the attributes for the element
 | 
						|
   *
 | 
						|
   * @return the new element
 | 
						|
   */
 | 
						|
  protected Element createBranchElement(Element parent, AttributeSet a)
 | 
						|
  {
 | 
						|
    return new BlockElement(parent, a);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the parser used by this HTMLDocument to insert HTML.
 | 
						|
   *
 | 
						|
   * @return the parser used by this HTMLDocument to insert HTML.
 | 
						|
   */
 | 
						|
  public HTMLEditorKit.Parser getParser()
 | 
						|
  {
 | 
						|
    return parser;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Sets the parser used by this HTMLDocument to insert HTML.
 | 
						|
   *
 | 
						|
   * @param p the parser to use
 | 
						|
   */
 | 
						|
  public void setParser (HTMLEditorKit.Parser p)
 | 
						|
  {
 | 
						|
    parser = p;
 | 
						|
  }
 | 
						|
  /**
 | 
						|
   * Sets the number of tokens to buffer before trying to display the
 | 
						|
   * Document.
 | 
						|
   *
 | 
						|
   * @param n the number of tokens to buffer
 | 
						|
   */
 | 
						|
  public void setTokenThreshold (int n)
 | 
						|
  {
 | 
						|
    tokenThreshold = n;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the number of tokens that are buffered before the document
 | 
						|
   * is rendered.
 | 
						|
   *
 | 
						|
   * @return the number of tokens buffered
 | 
						|
   */
 | 
						|
  public int getTokenThreshold ()
 | 
						|
  {
 | 
						|
    return tokenThreshold;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the location against which to resolve relative URLs.
 | 
						|
   * This is the document's URL if the document was loaded from a URL.
 | 
						|
   * If a <code>base</code> tag is found, it will be used.
 | 
						|
   * @return the base URL
 | 
						|
   */
 | 
						|
  public URL getBase()
 | 
						|
  {
 | 
						|
    return baseURL;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Sets the location against which to resolve relative URLs.
 | 
						|
   * @param u the new base URL
 | 
						|
   */
 | 
						|
  public void setBase(URL u)
 | 
						|
  {
 | 
						|
    baseURL = u;
 | 
						|
    getStyleSheet().setBase(u);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns whether or not the parser preserves unknown HTML tags.
 | 
						|
   * @return true if the parser preserves unknown tags
 | 
						|
   */
 | 
						|
  public boolean getPreservesUnknownTags()
 | 
						|
  {
 | 
						|
    return preservesUnknownTags;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Sets the behaviour of the parser when it encounters unknown HTML tags.
 | 
						|
   * @param preservesTags true if the parser should preserve unknown tags.
 | 
						|
   */
 | 
						|
  public void setPreservesUnknownTags(boolean preservesTags)
 | 
						|
  {
 | 
						|
    preservesUnknownTags = preservesTags;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * An iterator to iterate through LeafElements in the document.
 | 
						|
   */
 | 
						|
  class LeafIterator extends Iterator
 | 
						|
  {
 | 
						|
    HTML.Tag tag;
 | 
						|
    HTMLDocument doc;
 | 
						|
    ElementIterator it;
 | 
						|
 | 
						|
    public LeafIterator (HTML.Tag t, HTMLDocument d)
 | 
						|
    {
 | 
						|
      doc = d;
 | 
						|
      tag = t;
 | 
						|
      it = new ElementIterator(doc);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Return the attributes for the tag associated with this iteartor
 | 
						|
     * @return the AttributeSet
 | 
						|
     */
 | 
						|
    public AttributeSet getAttributes()
 | 
						|
    {
 | 
						|
      if (it.current() != null)
 | 
						|
        return it.current().getAttributes();
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the end of the range for the current occurrence of the tag
 | 
						|
     * being defined and having the same attributes.
 | 
						|
     * @return the end of the range
 | 
						|
     */
 | 
						|
    public int getEndOffset()
 | 
						|
    {
 | 
						|
      if (it.current() != null)
 | 
						|
        return it.current().getEndOffset();
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the start of the range for the current occurrence of the tag
 | 
						|
     * being defined and having the same attributes.
 | 
						|
     * @return the start of the range (-1 if it can't be found).
 | 
						|
     */
 | 
						|
 | 
						|
    public int getStartOffset()
 | 
						|
    {
 | 
						|
      if (it.current() != null)
 | 
						|
        return it.current().getStartOffset();
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Advance the iterator to the next LeafElement .
 | 
						|
     */
 | 
						|
    public void next()
 | 
						|
    {
 | 
						|
      it.next();
 | 
						|
      while (it.current()!= null && !it.current().isLeaf())
 | 
						|
        it.next();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Indicates whether or not the iterator currently represents an occurrence
 | 
						|
     * of the tag.
 | 
						|
     * @return true if the iterator currently represents an occurrence of the
 | 
						|
     * tag.
 | 
						|
     */
 | 
						|
    public boolean isValid()
 | 
						|
    {
 | 
						|
      return it.current() != null;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Type of tag for this iterator.
 | 
						|
     */
 | 
						|
    public Tag getTag()
 | 
						|
    {
 | 
						|
      return tag;
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event)
 | 
						|
  {
 | 
						|
    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
 | 
						|
   * @return the Iterator
 | 
						|
   */
 | 
						|
  public HTMLDocument.Iterator getIterator (HTML.Tag t)
 | 
						|
  {
 | 
						|
    return new HTMLDocument.LeafIterator(t, this);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * An iterator over a particular type of tag.
 | 
						|
   */
 | 
						|
  public abstract static class Iterator
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * Return the attribute set for this tag.
 | 
						|
     * @return the <code>AttributeSet</code> (null if none found).
 | 
						|
     */
 | 
						|
    public abstract AttributeSet getAttributes();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the end of the range for the current occurrence of the tag
 | 
						|
     * being defined and having the same attributes.
 | 
						|
     * @return the end of the range
 | 
						|
     */
 | 
						|
    public abstract int getEndOffset();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the start of the range for the current occurrence of the tag
 | 
						|
     * being defined and having the same attributes.
 | 
						|
     * @return the start of the range (-1 if it can't be found).
 | 
						|
     */
 | 
						|
    public abstract int getStartOffset();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Move the iterator forward.
 | 
						|
     */
 | 
						|
    public abstract void next();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Indicates whether or not the iterator currently represents an occurrence
 | 
						|
     * of the tag.
 | 
						|
     * @return true if the iterator currently represents an occurrence of the
 | 
						|
     * tag.
 | 
						|
     */
 | 
						|
    public abstract boolean isValid();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Type of tag this iterator represents.
 | 
						|
     * @return the tag.
 | 
						|
     */
 | 
						|
    public abstract HTML.Tag getTag();
 | 
						|
  }
 | 
						|
 | 
						|
  public class BlockElement extends AbstractDocument.BranchElement
 | 
						|
  {
 | 
						|
    public BlockElement (Element parent, AttributeSet a)
 | 
						|
    {
 | 
						|
      super(parent, a);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Gets the resolving parent.  Since HTML attributes are not
 | 
						|
     * inherited at the model level, this returns null.
 | 
						|
     */
 | 
						|
    public AttributeSet getResolveParent()
 | 
						|
    {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Gets the name of the element.
 | 
						|
     *
 | 
						|
     * @return the name of the element if it exists, null otherwise.
 | 
						|
     */
 | 
						|
    public String getName()
 | 
						|
    {
 | 
						|
      Object tag = getAttribute(StyleConstants.NameAttribute);
 | 
						|
      String name = null;
 | 
						|
      if (tag != null)
 | 
						|
        name = tag.toString();
 | 
						|
      if (name == null)
 | 
						|
        name = super.getName();
 | 
						|
      return name;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * RunElement represents a section of text that has a set of
 | 
						|
   * HTML character level attributes assigned to it.
 | 
						|
   */
 | 
						|
  public class RunElement extends AbstractDocument.LeafElement
 | 
						|
  {
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructs an element that has no children. It represents content
 | 
						|
     * within the document.
 | 
						|
     *
 | 
						|
     * @param parent - parent of this
 | 
						|
     * @param a - elements attributes
 | 
						|
     * @param start - the start offset >= 0
 | 
						|
     * @param end - the end offset
 | 
						|
     */
 | 
						|
    public RunElement(Element parent, AttributeSet a, int start, int end)
 | 
						|
    {
 | 
						|
      super(parent, a, start, end);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Gets the name of the element.
 | 
						|
     *
 | 
						|
     * @return the name of the element if it exists, null otherwise.
 | 
						|
     */
 | 
						|
    public String getName()
 | 
						|
    {
 | 
						|
      Object tag = getAttribute(StyleConstants.NameAttribute);
 | 
						|
      String name = null;
 | 
						|
      if (tag != null)
 | 
						|
        name = tag.toString();
 | 
						|
      if (name == null)
 | 
						|
        name = super.getName();
 | 
						|
      return name;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Gets the resolving parent. HTML attributes do not inherit at the
 | 
						|
     * model level, so this method returns null.
 | 
						|
     *
 | 
						|
     * @return null
 | 
						|
     */
 | 
						|
    public AttributeSet getResolveParent()
 | 
						|
    {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * A reader to load an HTMLDocument with HTML structure.
 | 
						|
   *
 | 
						|
   * @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<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();
 | 
						|
 | 
						|
    /** A mapping between HTML.Tag objects and the actions that handle them **/
 | 
						|
    HashMap tagToAction;
 | 
						|
 | 
						|
    /** Tells us whether we've received the '</html>' tag yet **/
 | 
						|
    boolean endHTMLEncountered = false;
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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;
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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;
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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 <textarea> 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
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * This method is called when a start tag is seen for one of the types
 | 
						|
       * of tags associated with this Action.  By default this does nothing.
 | 
						|
       */
 | 
						|
      public void start(HTML.Tag t, MutableAttributeSet a)
 | 
						|
      {
 | 
						|
        // Nothing to do here.
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Called when an end tag is seen for one of the types of tags associated
 | 
						|
       * with this Action.  By default does nothing.
 | 
						|
       */
 | 
						|
      public void end(HTML.Tag t)
 | 
						|
      {
 | 
						|
        // Nothing to do here.
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    public class BlockAction extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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)
 | 
						|
      {
 | 
						|
        // Tell the parse buffer to open a new block for this tag.
 | 
						|
        blockOpen(t, a);
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Called when an end tag is seen for one of the types of tags associated
 | 
						|
       * with this Action.
 | 
						|
       */
 | 
						|
      public void end(HTML.Tag t)
 | 
						|
      {
 | 
						|
        // Tell the parse buffer to close this block.
 | 
						|
        blockClose(t);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    public class CharacterAction extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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)
 | 
						|
      {
 | 
						|
        // 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());
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Called when an end tag is seen for one of the types of tags associated
 | 
						|
       * with this Action.
 | 
						|
       */
 | 
						|
      public void end(HTML.Tag t)
 | 
						|
      {
 | 
						|
        popCharacterStyle();
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Processes elements that make up forms: <input>, <textarea>,
 | 
						|
     * <select> and <option>.
 | 
						|
     */
 | 
						|
    public class FormAction extends SpecialAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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)
 | 
						|
      {
 | 
						|
        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);
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Called when an end tag is seen for one of the types of tags associated
 | 
						|
       * with this Action.
 | 
						|
       */
 | 
						|
      public void end(HTML.Tag t)
 | 
						|
      {
 | 
						|
        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
 | 
						|
     * still inserted and can be accessed when iterating the HTML document. The
 | 
						|
     * parser will only fire
 | 
						|
     * {@link javax.swing.text.html.HTMLEditorKit.ParserCallback#handleText} for
 | 
						|
     * the hidden tags, regardless from that html tags the hidden section may
 | 
						|
     * contain.
 | 
						|
     */
 | 
						|
    public class HiddenAction
 | 
						|
        extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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)
 | 
						|
      {
 | 
						|
        blockOpen(t, a);
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Called when an end tag is seen for one of the types of tags associated
 | 
						|
       * with this Action.
 | 
						|
       */
 | 
						|
      public void end(HTML.Tag t)
 | 
						|
      {
 | 
						|
        blockClose(t);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Handles <isindex> tags.
 | 
						|
     */
 | 
						|
    public class IsindexAction extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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)
 | 
						|
      {
 | 
						|
        blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
 | 
						|
        addSpecialElement(t, a);
 | 
						|
        blockClose(HTML.Tag.IMPLIED);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    public class ParagraphAction extends BlockAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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)
 | 
						|
      {
 | 
						|
        super.start(t, a);
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Called when an end tag is seen for one of the types of tags associated
 | 
						|
       * with this Action.
 | 
						|
       */
 | 
						|
      public void end(HTML.Tag t)
 | 
						|
      {
 | 
						|
        super.end(t);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * This action is performed when a <pre> tag is parsed.
 | 
						|
     */
 | 
						|
    public class PreAction extends BlockAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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)
 | 
						|
      {
 | 
						|
        inPreTag = true;
 | 
						|
        blockOpen(t, a);
 | 
						|
        a.addAttribute(CSS.Attribute.WHITE_SPACE, "pre");
 | 
						|
        blockOpen(HTML.Tag.IMPLIED, a);
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Called when an end tag is seen for one of the types of tags associated
 | 
						|
       * with this Action.
 | 
						|
       */
 | 
						|
      public void end(HTML.Tag t)
 | 
						|
      {
 | 
						|
        blockClose(HTML.Tag.IMPLIED);
 | 
						|
        inPreTag = false;
 | 
						|
        blockClose(t);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Inserts the elements that are represented by ths single tag with
 | 
						|
     * attributes (only). The closing tag, even if present, mut follow
 | 
						|
     * immediately after the starting tag without providing any additional
 | 
						|
     * information. Hence the {@link TagAction#end} method need not be
 | 
						|
     * overridden and still does nothing.
 | 
						|
     */
 | 
						|
    public class SpecialAction extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * The functionality is delegated to {@link HTMLReader#addSpecialElement}
 | 
						|
       */
 | 
						|
      public void start(HTML.Tag t, MutableAttributeSet a)
 | 
						|
      {
 | 
						|
        addSpecialElement(t, a);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    class AreaAction extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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.
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * 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.
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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)
 | 
						|
      {
 | 
						|
        baseTarget = (String) a.getAttribute(HTML.Attribute.TARGET);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    class HeadAction extends BlockAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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.
 | 
						|
        super.start(t, a);
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Called when an end tag is seen for one of the types of tags associated
 | 
						|
       * with this Action.
 | 
						|
       */
 | 
						|
      public void end(HTML.Tag 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 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)
 | 
						|
      {
 | 
						|
        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();
 | 
						|
                          }
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    class MapAction extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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.
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * 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 MetaAction extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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.
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * 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 StyleAction extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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)
 | 
						|
      {
 | 
						|
        inStyleTag = true;
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Called when an end tag is seen for one of the types of tags associated
 | 
						|
       * with this Action.
 | 
						|
       */
 | 
						|
      public void end(HTML.Tag t)
 | 
						|
      {
 | 
						|
        inStyleTag = false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    class TitleAction extends TagAction
 | 
						|
    {
 | 
						|
      /**
 | 
						|
       * 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.
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * 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.
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    public HTMLReader(int offset)
 | 
						|
    {
 | 
						|
      this (offset, 0, 0, null);
 | 
						|
    }
 | 
						|
 | 
						|
    public HTMLReader(int offset, int popDepth, int pushDepth,
 | 
						|
                      HTML.Tag insertTag)
 | 
						|
    {
 | 
						|
      this.insertTag = insertTag;
 | 
						|
      this.offset = offset;
 | 
						|
      this.popDepth = popDepth;
 | 
						|
      this.pushDepth = pushDepth;
 | 
						|
      threshold = getTokenThreshold();
 | 
						|
      initTags();
 | 
						|
    }
 | 
						|
 | 
						|
    void initTags()
 | 
						|
    {
 | 
						|
      tagToAction = new HashMap(72);
 | 
						|
      CharacterAction characterAction = new CharacterAction();
 | 
						|
      HiddenAction hiddenAction = new HiddenAction();
 | 
						|
      AreaAction areaAction = new AreaAction();
 | 
						|
      BaseAction baseAction = new BaseAction();
 | 
						|
      BlockAction blockAction = new BlockAction();
 | 
						|
      SpecialAction specialAction = new SpecialAction();
 | 
						|
      ParagraphAction paragraphAction = new ParagraphAction();
 | 
						|
      HeadAction headAction = new HeadAction();
 | 
						|
      FormAction formAction = new FormAction();
 | 
						|
      IsindexAction isindexAction = new IsindexAction();
 | 
						|
      LinkAction linkAction = new LinkAction();
 | 
						|
      MapAction mapAction = new MapAction();
 | 
						|
      PreAction preAction = new PreAction();
 | 
						|
      MetaAction metaAction = new MetaAction();
 | 
						|
      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);
 | 
						|
      tagToAction.put(HTML.Tag.AREA, areaAction);
 | 
						|
      tagToAction.put(HTML.Tag.B, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.BASE, baseAction);
 | 
						|
      tagToAction.put(HTML.Tag.BASEFONT, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.BIG, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.BLOCKQUOTE, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.BODY, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.BR, specialAction);
 | 
						|
      tagToAction.put(HTML.Tag.CAPTION, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.CENTER, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.CITE, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.CODE, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.DD, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.DFN, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.DIR, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.DIV, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.DL, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.DT, paragraphAction);
 | 
						|
      tagToAction.put(HTML.Tag.EM, characterAction);
 | 
						|
      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);
 | 
						|
      tagToAction.put(HTML.Tag.H2, paragraphAction);
 | 
						|
      tagToAction.put(HTML.Tag.H3, paragraphAction);
 | 
						|
      tagToAction.put(HTML.Tag.H4, paragraphAction);
 | 
						|
      tagToAction.put(HTML.Tag.H5, paragraphAction);
 | 
						|
      tagToAction.put(HTML.Tag.H6, paragraphAction);
 | 
						|
      tagToAction.put(HTML.Tag.HEAD, headAction);
 | 
						|
      tagToAction.put(HTML.Tag.HR, specialAction);
 | 
						|
      tagToAction.put(HTML.Tag.HTML, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.I, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.IMG, specialAction);
 | 
						|
      tagToAction.put(HTML.Tag.INPUT, formAction);
 | 
						|
      tagToAction.put(HTML.Tag.ISINDEX, isindexAction);
 | 
						|
      tagToAction.put(HTML.Tag.KBD, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.LI, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.LINK, linkAction);
 | 
						|
      tagToAction.put(HTML.Tag.MAP, mapAction);
 | 
						|
      tagToAction.put(HTML.Tag.MENU, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.META, metaAction);
 | 
						|
      tagToAction.put(HTML.Tag.NOFRAMES, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.OBJECT, specialAction);
 | 
						|
      tagToAction.put(HTML.Tag.OL, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.OPTION, formAction);
 | 
						|
      tagToAction.put(HTML.Tag.P, paragraphAction);
 | 
						|
      tagToAction.put(HTML.Tag.PARAM, hiddenAction);
 | 
						|
      tagToAction.put(HTML.Tag.PRE, preAction);
 | 
						|
      tagToAction.put(HTML.Tag.SAMP, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.SCRIPT, hiddenAction);
 | 
						|
      tagToAction.put(HTML.Tag.SELECT, formAction);
 | 
						|
      tagToAction.put(HTML.Tag.SMALL, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.STRIKE, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.S, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.STRONG, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.STYLE, styleAction);
 | 
						|
      tagToAction.put(HTML.Tag.SUB, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.SUP, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.TABLE, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.TD, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.TEXTAREA, formAction);
 | 
						|
      tagToAction.put(HTML.Tag.TH, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.TITLE, titleAction);
 | 
						|
      tagToAction.put(HTML.Tag.TR, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.TT, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.U, characterAction);
 | 
						|
      tagToAction.put(HTML.Tag.UL, blockAction);
 | 
						|
      tagToAction.put(HTML.Tag.VAR, characterAction);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Pushes the current character style onto the stack.
 | 
						|
     *
 | 
						|
     */
 | 
						|
    protected void pushCharacterStyle()
 | 
						|
    {
 | 
						|
      charAttrStack.push(charAttr.copyAttributes());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Pops a character style off of the stack and uses it as the
 | 
						|
     * current character style.
 | 
						|
     *
 | 
						|
     */
 | 
						|
    protected void popCharacterStyle()
 | 
						|
    {
 | 
						|
      if (!charAttrStack.isEmpty())
 | 
						|
        charAttr = (MutableAttributeSet) charAttrStack.pop();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Registers a given tag with a given Action.  All of the well-known tags
 | 
						|
     * are registered by default, but this method can change their behaviour
 | 
						|
     * or add support for custom or currently unsupported tags.
 | 
						|
     *
 | 
						|
     * @param t the Tag to register
 | 
						|
     * @param a the Action for the Tag
 | 
						|
     */
 | 
						|
    protected void registerTag(HTML.Tag t, HTMLDocument.HTMLReader.TagAction a)
 | 
						|
    {
 | 
						|
      tagToAction.put (t, a);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * This is the last method called on the HTMLReader, allowing any pending
 | 
						|
     * changes to be flushed to the HTMLDocument.
 | 
						|
     */
 | 
						|
    public void flush() throws BadLocationException
 | 
						|
    {
 | 
						|
      flushImpl();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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.
 | 
						|
     *
 | 
						|
     * @param data the text that was inserted
 | 
						|
     * @param pos the position at which the text was inserted
 | 
						|
     */
 | 
						|
    public void handleText(char[] data, int pos)
 | 
						|
    {
 | 
						|
      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);
 | 
						|
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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
 | 
						|
     * @param pos the position at which the tag was encountered
 | 
						|
     */
 | 
						|
    public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
 | 
						|
    {
 | 
						|
      if (t == insertTag)
 | 
						|
        insertTagEncountered = true;
 | 
						|
 | 
						|
      if (shouldInsert())
 | 
						|
        {
 | 
						|
          TagAction action = (TagAction) tagToAction.get(t);
 | 
						|
          if (action != null)
 | 
						|
            action.start(t, a);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * This method called by parser to handle a comment block.
 | 
						|
     *
 | 
						|
     * @param data the comment
 | 
						|
     * @param pos the position at which the comment was encountered
 | 
						|
     */
 | 
						|
    public void handleComment(char[] data, int pos)
 | 
						|
    {
 | 
						|
      if (shouldInsert())
 | 
						|
        {
 | 
						|
          TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
 | 
						|
          if (action != null)
 | 
						|
            {
 | 
						|
              action.start(HTML.Tag.COMMENT, new SimpleAttributeSet());
 | 
						|
              action.end(HTML.Tag.COMMENT);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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)
 | 
						|
    {
 | 
						|
      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
 | 
						|
     * appropriate handler for the tag.
 | 
						|
     *
 | 
						|
     * @param t the HTML.Tag that was encountered
 | 
						|
     * @param a the attribute set
 | 
						|
     * @param pos the position at which the tag was encountered
 | 
						|
     */
 | 
						|
    public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos)
 | 
						|
    {
 | 
						|
      if (t == insertTag)
 | 
						|
        insertTagEncountered = true;
 | 
						|
 | 
						|
      if (shouldInsert())
 | 
						|
        {
 | 
						|
          TagAction action = (TagAction) tagToAction.get(t);
 | 
						|
          if (action != null)
 | 
						|
            {
 | 
						|
              action.start(t, a);
 | 
						|
              action.end(t);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * This is invoked after the stream has been parsed but before it has been
 | 
						|
     * flushed.
 | 
						|
     *
 | 
						|
     * @param eol one of \n, \r, or \r\n, whichever was encountered the most in
 | 
						|
     * parsing the stream
 | 
						|
     * @since 1.3
 | 
						|
     */
 | 
						|
    public void handleEndOfLineString(String eol)
 | 
						|
    {
 | 
						|
      // FIXME: Implement.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds the given text to the textarea document.  Called only when we are
 | 
						|
     * within a textarea.
 | 
						|
     *
 | 
						|
     * @param data the text to add to the textarea
 | 
						|
     */
 | 
						|
    protected void textAreaContent(char[] data)
 | 
						|
    {
 | 
						|
      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)
 | 
						|
    {
 | 
						|
      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);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Instructs the parse buffer to create a block element with the given
 | 
						|
     * attributes.
 | 
						|
     *
 | 
						|
     * @param t the tag that requires opening a new block
 | 
						|
     * @param attr the attribute set for the new block
 | 
						|
     */
 | 
						|
    protected void blockOpen(HTML.Tag t, MutableAttributeSet attr)
 | 
						|
    {
 | 
						|
      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);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * 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
 | 
						|
     *
 | 
						|
     * @param t the HTML.Tag that is closing its block
 | 
						|
     */
 | 
						|
    protected void blockClose(HTML.Tag t)
 | 
						|
    {
 | 
						|
      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 = parseBuffer.size() > 0 ? (DefaultStyledDocument.ElementSpec)
 | 
						|
                                parseBuffer.get(parseBuffer.size() - 1) : null;
 | 
						|
      if (prev != null &&
 | 
						|
          prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType)
 | 
						|
        {
 | 
						|
          addContent(new char[]{' '}, 0, 1);
 | 
						|
        }
 | 
						|
 | 
						|
      element = new DefaultStyledDocument.ElementSpec(null,
 | 
						|
                                DefaultStyledDocument.ElementSpec.EndTagType);
 | 
						|
      parseBuffer.addElement(element);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds text to the appropriate context using the current character
 | 
						|
     * attribute set.
 | 
						|
     *
 | 
						|
     * @param data the text to add
 | 
						|
     * @param offs the offset at which to add it
 | 
						|
     * @param length the length of the text to add
 | 
						|
     */
 | 
						|
    protected void addContent(char[] data, int offs, int length)
 | 
						|
    {
 | 
						|
      addContent(data, offs, length, true);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds text to the appropriate context using the current character
 | 
						|
     * attribute set, and possibly generating an IMPLIED Tag if necessary.
 | 
						|
     *
 | 
						|
     * @param data the text to add
 | 
						|
     * @param offs the offset at which to add it
 | 
						|
     * @param length the length of the text to add
 | 
						|
     * @param generateImpliedPIfNecessary whether or not we should generate
 | 
						|
     * an HTML.Tag.IMPLIED tag if necessary
 | 
						|
     */
 | 
						|
    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;
 | 
						|
 | 
						|
      // Copy the attribute set, don't use the same object because
 | 
						|
      // it may change
 | 
						|
      if (charAttr != null)
 | 
						|
        attributes = charAttr.copyAttributes();
 | 
						|
      else
 | 
						|
        attributes = ctx.getEmptySet();
 | 
						|
      attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute,
 | 
						|
                                    HTML.Tag.CONTENT);
 | 
						|
      element = new DefaultStyledDocument.ElementSpec(attributes,
 | 
						|
                                DefaultStyledDocument.ElementSpec.ContentType,
 | 
						|
                                data, offs, length);
 | 
						|
 | 
						|
      // Add the element to the buffer
 | 
						|
      parseBuffer.addElement(element);
 | 
						|
 | 
						|
      if (parseBuffer.size() > threshold)
 | 
						|
        {
 | 
						|
          if (threshold <= MAX_THRESHOLD)
 | 
						|
            threshold *= GROW_THRESHOLD;
 | 
						|
          try
 | 
						|
            {
 | 
						|
              flushImpl();
 | 
						|
            }
 | 
						|
          catch (BadLocationException ble)
 | 
						|
            {
 | 
						|
              // TODO: what to do here?
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Adds content that is specified in the attribute set.
 | 
						|
     *
 | 
						|
     * @param t the HTML.Tag
 | 
						|
     * @param a the attribute set specifying the special content
 | 
						|
     */
 | 
						|
    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);
 | 
						|
 | 
						|
      // 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(a.copyAttributes(),
 | 
						|
          DefaultStyledDocument.ElementSpec.ContentType,
 | 
						|
          new char[] {' '}, 0, 1 );
 | 
						|
      parseBuffer.add(spec);
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the reader for the parser to use when loading the document with HTML.
 | 
						|
   *
 | 
						|
   * @param pos - the starting position
 | 
						|
   * @return - the reader
 | 
						|
   */
 | 
						|
  public HTMLEditorKit.ParserCallback getReader(int pos)
 | 
						|
  {
 | 
						|
    return new HTMLReader(pos);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the reader for the parser to use when loading the document with HTML.
 | 
						|
   *
 | 
						|
   * @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
 | 
						|
   * @return - the reader
 | 
						|
   */
 | 
						|
  public HTMLEditorKit.ParserCallback getReader(int pos,
 | 
						|
                                                int popDepth,
 | 
						|
                                                int pushDepth,
 | 
						|
                                                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);
 | 
						|
      }
 | 
						|
    };
 | 
						|
 | 
						|
    return reader;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the child element that contains the attribute with the value or null.
 | 
						|
   * Not thread-safe.
 | 
						|
   *
 | 
						|
   * @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.
 | 
						|
   */
 | 
						|
  public Element getElement(Element e, Object attribute, Object value)
 | 
						|
  {
 | 
						|
    if (e != null)
 | 
						|
      {
 | 
						|
        if (e.getAttributes().containsAttribute(attribute, value))
 | 
						|
          return e;
 | 
						|
 | 
						|
        int count = e.getElementCount();
 | 
						|
        for (int j = 0; j < count; j++)
 | 
						|
          {
 | 
						|
            Element child = e.getElement(j);
 | 
						|
            if (child.getAttributes().containsAttribute(attribute, value))
 | 
						|
              return child;
 | 
						|
 | 
						|
            Element grandChild = getElement(child, attribute, value);
 | 
						|
            if (grandChild != null)
 | 
						|
              return grandChild;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * 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 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.Attribute.ID,
 | 
						|
                      attrId);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Replaces the children of the given element with the contents of
 | 
						|
   * the string. The document must have an HTMLEditorKit.Parser set.
 | 
						|
   * This will be seen as at least two events, n inserts followed by a remove.
 | 
						|
   *
 | 
						|
   * @param elem - the brance element whose children will be replaced
 | 
						|
   * @param htmlText - the string to be parsed and assigned to element.
 | 
						|
   * @throws BadLocationException
 | 
						|
   * @throws IOException
 | 
						|
   * @throws IllegalArgumentException - if elem is a leaf
 | 
						|
   * @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set
 | 
						|
   */
 | 
						|
  public void setInnerHTML(Element elem, String htmlText)
 | 
						|
    throws BadLocationException, IOException
 | 
						|
  {
 | 
						|
    if (elem.isLeaf())
 | 
						|
      throw new IllegalArgumentException("Element is a leaf");
 | 
						|
 | 
						|
    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.
 | 
						|
   *
 | 
						|
   * @param elem - the branch element whose parent will be replaced
 | 
						|
   * @param htmlText - the string to be parsed and assigned to elem
 | 
						|
   * @throws BadLocationException
 | 
						|
   * @throws IOException
 | 
						|
   * @throws IllegalStateException - if parser is not set
 | 
						|
   */
 | 
						|
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.
 | 
						|
   *
 | 
						|
   * @param elem - the element to be the root for the new text.
 | 
						|
   * @param htmlText - the string to be parsed and assigned to elem
 | 
						|
   * @throws BadLocationException
 | 
						|
   * @throws IOException
 | 
						|
   * @throws IllegalStateException - if parser has not been set
 | 
						|
   */
 | 
						|
  public void insertBeforeStart(Element elem, String htmlText)
 | 
						|
      throws BadLocationException, IOException
 | 
						|
  {
 | 
						|
    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.
 | 
						|
   *
 | 
						|
   * @param elem - the element to be the root for the new text
 | 
						|
   * @param htmlText - the text to insert
 | 
						|
   * @throws BadLocationException
 | 
						|
   * @throws IOException
 | 
						|
   * @throws IllegalStateException - if parser is not set
 | 
						|
   */
 | 
						|
  public void insertBeforeEnd(Element elem, String htmlText)
 | 
						|
      throws BadLocationException, IOException
 | 
						|
  {
 | 
						|
    HTMLEditorKit.ParserCallback reader = getInsertingReader(
 | 
						|
      elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
 | 
						|
 | 
						|
    // TODO charset
 | 
						|
    getParser().parse(new StringReader(htmlText), reader, true);
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Inserts the string after the end of the given element.
 | 
						|
   * The parser must be set.
 | 
						|
   *
 | 
						|
   * @param elem - the element to be the root for the new text
 | 
						|
   * @param htmlText - the text to insert
 | 
						|
   * @throws BadLocationException
 | 
						|
   * @throws IOException
 | 
						|
   * @throws IllegalStateException - if parser is not set
 | 
						|
   */
 | 
						|
  public void insertAfterEnd(Element elem, String htmlText)
 | 
						|
      throws BadLocationException, IOException
 | 
						|
  {
 | 
						|
    HTMLEditorKit.ParserCallback reader = getInsertingReader(
 | 
						|
      elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
 | 
						|
 | 
						|
    // TODO charset
 | 
						|
    getParser().parse(new StringReader(htmlText), reader, true);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Inserts the string at the start of the element.
 | 
						|
   * The parser must be set.
 | 
						|
   *
 | 
						|
   * @param elem - the element to be the root for the new text
 | 
						|
   * @param htmlText - the text to insert
 | 
						|
   * @throws BadLocationException
 | 
						|
   * @throws IOException
 | 
						|
   * @throws IllegalStateException - if parser is not set
 | 
						|
   */
 | 
						|
  public void insertAfterStart(Element elem, String htmlText)
 | 
						|
      throws BadLocationException, IOException
 | 
						|
  {
 | 
						|
    HTMLEditorKit.ParserCallback reader = getInsertingReader(
 | 
						|
      elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem);
 | 
						|
 | 
						|
    // 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();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
}
 |