mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1521 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1521 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			Java
		
	
	
	
/* HTMLEditorKit.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 java.awt.event.ActionEvent;
 | 
						|
import java.awt.event.MouseAdapter;
 | 
						|
import java.awt.event.MouseEvent;
 | 
						|
import java.awt.event.MouseMotionListener;
 | 
						|
import java.awt.Cursor;
 | 
						|
import java.awt.Point;
 | 
						|
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.InputStream;
 | 
						|
import java.io.InputStreamReader;
 | 
						|
import java.io.Reader;
 | 
						|
import java.io.Serializable;
 | 
						|
import java.io.StringReader;
 | 
						|
import java.io.Writer;
 | 
						|
import java.net.MalformedURLException;
 | 
						|
import java.net.URL;
 | 
						|
 | 
						|
import javax.accessibility.Accessible;
 | 
						|
import javax.accessibility.AccessibleContext;
 | 
						|
 | 
						|
import javax.swing.Action;
 | 
						|
import javax.swing.JEditorPane;
 | 
						|
import javax.swing.SwingUtilities;
 | 
						|
import javax.swing.event.HyperlinkEvent;
 | 
						|
import javax.swing.text.AttributeSet;
 | 
						|
import javax.swing.text.BadLocationException;
 | 
						|
import javax.swing.text.Document;
 | 
						|
import javax.swing.text.EditorKit;
 | 
						|
import javax.swing.text.Element;
 | 
						|
import javax.swing.text.MutableAttributeSet;
 | 
						|
import javax.swing.text.StyleConstants;
 | 
						|
import javax.swing.text.StyledDocument;
 | 
						|
import javax.swing.text.StyledEditorKit;
 | 
						|
import javax.swing.text.TextAction;
 | 
						|
import javax.swing.text.View;
 | 
						|
import javax.swing.text.ViewFactory;
 | 
						|
import javax.swing.text.html.parser.ParserDelegator;
 | 
						|
 | 
						|
/* Move these imports here after javax.swing.text.html to make it compile
 | 
						|
   with jikes.  */
 | 
						|
import gnu.javax.swing.text.html.parser.GnuParserDelegator;
 | 
						|
import gnu.javax.swing.text.html.parser.HTML_401F;
 | 
						|
 | 
						|
/**
 | 
						|
 * @author Lillian Angel (langel at redhat dot com)
 | 
						|
 */
 | 
						|
public class HTMLEditorKit
 | 
						|
  extends StyledEditorKit
 | 
						|
  implements Serializable, Cloneable, Accessible
 | 
						|
{
 | 
						|
 | 
						|
  /**
 | 
						|
   * Fires the hyperlink events on the associated component
 | 
						|
   * when needed.
 | 
						|
   */
 | 
						|
  public static class LinkController
 | 
						|
    extends MouseAdapter
 | 
						|
    implements MouseMotionListener, Serializable
 | 
						|
    {
 | 
						|
 | 
						|
      /**
 | 
						|
       * The element of the last anchor tag.
 | 
						|
       */
 | 
						|
      private Element lastAnchorElement;
 | 
						|
 | 
						|
      /**
 | 
						|
       * Constructor
 | 
						|
       */
 | 
						|
      public LinkController()
 | 
						|
      {
 | 
						|
        super();
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Dispatched when the mouse is clicked. If the component
 | 
						|
       * is read-only, then the clicked event is used to drive an
 | 
						|
       * attempt to follow the reference specified by a link
 | 
						|
       *
 | 
						|
       * @param e - the mouse event
 | 
						|
       */
 | 
						|
      public void mouseClicked(MouseEvent e)
 | 
						|
      {
 | 
						|
        JEditorPane editor = (JEditorPane) e.getSource();
 | 
						|
        if (! editor.isEditable() && SwingUtilities.isLeftMouseButton(e))
 | 
						|
          {
 | 
						|
            Point loc = e.getPoint();
 | 
						|
            int pos = editor.viewToModel(loc);
 | 
						|
            if (pos >= 0)
 | 
						|
              activateLink(pos, editor, e.getX(), e.getY());
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Dispatched when the mouse is dragged on a component.
 | 
						|
       *
 | 
						|
       * @param e - the mouse event.
 | 
						|
       */
 | 
						|
      public void mouseDragged(MouseEvent e)
 | 
						|
      {
 | 
						|
        // Nothing to do here.
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Dispatched when the mouse cursor has moved into the component.
 | 
						|
       *
 | 
						|
       * @param e - the mouse event.
 | 
						|
       */
 | 
						|
      public void mouseMoved(MouseEvent e)
 | 
						|
      {
 | 
						|
        JEditorPane editor = (JEditorPane) e.getSource();
 | 
						|
        HTMLEditorKit kit = (HTMLEditorKit) editor.getEditorKit();
 | 
						|
        if (! editor.isEditable())
 | 
						|
          {
 | 
						|
            Document doc = editor.getDocument();
 | 
						|
            if (doc instanceof HTMLDocument)
 | 
						|
              {
 | 
						|
                Cursor newCursor = kit.getDefaultCursor();
 | 
						|
                HTMLDocument htmlDoc = (HTMLDocument) doc;
 | 
						|
                Point loc = e.getPoint();
 | 
						|
                int pos = editor.viewToModel(loc);
 | 
						|
                Element el = htmlDoc.getCharacterElement(pos);
 | 
						|
                if (pos < el.getStartOffset() || pos >= el.getEndOffset())
 | 
						|
                  el = null;
 | 
						|
                if (el != null)
 | 
						|
                  {
 | 
						|
                    AttributeSet aAtts = (AttributeSet)
 | 
						|
                                   el.getAttributes().getAttribute(HTML.Tag.A);
 | 
						|
                    if (aAtts != null)
 | 
						|
                      {
 | 
						|
                        if (el != lastAnchorElement)
 | 
						|
                          {
 | 
						|
                            if (lastAnchorElement != null)
 | 
						|
                              htmlDoc.updateSpecialClass(lastAnchorElement,
 | 
						|
                                                  HTML.Attribute.DYNAMIC_CLASS,
 | 
						|
                                                  null);
 | 
						|
                            lastAnchorElement = el;
 | 
						|
                            htmlDoc.updateSpecialClass(el,
 | 
						|
                                                  HTML.Attribute.DYNAMIC_CLASS,
 | 
						|
                                                  "hover");
 | 
						|
                          }
 | 
						|
                        newCursor = kit.getLinkCursor();
 | 
						|
                      }
 | 
						|
                    else
 | 
						|
                      {
 | 
						|
                        if (lastAnchorElement != null)
 | 
						|
                          htmlDoc.updateSpecialClass(lastAnchorElement,
 | 
						|
                                              HTML.Attribute.DYNAMIC_CLASS,
 | 
						|
                                              null);
 | 
						|
                        lastAnchorElement = null;
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    if (lastAnchorElement != null)
 | 
						|
                      htmlDoc.updateSpecialClass(lastAnchorElement,
 | 
						|
                                          HTML.Attribute.DYNAMIC_CLASS,
 | 
						|
                                          null);
 | 
						|
                    lastAnchorElement = null;
 | 
						|
                  }
 | 
						|
                if (editor.getCursor() != newCursor)
 | 
						|
                  {
 | 
						|
                    editor.setCursor(newCursor);
 | 
						|
                  }
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * If the given position represents a link, then linkActivated is called
 | 
						|
       * on the JEditorPane.
 | 
						|
       *
 | 
						|
       * @param pos the position
 | 
						|
       * @param editor the editor pane
 | 
						|
       */
 | 
						|
      protected void activateLink(int pos, JEditorPane editor)
 | 
						|
      {
 | 
						|
        activateLink(pos, editor);
 | 
						|
      }
 | 
						|
 | 
						|
      private void activateLink(int pos, JEditorPane editor, int x, int y)
 | 
						|
      {
 | 
						|
        // TODO: This is here for future extension for mapped links support.
 | 
						|
        // For the time beeing we implement simple hyperlinks.
 | 
						|
        Document doc = editor.getDocument();
 | 
						|
        if (doc instanceof HTMLDocument)
 | 
						|
          {
 | 
						|
            HTMLDocument htmlDoc = (HTMLDocument) doc;
 | 
						|
            Element el = htmlDoc.getCharacterElement(pos);
 | 
						|
            AttributeSet atts = el.getAttributes();
 | 
						|
            AttributeSet anchorAtts =
 | 
						|
              (AttributeSet) atts.getAttribute(HTML.Tag.A);
 | 
						|
            String href = null;
 | 
						|
            if (anchorAtts != null)
 | 
						|
              {
 | 
						|
                href = (String) anchorAtts.getAttribute(HTML.Attribute.HREF);
 | 
						|
                htmlDoc.updateSpecialClass(el, HTML.Attribute.PSEUDO_CLASS,
 | 
						|
                                           "visited");
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                // TODO: Implement link maps here.
 | 
						|
              }
 | 
						|
            HyperlinkEvent event = null;
 | 
						|
            if (href != null)
 | 
						|
              event = createHyperlinkEvent(editor, htmlDoc, href,
 | 
						|
                                           anchorAtts, el);
 | 
						|
            if (event != null)
 | 
						|
              editor.fireHyperlinkUpdate(event);
 | 
						|
          }
 | 
						|
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Creates a HyperlinkEvent for the specified href and anchor if
 | 
						|
       * possible. If for some reason this won't work, return null.
 | 
						|
       *
 | 
						|
       * @param editor the editor
 | 
						|
       * @param doc the document
 | 
						|
       * @param href the href link
 | 
						|
       * @param anchor the anchor
 | 
						|
       * @param el the element
 | 
						|
       *
 | 
						|
       * @return the hyperlink event, or <code>null</code> if we couldn't
 | 
						|
       *         create one
 | 
						|
       */
 | 
						|
      private HyperlinkEvent createHyperlinkEvent(JEditorPane editor,
 | 
						|
                                                  HTMLDocument doc,
 | 
						|
                                                  String href,
 | 
						|
                                                  AttributeSet anchor,
 | 
						|
                                                  Element el)
 | 
						|
      {
 | 
						|
        URL url;
 | 
						|
        try
 | 
						|
          {
 | 
						|
            URL base = doc.getBase();
 | 
						|
            url = new URL(base, href);
 | 
						|
 | 
						|
          }
 | 
						|
        catch (MalformedURLException ex)
 | 
						|
          {
 | 
						|
            url = null;
 | 
						|
          }
 | 
						|
        HyperlinkEvent ev;
 | 
						|
        if (doc.isFrameDocument())
 | 
						|
          {
 | 
						|
            String target = null;
 | 
						|
            if (anchor != null)
 | 
						|
              target = (String) anchor.getAttribute(HTML.Attribute.TARGET);
 | 
						|
            if (target == null || target.equals(""))
 | 
						|
              target = doc.getBaseTarget();
 | 
						|
            if (target == null || target.equals(""))
 | 
						|
              target = "_self";
 | 
						|
            ev = new HTMLFrameHyperlinkEvent(editor,
 | 
						|
                                            HyperlinkEvent.EventType.ACTIVATED,
 | 
						|
                                            url, href, el, target);
 | 
						|
          }
 | 
						|
        else
 | 
						|
          {
 | 
						|
            ev = new HyperlinkEvent(editor, HyperlinkEvent.EventType.ACTIVATED,
 | 
						|
                                    url, href, el);
 | 
						|
          }
 | 
						|
        return ev;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This class is used to insert a string of HTML into an existing
 | 
						|
   * document. At least 2 HTML.Tags need to be supplied. The first Tag (parentTag)
 | 
						|
   * identifies the parent in the document to add the elements to. The second, (addTag),
 | 
						|
   * identifies that the first tag should be added to the document as seen in the string.
 | 
						|
   * The parser will generate all appropriate (opening/closing tags_ even if they are not
 | 
						|
   * in the HTML string passed in.
 | 
						|
   */
 | 
						|
  public static class InsertHTMLTextAction
 | 
						|
    extends HTMLTextAction
 | 
						|
    {
 | 
						|
 | 
						|
      /**
 | 
						|
       * Tag in HTML to start adding tags from.
 | 
						|
       */
 | 
						|
      protected HTML.Tag addTag;
 | 
						|
 | 
						|
      /**
 | 
						|
       * Alternate tag in HTML to start adding tags from if parentTag is
 | 
						|
       * not found and alternateParentTag is not found.
 | 
						|
       */
 | 
						|
      protected HTML.Tag alternateAddTag;
 | 
						|
 | 
						|
      /**
 | 
						|
       * Alternate tag to check if parentTag is not found.
 | 
						|
       */
 | 
						|
      protected HTML.Tag alternateParentTag;
 | 
						|
 | 
						|
      /**
 | 
						|
       * HTML to insert.
 | 
						|
       */
 | 
						|
      protected String html;
 | 
						|
 | 
						|
      /**
 | 
						|
       * Tag to check for in the document.
 | 
						|
       */
 | 
						|
      protected HTML.Tag parentTag;
 | 
						|
 | 
						|
      /**
 | 
						|
       * Initializes all fields.
 | 
						|
       *
 | 
						|
       * @param name - the name of the document.
 | 
						|
       * @param html - the html to insert
 | 
						|
       * @param parentTag - the parent tag to check for
 | 
						|
       * @param addTag - the tag to start adding from
 | 
						|
       */
 | 
						|
      public InsertHTMLTextAction(String name, String html,
 | 
						|
                                  HTML.Tag parentTag, HTML.Tag addTag)
 | 
						|
      {
 | 
						|
        this(name, html, parentTag, addTag, null, null);
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Initializes all fields and calls super
 | 
						|
       *
 | 
						|
       * @param name - the name of the document.
 | 
						|
       * @param html - the html to insert
 | 
						|
       * @param parentTag - the parent tag to check for
 | 
						|
       * @param addTag - the tag to start adding from
 | 
						|
       * @param alternateParentTag - the alternate parent tag
 | 
						|
       * @param alternateAddTag - the alternate add tag
 | 
						|
       */
 | 
						|
      public InsertHTMLTextAction(String name, String html, HTML.Tag parentTag,
 | 
						|
                                  HTML.Tag addTag, HTML.Tag alternateParentTag,
 | 
						|
                                  HTML.Tag alternateAddTag)
 | 
						|
      {
 | 
						|
        super(name);
 | 
						|
        // Fields are for easy access when the action is applied to an actual
 | 
						|
        // document.
 | 
						|
        this.html = html;
 | 
						|
        this.parentTag = parentTag;
 | 
						|
        this.addTag = addTag;
 | 
						|
        this.alternateParentTag = alternateParentTag;
 | 
						|
        this.alternateAddTag = alternateAddTag;
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * HTMLEditorKit.insertHTML is called. If an exception is
 | 
						|
       * thrown, it is wrapped in a RuntimeException and thrown.
 | 
						|
       *
 | 
						|
       * @param editor - the editor to use to get the editorkit
 | 
						|
       * @param doc -
 | 
						|
       *          the Document to insert the HTML into.
 | 
						|
       * @param offset -
 | 
						|
       *          where to begin inserting the HTML.
 | 
						|
       * @param html -
 | 
						|
       *          the String to insert
 | 
						|
       * @param popDepth -
 | 
						|
       *          the number of ElementSpec.EndTagTypes to generate before
 | 
						|
       *          inserting
 | 
						|
       * @param pushDepth -
 | 
						|
       *          the number of ElementSpec.StartTagTypes with a direction of
 | 
						|
       *          ElementSpec.JoinNextDirection that should be generated before
 | 
						|
       * @param addTag -
 | 
						|
       *          the first tag to start inserting into document
 | 
						|
       */
 | 
						|
      protected void insertHTML(JEditorPane editor, HTMLDocument doc, int offset,
 | 
						|
                              String html, int popDepth, int pushDepth,
 | 
						|
                              HTML.Tag addTag)
 | 
						|
      {
 | 
						|
        try
 | 
						|
          {
 | 
						|
            super.getHTMLEditorKit(editor).insertHTML(doc, offset, html,
 | 
						|
                                                      popDepth, pushDepth, addTag);
 | 
						|
          }
 | 
						|
        catch (IOException e)
 | 
						|
          {
 | 
						|
            throw (RuntimeException) new RuntimeException("Parser is null.").initCause(e);
 | 
						|
          }
 | 
						|
        catch (BadLocationException ex)
 | 
						|
          {
 | 
						|
            throw (RuntimeException) new RuntimeException("BadLocationException: "
 | 
						|
                                              + offset).initCause(ex);
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Invoked when inserting at a boundary. Determines the number of pops,
 | 
						|
       * and then the number of pushes that need to be performed. The it calls
 | 
						|
       * insertHTML.
 | 
						|
       *
 | 
						|
       * @param editor -
 | 
						|
       *          the editor to use to get the editorkit
 | 
						|
       * @param doc -
 | 
						|
       *          the Document to insert the HTML into.
 | 
						|
       * @param offset -
 | 
						|
       *          where to begin inserting the HTML.
 | 
						|
       * @param insertElement -
 | 
						|
       *          the element to insert
 | 
						|
       * @param html -
 | 
						|
       *          the html to insert
 | 
						|
       * @param parentTag -
 | 
						|
       *          the parent tag
 | 
						|
       * @param addTag -
 | 
						|
       *          the first tag
 | 
						|
       */
 | 
						|
      protected void insertAtBoundary(JEditorPane editor,
 | 
						|
                                      HTMLDocument doc, int offset,
 | 
						|
                                      Element insertElement,
 | 
						|
                                      String html, HTML.Tag parentTag,
 | 
						|
                                      HTML.Tag addTag)
 | 
						|
      {
 | 
						|
        insertAtBoundry(editor, doc, offset, insertElement,
 | 
						|
                        html, parentTag, addTag);
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Invoked when inserting at a boundary. Determines the number of pops,
 | 
						|
       * and then the number of pushes that need to be performed. The it calls
 | 
						|
       * insertHTML.
 | 
						|
       *
 | 
						|
       * @param editor - the editor to use to get the editorkit
 | 
						|
       * @param doc -
 | 
						|
       *          the Document to insert the HTML into.
 | 
						|
       * @param offset -
 | 
						|
       *          where to begin inserting the HTML.
 | 
						|
       * @param insertElement - the element to insert
 | 
						|
       * @param html - the html to insert
 | 
						|
       * @param parentTag - the parent tag
 | 
						|
       * @param addTag - the first tag
 | 
						|
       *
 | 
						|
       * @deprecated as of v1.3, use insertAtBoundary
 | 
						|
       */
 | 
						|
      protected void insertAtBoundry(JEditorPane editor,
 | 
						|
                                     HTMLDocument doc,
 | 
						|
                                     int offset, Element insertElement,
 | 
						|
                                     String html, HTML.Tag parentTag,
 | 
						|
                                     HTML.Tag addTag)
 | 
						|
      {
 | 
						|
        Element parent = insertElement;
 | 
						|
        Element el;
 | 
						|
        // Find common parent element.
 | 
						|
        if (offset > 0 || insertElement == null)
 | 
						|
          {
 | 
						|
            el = doc.getDefaultRootElement();
 | 
						|
            while (el != null && el.getStartOffset() != offset
 | 
						|
                   && ! el.isLeaf())
 | 
						|
              el = el.getElement(el.getElementIndex(offset));
 | 
						|
            parent = el != null ? el.getParentElement() : null;
 | 
						|
          }
 | 
						|
        if (parent != null)
 | 
						|
          {
 | 
						|
            int pops = 0;
 | 
						|
            int pushes = 0;
 | 
						|
            if (offset == 0 && insertElement != null)
 | 
						|
              {
 | 
						|
                el = parent;
 | 
						|
                while (el != null && ! el.isLeaf())
 | 
						|
                  {
 | 
						|
                    el = el.getElement(el.getElementIndex(offset));
 | 
						|
                    pops++;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                el = parent;
 | 
						|
                offset--;
 | 
						|
                while (el != null && ! el.isLeaf())
 | 
						|
                  {
 | 
						|
                    el = el.getElement(el.getElementIndex(offset));
 | 
						|
                    pops++;
 | 
						|
                  }
 | 
						|
                el = parent;
 | 
						|
                offset++;
 | 
						|
                while (el != null && el != insertElement)
 | 
						|
                  {
 | 
						|
                    el = el.getElement(el.getElementIndex(offset));
 | 
						|
                    pushes++;
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            pops = Math.max(0, pops - 1);
 | 
						|
            insertHTML(editor, doc, offset, html, pops, pushes, addTag);
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Inserts the HTML.
 | 
						|
       *
 | 
						|
       * @param ae - the action performed
 | 
						|
       */
 | 
						|
      public void actionPerformed(ActionEvent ae)
 | 
						|
      {
 | 
						|
        JEditorPane source = getEditor(ae);
 | 
						|
        if (source != null)
 | 
						|
          {
 | 
						|
            HTMLDocument d = getHTMLDocument(source);
 | 
						|
            int offset = source.getSelectionStart();
 | 
						|
            int length = d.getLength();
 | 
						|
            boolean inserted = true;
 | 
						|
            if (! tryInsert(source, d, offset, parentTag, addTag))
 | 
						|
              {
 | 
						|
                inserted = tryInsert(source, d, offset, alternateParentTag,
 | 
						|
                                     alternateAddTag);
 | 
						|
              }
 | 
						|
            if (inserted)
 | 
						|
              adjustSelection(source, d, offset, length);
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Tries to insert the html chunk to the specified <code>addTag</code>.
 | 
						|
       *
 | 
						|
       * @param pane the editor
 | 
						|
       * @param doc the document
 | 
						|
       * @param offset the offset at which to insert
 | 
						|
       * @param tag the tag at which to insert
 | 
						|
       * @param addTag the add tag
 | 
						|
       *
 | 
						|
       * @return <code>true</code> when the html has been inserted successfully,
 | 
						|
       *         <code>false</code> otherwise
 | 
						|
       */
 | 
						|
      private boolean tryInsert(JEditorPane pane, HTMLDocument doc, int offset,
 | 
						|
                                HTML.Tag tag, HTML.Tag addTag)
 | 
						|
      {
 | 
						|
        boolean inserted = false;
 | 
						|
        Element el = findElementMatchingTag(doc, offset, tag);
 | 
						|
        if (el != null && el.getStartOffset() == offset)
 | 
						|
          {
 | 
						|
            insertAtBoundary(pane, doc, offset, el, html, tag, addTag);
 | 
						|
            inserted = true;
 | 
						|
          }
 | 
						|
        else if (offset > 0)
 | 
						|
          {
 | 
						|
            int depth = elementCountToTag(doc, offset - 1, tag);
 | 
						|
            if (depth != -1)
 | 
						|
              {
 | 
						|
                insertHTML(pane, doc, offset, html, depth, 0, addTag);
 | 
						|
                inserted = true;
 | 
						|
              }
 | 
						|
          }
 | 
						|
        return inserted;
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Adjusts the selection after an insertion has been performed.
 | 
						|
       *
 | 
						|
       * @param pane the editor pane
 | 
						|
       * @param doc the document
 | 
						|
       * @param offset the insert offset
 | 
						|
       * @param oldLen the old document length
 | 
						|
       */
 | 
						|
      private void adjustSelection(JEditorPane pane, HTMLDocument doc,
 | 
						|
                                   int offset, int oldLen)
 | 
						|
      {
 | 
						|
        int newLen = doc.getLength();
 | 
						|
        if (newLen != oldLen && offset < newLen)
 | 
						|
          {
 | 
						|
            if (offset > 0)
 | 
						|
              {
 | 
						|
                String text;
 | 
						|
                try
 | 
						|
                  {
 | 
						|
                    text = doc.getText(offset - 1, 1);
 | 
						|
                  }
 | 
						|
                catch (BadLocationException ex)
 | 
						|
                  {
 | 
						|
                    text = null;
 | 
						|
                  }
 | 
						|
                if (text != null && text.length() > 0
 | 
						|
                    && text.charAt(0) == '\n')
 | 
						|
                  {
 | 
						|
                    pane.select(offset, offset);
 | 
						|
                  }
 | 
						|
                else
 | 
						|
                  {
 | 
						|
                    pane.select(offset + 1, offset + 1);
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                pane.select(1, 1);
 | 
						|
              }
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Abstract Action class that helps inserting HTML into an existing document.
 | 
						|
   */
 | 
						|
  public abstract static class HTMLTextAction
 | 
						|
    extends StyledEditorKit.StyledTextAction
 | 
						|
    {
 | 
						|
 | 
						|
      /**
 | 
						|
       * Constructor
 | 
						|
       */
 | 
						|
      public HTMLTextAction(String name)
 | 
						|
      {
 | 
						|
        super(name);
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Gets the HTMLDocument from the JEditorPane.
 | 
						|
       *
 | 
						|
       * @param e - the editor pane
 | 
						|
       * @return the html document.
 | 
						|
       */
 | 
						|
      protected HTMLDocument getHTMLDocument(JEditorPane e)
 | 
						|
      {
 | 
						|
        Document d = e.getDocument();
 | 
						|
        if (d instanceof HTMLDocument)
 | 
						|
          return (HTMLDocument) d;
 | 
						|
        throw new IllegalArgumentException("Document is not a HTMLDocument.");
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Gets the HTMLEditorKit
 | 
						|
       *
 | 
						|
       * @param e - the JEditorPane to get the HTMLEditorKit from.
 | 
						|
       * @return the HTMLEditorKit
 | 
						|
       */
 | 
						|
      protected HTMLEditorKit getHTMLEditorKit(JEditorPane e)
 | 
						|
      {
 | 
						|
        EditorKit d = e.getEditorKit();
 | 
						|
        if (d instanceof HTMLEditorKit)
 | 
						|
          return (HTMLEditorKit) d;
 | 
						|
        throw new IllegalArgumentException("EditorKit is not a HTMLEditorKit.");
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Returns an array of Elements that contain the offset.
 | 
						|
       * The first elements corresponds to the roots of the doc.
 | 
						|
       *
 | 
						|
       * @param doc - the document to get the Elements from.
 | 
						|
       * @param offset - the offset the Elements must contain
 | 
						|
       * @return an array of all the elements containing the offset.
 | 
						|
       */
 | 
						|
      protected Element[] getElementsAt(HTMLDocument doc,
 | 
						|
                                        int offset)
 | 
						|
      {
 | 
						|
        return getElementsAt(doc.getDefaultRootElement(), offset, 0);
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Helper function to get all elements using recursion.
 | 
						|
       */
 | 
						|
      private Element[] getElementsAt(Element root, int offset, int depth)
 | 
						|
      {
 | 
						|
        Element[] elements = null;
 | 
						|
        if (root != null)
 | 
						|
          {
 | 
						|
            if (root.isLeaf())
 | 
						|
              {
 | 
						|
                elements = new Element[depth + 1];
 | 
						|
                elements[depth] = root;
 | 
						|
                return elements;
 | 
						|
              }
 | 
						|
            elements = getElementsAt(root.getElement(root.getElementIndex(offset)),
 | 
						|
                                     offset, depth + 1);
 | 
						|
            elements[depth] = root;
 | 
						|
          }
 | 
						|
        return elements;
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Returns the number of elements, starting at the deepest point, needed
 | 
						|
       * to get an element representing tag. -1 if no elements are found, 0 if
 | 
						|
       * the parent of the leaf at offset represents the tag.
 | 
						|
       *
 | 
						|
       * @param doc -
 | 
						|
       *          the document to search
 | 
						|
       * @param offset -
 | 
						|
       *          the offset to check
 | 
						|
       * @param tag -
 | 
						|
       *          the tag to look for
 | 
						|
       * @return - the number of elements needed to get an element representing
 | 
						|
       *         tag.
 | 
						|
       */
 | 
						|
      protected int elementCountToTag(HTMLDocument doc,
 | 
						|
                                      int offset, HTML.Tag tag)
 | 
						|
      {
 | 
						|
        Element root = doc.getDefaultRootElement();
 | 
						|
        int num = -1;
 | 
						|
        Element next = root.getElement(root.getElementIndex(offset));
 | 
						|
 | 
						|
        while (!next.isLeaf())
 | 
						|
          {
 | 
						|
            num++;
 | 
						|
            if (next.getAttributes().
 | 
						|
                getAttribute(StyleConstants.NameAttribute).equals(tag))
 | 
						|
              return num;
 | 
						|
            next = next.getElement(next.getElementIndex(offset));
 | 
						|
          }
 | 
						|
        return num;
 | 
						|
      }
 | 
						|
 | 
						|
      /**
 | 
						|
       * Gets the deepest element at offset with the
 | 
						|
       * matching tag.
 | 
						|
       *
 | 
						|
       * @param doc - the document to search
 | 
						|
       * @param offset - the offset to check for
 | 
						|
       * @param tag - the tag to match
 | 
						|
       * @return - the element that is found, null if not found.
 | 
						|
       */
 | 
						|
      protected Element findElementMatchingTag(HTMLDocument doc,
 | 
						|
                                               int offset, HTML.Tag tag)
 | 
						|
      {
 | 
						|
        Element element = doc.getDefaultRootElement();
 | 
						|
        Element tagElement = null;
 | 
						|
 | 
						|
        while (element != null)
 | 
						|
          {
 | 
						|
            Object otag = element.getAttributes().getAttribute(
 | 
						|
                                     StyleConstants.NameAttribute);
 | 
						|
            if (otag instanceof HTML.Tag && otag.equals(tag))
 | 
						|
              tagElement = element;
 | 
						|
            element = element.getElement(element.getElementIndex(offset));
 | 
						|
          }
 | 
						|
 | 
						|
        return tagElement;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
  /**
 | 
						|
   * A {@link ViewFactory} that is able to create {@link View}s for
 | 
						|
   * the <code>Element</code>s that are supported.
 | 
						|
   */
 | 
						|
  public static class HTMLFactory
 | 
						|
    implements ViewFactory
 | 
						|
  {
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructor
 | 
						|
     */
 | 
						|
    public HTMLFactory()
 | 
						|
    {
 | 
						|
      // Do Nothing here.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Creates a {@link View} for the specified <code>Element</code>.
 | 
						|
     *
 | 
						|
     * @param element the <code>Element</code> to create a <code>View</code>
 | 
						|
     *        for
 | 
						|
     * @return the <code>View</code> for the specified <code>Element</code>
 | 
						|
     *         or <code>null</code> if the type of <code>element</code> is
 | 
						|
     *         not supported
 | 
						|
     */
 | 
						|
    public View create(Element element)
 | 
						|
    {
 | 
						|
      View view = null;
 | 
						|
      Object attr =
 | 
						|
        element.getAttributes().getAttribute(StyleConstants.NameAttribute);
 | 
						|
      if (attr instanceof HTML.Tag)
 | 
						|
        {
 | 
						|
          HTML.Tag tag = (HTML.Tag) attr;
 | 
						|
 | 
						|
          if (tag == HTML.Tag.IMPLIED || tag == HTML.Tag.P
 | 
						|
              || tag == HTML.Tag.H1 || tag == HTML.Tag.H2
 | 
						|
              || tag == HTML.Tag.H3 || tag == HTML.Tag.H4
 | 
						|
              || tag == HTML.Tag.H5 || tag == HTML.Tag.H6
 | 
						|
              || tag == HTML.Tag.DT)
 | 
						|
            view = new ParagraphView(element);
 | 
						|
          else if (tag == HTML.Tag.LI || tag == HTML.Tag.DL
 | 
						|
                   || tag == HTML.Tag.DD || tag == HTML.Tag.BODY
 | 
						|
                   || tag == HTML.Tag.HTML || tag == HTML.Tag.CENTER
 | 
						|
                   || tag == HTML.Tag.DIV
 | 
						|
                   || tag == HTML.Tag.BLOCKQUOTE
 | 
						|
                   || tag == HTML.Tag.PRE
 | 
						|
                   || tag == HTML.Tag.FORM
 | 
						|
                   // Misplaced TD and TH tags get mapped as vertical block.
 | 
						|
                   // Note that correctly placed tags get mapped in TableView.
 | 
						|
                   || tag == HTML.Tag.TD || tag == HTML.Tag.TH)
 | 
						|
            view = new BlockView(element, View.Y_AXIS);
 | 
						|
          else if (tag == HTML.Tag.TR)
 | 
						|
            // Misplaced TR tags get mapped as horizontal blocks.
 | 
						|
            // Note that correctly placed tags get mapped in TableView.
 | 
						|
            view = new BlockView(element, View.X_AXIS);
 | 
						|
          else if (tag == HTML.Tag.IMG)
 | 
						|
            view = new ImageView(element);
 | 
						|
 | 
						|
          else if (tag == HTML.Tag.CONTENT)
 | 
						|
            view = new InlineView(element);
 | 
						|
          else if (tag == HTML.Tag.HEAD)
 | 
						|
            view = new NullView(element);
 | 
						|
          else if (tag == HTML.Tag.TABLE)
 | 
						|
            view = new javax.swing.text.html.TableView(element);
 | 
						|
          else if (tag == HTML.Tag.HR)
 | 
						|
            view = new HRuleView(element);
 | 
						|
          else if (tag == HTML.Tag.BR)
 | 
						|
            view = new BRView(element);
 | 
						|
          else if (tag == HTML.Tag.INPUT || tag == HTML.Tag.SELECT
 | 
						|
                   || tag == HTML.Tag.TEXTAREA)
 | 
						|
            view = new FormView(element);
 | 
						|
 | 
						|
          else if (tag == HTML.Tag.MENU || tag == HTML.Tag.DIR
 | 
						|
                   || tag == HTML.Tag.UL || tag == HTML.Tag.OL)
 | 
						|
            view = new ListView(element);
 | 
						|
          else if (tag == HTML.Tag.FRAMESET)
 | 
						|
            view = new FrameSetView(element);
 | 
						|
          else if (tag == HTML.Tag.FRAME)
 | 
						|
            view = new FrameView(element);
 | 
						|
          else if (tag == HTML.Tag.OBJECT)
 | 
						|
            view = new ObjectView(element);
 | 
						|
        }
 | 
						|
      if (view == null)
 | 
						|
        {
 | 
						|
          view = new NullView(element);
 | 
						|
        }
 | 
						|
      return view;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * The abstract HTML parser declaration.
 | 
						|
   */
 | 
						|
  public abstract static class Parser
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * Parse the HTML text, calling various methods of the provided callback
 | 
						|
     * in response to the occurence of the corresponding HTML constructions.
 | 
						|
     * @param reader The reader to read the source HTML from.
 | 
						|
     * @param callback The callback to receive information about the parsed
 | 
						|
     * HTML structures
 | 
						|
     * @param ignoreCharSet If true, the parser ignores all charset information
 | 
						|
     * that may be present in HTML documents.
 | 
						|
     * @throws IOException, normally if the reader throws one.
 | 
						|
     */
 | 
						|
    public abstract void parse(Reader reader, ParserCallback callback,
 | 
						|
                               boolean ignoreCharSet) throws IOException;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * The "hook" that receives all information about the HTML document
 | 
						|
   * structure while parsing it. The methods are invoked by parser
 | 
						|
   * and should be normally overridden.
 | 
						|
   */
 | 
						|
  public static class ParserCallback
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * If the tag does not occurs in the html stream directly, but
 | 
						|
     * is supposed by parser, the tag attribute set contains this additional
 | 
						|
     * attribute, having value Boolean.True.
 | 
						|
     */
 | 
						|
    public static final Object IMPLIED = "_implied_";
 | 
						|
 | 
						|
    /**
 | 
						|
     * Constructor
 | 
						|
     */
 | 
						|
    public ParserCallback()
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The parser calls this method after it finishes parsing the document.
 | 
						|
     */
 | 
						|
    public void flush() throws BadLocationException
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Handle HTML comment, present in the given position.
 | 
						|
     * @param comment the comment
 | 
						|
     * @position the position of the comment in the text being parsed.
 | 
						|
     */
 | 
						|
    public void handleComment(char[] comment, int position)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Notifies about the character sequences, used to separate lines in
 | 
						|
     * this document. The parser calls this method after it finishes
 | 
						|
     * parsing the document, but before flush().
 | 
						|
     * @param end_of_line The "end of line sequence", one of: \r or \n or \r\n.
 | 
						|
     */
 | 
						|
    public void handleEndOfLineString(String end_of_line)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The method is called when the HTML closing tag ((like </table>)
 | 
						|
     * is found or if the parser concludes that the one should be present
 | 
						|
     * in the current position.
 | 
						|
     * @param tag The tag being handled
 | 
						|
     * @param position the tag position in the text being parsed.
 | 
						|
     */
 | 
						|
    public void handleEndTag(HTML.Tag tag, int position)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Handle the error.
 | 
						|
     * @param message The message, explaining the error.
 | 
						|
     * @param position The starting position of the fragment that has caused
 | 
						|
     * the error in the html document being parsed.
 | 
						|
     */
 | 
						|
    public void handleError(String message, int position)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Handle the tag with no content, like <br>. The method is
 | 
						|
     * called for the elements that, in accordance with the current DTD,
 | 
						|
     * has an empty content.
 | 
						|
     * @param tag The tag being handled.
 | 
						|
     * @param position The tag position in the text being parsed.
 | 
						|
     */
 | 
						|
    public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes,
 | 
						|
                                int position)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * The method is called when the HTML opening tag ((like <table>)
 | 
						|
     * is found or if the parser concludes that the one should be present
 | 
						|
     * in the current position.
 | 
						|
     * @param tag The tag being handled
 | 
						|
     * @param position The tag position in the text being parsed
 | 
						|
     */
 | 
						|
    public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes,
 | 
						|
                               int position)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Handle the text section.
 | 
						|
     * @param text A section text.
 | 
						|
     * @param position The text position in the HTML document text being parsed.
 | 
						|
     */
 | 
						|
    public void handleText(char[] text, int position)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Use serialVersionUID (v1.4) for interoperability.
 | 
						|
   */
 | 
						|
  private static final long serialVersionUID = 8751997116710384592L;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Default cascading stylesheed file ("default.css").
 | 
						|
   */
 | 
						|
  public static final String DEFAULT_CSS = "default.css";
 | 
						|
 | 
						|
  /**
 | 
						|
   * The <b>bold</b> action identifier.
 | 
						|
   */
 | 
						|
  public static final String BOLD_ACTION = "html-bold-action";
 | 
						|
 | 
						|
  /**
 | 
						|
   * The <i>italic</i> action identifier.
 | 
						|
   */
 | 
						|
  public static final String ITALIC_ACTION = "html-italic-action";
 | 
						|
 | 
						|
  /**
 | 
						|
   * The <font color="#FF0000">color</font> action indentifier
 | 
						|
   * (passing the color as an argument).
 | 
						|
   */
 | 
						|
  public static final String COLOR_ACTION = "html-color-action";
 | 
						|
 | 
						|
  /**
 | 
						|
   * The <font size="+1">increase</font> font action identifier.
 | 
						|
   */
 | 
						|
  public static final String FONT_CHANGE_BIGGER = "html-font-bigger";
 | 
						|
 | 
						|
  /**
 | 
						|
   * The <font size="-1">decrease</font> font action identifier.
 | 
						|
   */
 | 
						|
  public static final String FONT_CHANGE_SMALLER = "html-font-smaller";
 | 
						|
 | 
						|
  /**
 | 
						|
   * Align images at the bottom.
 | 
						|
   */
 | 
						|
  public static final String IMG_ALIGN_BOTTOM = "html-image-align-bottom";
 | 
						|
 | 
						|
  /**
 | 
						|
   * Align images at the middle.
 | 
						|
   */
 | 
						|
  public static final String IMG_ALIGN_MIDDLE = "html-image-align-middle";
 | 
						|
 | 
						|
  /**
 | 
						|
   * Align images at the top.
 | 
						|
   */
 | 
						|
  public static final String IMG_ALIGN_TOP = "html-image-align-top";
 | 
						|
 | 
						|
  /**
 | 
						|
   * Align images at the border.
 | 
						|
   */
 | 
						|
  public static final String IMG_BORDER = "html-image-border";
 | 
						|
 | 
						|
  /**
 | 
						|
   * The "logical style" action identifier, passing that style as parameter.
 | 
						|
   */
 | 
						|
  public static final String LOGICAL_STYLE_ACTION = "html-logical-style-action";
 | 
						|
 | 
						|
  /**
 | 
						|
   * The "ident paragraph left" action.
 | 
						|
   */
 | 
						|
  public static final String PARA_INDENT_LEFT = "html-para-indent-left";
 | 
						|
 | 
						|
  /**
 | 
						|
   * The "ident paragraph right" action.
 | 
						|
   */
 | 
						|
  public static final String PARA_INDENT_RIGHT = "html-para-indent-right";
 | 
						|
 | 
						|
  /**
 | 
						|
   * Actions for HTML
 | 
						|
   */
 | 
						|
  private static final Action[] defaultActions =
 | 
						|
  {
 | 
						|
    new InsertHTMLTextAction("InsertTable",
 | 
						|
                             "<table border=1><tr><td></td></tr></table>",
 | 
						|
                             HTML.Tag.BODY, HTML.Tag.TABLE),
 | 
						|
    new InsertHTMLTextAction("InsertTableRow",
 | 
						|
                             "<table border=1><tr><td></td></tr></table>",
 | 
						|
                             HTML.Tag.TABLE, HTML.Tag.TR,
 | 
						|
                             HTML.Tag.BODY, HTML.Tag.TABLE),
 | 
						|
    new InsertHTMLTextAction("InsertTableCell",
 | 
						|
                             "<table border=1><tr><td></td></tr></table>",
 | 
						|
                             HTML.Tag.TR, HTML.Tag.TD,
 | 
						|
                             HTML.Tag.BODY, HTML.Tag.TABLE),
 | 
						|
    new InsertHTMLTextAction("InsertUnorderedList",
 | 
						|
                             "<ul><li></li></ul>",
 | 
						|
                             HTML.Tag.BODY, HTML.Tag.UL),
 | 
						|
    new InsertHTMLTextAction("InsertUnorderedListItem",
 | 
						|
                             "<ul><li></li></ul>",
 | 
						|
                             HTML.Tag.UL, HTML.Tag.LI,
 | 
						|
                             HTML.Tag.BODY, HTML.Tag.UL),
 | 
						|
    new InsertHTMLTextAction("InsertOrderedList",
 | 
						|
                             "<ol><li></li></ol>",
 | 
						|
                             HTML.Tag.BODY, HTML.Tag.OL),
 | 
						|
    new InsertHTMLTextAction("InsertOrderedListItem",
 | 
						|
                             "<ol><li></li></ol>",
 | 
						|
                             HTML.Tag.OL, HTML.Tag.LI,
 | 
						|
                             HTML.Tag.BODY, HTML.Tag.OL),
 | 
						|
    new InsertHTMLTextAction("InsertPre",
 | 
						|
                             "<pre></pre>", HTML.Tag.BODY, HTML.Tag.PRE)
 | 
						|
    // TODO: The reference impl has an InsertHRAction too.
 | 
						|
  };
 | 
						|
 | 
						|
  /**
 | 
						|
   * The current style sheet.
 | 
						|
   */
 | 
						|
  private StyleSheet styleSheet;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The ViewFactory for HTMLFactory.
 | 
						|
   */
 | 
						|
  HTMLFactory viewFactory;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The Cursor for links.
 | 
						|
   */
 | 
						|
  Cursor linkCursor;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The default cursor.
 | 
						|
   */
 | 
						|
  Cursor defaultCursor;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The parser.
 | 
						|
   */
 | 
						|
  Parser parser;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The mouse listener used for links.
 | 
						|
   */
 | 
						|
  private LinkController linkController;
 | 
						|
 | 
						|
  /** The content type */
 | 
						|
  String contentType = "text/html";
 | 
						|
 | 
						|
  /** The input attributes defined by default.css */
 | 
						|
  MutableAttributeSet inputAttributes;
 | 
						|
 | 
						|
  /** The editor pane used. */
 | 
						|
  JEditorPane editorPane;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Whether or not the editor kit handles form submissions.
 | 
						|
   *
 | 
						|
   * @see #isAutoFormSubmission()
 | 
						|
   * @see #setAutoFormSubmission(boolean)
 | 
						|
   */
 | 
						|
  private boolean autoFormSubmission;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet.
 | 
						|
   */
 | 
						|
  public HTMLEditorKit()
 | 
						|
  {
 | 
						|
    linkController = new LinkController();
 | 
						|
    autoFormSubmission = true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets a factory suitable for producing views of any
 | 
						|
   * models that are produced by this kit.
 | 
						|
   *
 | 
						|
   * @return the view factory suitable for producing views.
 | 
						|
   */
 | 
						|
  public ViewFactory getViewFactory()
 | 
						|
  {
 | 
						|
    if (viewFactory == null)
 | 
						|
      viewFactory = new HTMLFactory();
 | 
						|
    return viewFactory;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Create a text storage model for this type of editor.
 | 
						|
   *
 | 
						|
   * @return the model
 | 
						|
   */
 | 
						|
  public Document createDefaultDocument()
 | 
						|
  {
 | 
						|
    // Protect the shared stylesheet.
 | 
						|
    StyleSheet styleSheet = getStyleSheet();
 | 
						|
    StyleSheet ss = new StyleSheet();
 | 
						|
    ss.addStyleSheet(styleSheet);
 | 
						|
 | 
						|
    HTMLDocument document = new HTMLDocument(ss);
 | 
						|
    document.setParser(getParser());
 | 
						|
    document.setAsynchronousLoadPriority(4);
 | 
						|
    document.setTokenThreshold(100);
 | 
						|
    return document;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Get the parser that this editor kit uses for reading HTML streams. This
 | 
						|
   * method can be overridden to use the alternative parser.
 | 
						|
   *
 | 
						|
   * @return the HTML parser (by default, {@link ParserDelegator}).
 | 
						|
   */
 | 
						|
  protected Parser getParser()
 | 
						|
  {
 | 
						|
    if (parser == null)
 | 
						|
      {
 | 
						|
        parser = new GnuParserDelegator(HTML_401F.getInstance());
 | 
						|
      }
 | 
						|
    return parser;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Inserts HTML into an existing document.
 | 
						|
   *
 | 
						|
   * @param doc - the Document to insert the HTML into.
 | 
						|
   * @param offset - where to begin inserting the HTML.
 | 
						|
   * @param html - the String to insert
 | 
						|
   * @param popDepth - the number of ElementSpec.EndTagTypes
 | 
						|
   * to generate before inserting
 | 
						|
   * @param pushDepth - the number of ElementSpec.StartTagTypes
 | 
						|
   * with a direction of ElementSpec.JoinNextDirection that
 | 
						|
   * should be generated before
 | 
						|
   * @param insertTag - the first tag to start inserting into document
 | 
						|
   * @throws IOException - on any I/O error
 | 
						|
   * @throws BadLocationException - if pos represents an invalid location
 | 
						|
   * within the document
 | 
						|
   */
 | 
						|
  public void insertHTML(HTMLDocument doc, int offset, String html,
 | 
						|
                         int popDepth, int pushDepth, HTML.Tag insertTag)
 | 
						|
      throws BadLocationException, IOException
 | 
						|
  {
 | 
						|
    Parser parser = getParser();
 | 
						|
    if (offset < 0 || offset > doc.getLength())
 | 
						|
      throw new BadLocationException("Bad location", offset);
 | 
						|
    if (parser == null)
 | 
						|
      throw new IOException("Parser is null.");
 | 
						|
 | 
						|
    ParserCallback pc = doc.getReader(offset, popDepth, pushDepth, insertTag);
 | 
						|
 | 
						|
    // FIXME: What should ignoreCharSet be set to?
 | 
						|
 | 
						|
    // parser.parse inserts html into the buffer
 | 
						|
    parser.parse(new StringReader(html), pc, false);
 | 
						|
    pc.flush();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Inserts content from the given stream. Inserting HTML into a non-empty
 | 
						|
   * document must be inside the body Element, if you do not insert into
 | 
						|
   * the body an exception will be thrown. When inserting into a non-empty
 | 
						|
   * document all tags outside of the body (head, title) will be dropped.
 | 
						|
   *
 | 
						|
   * @param in - the stream to read from
 | 
						|
   * @param doc - the destination for the insertion
 | 
						|
   * @param pos - the location in the document to place the content
 | 
						|
   * @throws IOException - on any I/O error
 | 
						|
   * @throws BadLocationException - if pos represents an invalid location
 | 
						|
   * within the document
 | 
						|
   */
 | 
						|
  public void read(Reader in, Document doc, int pos) throws IOException,
 | 
						|
      BadLocationException
 | 
						|
  {
 | 
						|
    if (doc instanceof HTMLDocument)
 | 
						|
      {
 | 
						|
        Parser parser = getParser();
 | 
						|
        if (pos < 0 || pos > doc.getLength())
 | 
						|
          throw new BadLocationException("Bad location", pos);
 | 
						|
        if (parser == null)
 | 
						|
          throw new IOException("Parser is null.");
 | 
						|
 | 
						|
        HTMLDocument hd = ((HTMLDocument) doc);
 | 
						|
        if (editorPane != null)
 | 
						|
          hd.setBase(editorPane.getPage());
 | 
						|
        ParserCallback pc = hd.getReader(pos);
 | 
						|
 | 
						|
        // FIXME: What should ignoreCharSet be set to?
 | 
						|
 | 
						|
        // parser.parse inserts html into the buffer
 | 
						|
        parser.parse(in, pc, false);
 | 
						|
        pc.flush();
 | 
						|
      }
 | 
						|
    else
 | 
						|
      // read in DefaultEditorKit is called.
 | 
						|
      // the string is inserted in the document as usual.
 | 
						|
      super.read(in, doc, pos);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Writes content from a document to the given stream in
 | 
						|
   * an appropriate format.
 | 
						|
   *
 | 
						|
   * @param out - the stream to write to
 | 
						|
   * @param doc - the source for the write
 | 
						|
   * @param pos - the location in the document to get the content.
 | 
						|
   * @param len - the amount to write out
 | 
						|
   * @throws IOException - on any I/O error
 | 
						|
   * @throws BadLocationException - if pos represents an invalid location
 | 
						|
   * within the document
 | 
						|
   */
 | 
						|
  public void write(Writer out, Document doc, int pos, int len)
 | 
						|
      throws IOException, BadLocationException
 | 
						|
  {
 | 
						|
    if (doc instanceof HTMLDocument)
 | 
						|
      {
 | 
						|
        HTMLWriter writer = new HTMLWriter(out, (HTMLDocument) doc, pos, len);
 | 
						|
        writer.write();
 | 
						|
      }
 | 
						|
    else if (doc instanceof StyledDocument)
 | 
						|
      {
 | 
						|
        MinimalHTMLWriter writer = new MinimalHTMLWriter(out,
 | 
						|
                                                         (StyledDocument) doc,
 | 
						|
                                                         pos, len);
 | 
						|
        writer.write();
 | 
						|
      }
 | 
						|
    else
 | 
						|
      super.write(out, doc, pos, len);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the content type that the kit supports.
 | 
						|
   * This kit supports the type text/html.
 | 
						|
   *
 | 
						|
   * @returns the content type supported.
 | 
						|
   */
 | 
						|
  public String getContentType()
 | 
						|
  {
 | 
						|
    return contentType;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a copy of the editor kit.
 | 
						|
   *
 | 
						|
   * @return a copy of this.
 | 
						|
   */
 | 
						|
  public Object clone()
 | 
						|
  {
 | 
						|
    // FIXME: Need to clone all fields
 | 
						|
    HTMLEditorKit copy = (HTMLEditorKit) super.clone();
 | 
						|
    copy.linkController = new LinkController();
 | 
						|
    return copy;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Copies the key/values in elements AttributeSet into set.
 | 
						|
   * This does not copy component, icon, or element names attributes.
 | 
						|
   * This is called anytime the caret moves over a different location.
 | 
						|
   *
 | 
						|
   * @param element - the element to create the input attributes for.
 | 
						|
   * @param set - the set to copy the values into.
 | 
						|
   */
 | 
						|
  protected void createInputAttributes(Element element,
 | 
						|
                                       MutableAttributeSet set)
 | 
						|
  {
 | 
						|
    set.removeAttributes(set);
 | 
						|
    set.addAttributes(element.getAttributes());
 | 
						|
    // FIXME: Not fully implemented.
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Called when this is installed into the JEditorPane.
 | 
						|
   *
 | 
						|
   * @param c - the JEditorPane installed into.
 | 
						|
   */
 | 
						|
  public void install(JEditorPane c)
 | 
						|
  {
 | 
						|
    super.install(c);
 | 
						|
    c.addMouseListener(linkController);
 | 
						|
    c.addMouseMotionListener(linkController);
 | 
						|
    editorPane = c;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Called when the this is removed from the JEditorPane.
 | 
						|
   * It unregisters any listeners.
 | 
						|
   *
 | 
						|
   * @param c - the JEditorPane being removed from.
 | 
						|
   */
 | 
						|
  public void deinstall(JEditorPane c)
 | 
						|
  {
 | 
						|
    super.deinstall(c);
 | 
						|
    c.removeMouseListener(linkController);
 | 
						|
    c.removeMouseMotionListener(linkController);
 | 
						|
    editorPane = null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the AccessibleContext associated with this.
 | 
						|
   *
 | 
						|
   * @return the AccessibleContext for this.
 | 
						|
   */
 | 
						|
  public AccessibleContext getAccessibleContext()
 | 
						|
  {
 | 
						|
    // FIXME: Should return an instance of
 | 
						|
    // javax.swing.text.html.AccessibleHTML$RootHTMLAccessibleContext
 | 
						|
    // Not implemented yet.
 | 
						|
    return null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the action list. This list is supported by the superclass
 | 
						|
   * augmented by the collection of actions defined locally for style
 | 
						|
   * operations.
 | 
						|
   *
 | 
						|
   * @return an array of all the actions
 | 
						|
   */
 | 
						|
  public Action[] getActions()
 | 
						|
  {
 | 
						|
    return TextAction.augmentList(super.getActions(), defaultActions);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the default cursor.
 | 
						|
   *
 | 
						|
   * @return the default cursor
 | 
						|
   */
 | 
						|
  public Cursor getDefaultCursor()
 | 
						|
  {
 | 
						|
    if (defaultCursor == null)
 | 
						|
      defaultCursor = Cursor.getDefaultCursor();
 | 
						|
    return defaultCursor;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the cursor for links.
 | 
						|
   *
 | 
						|
   * @return the cursor for links.
 | 
						|
   */
 | 
						|
  public Cursor getLinkCursor()
 | 
						|
  {
 | 
						|
    if (linkCursor == null)
 | 
						|
      linkCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
 | 
						|
    return linkCursor;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Sets the Cursor for links.
 | 
						|
   *
 | 
						|
   * @param cursor - the new cursor for links.
 | 
						|
   */
 | 
						|
  public void setLinkCursor(Cursor cursor)
 | 
						|
  {
 | 
						|
    linkCursor = cursor;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Sets the default cursor.
 | 
						|
   *
 | 
						|
   * @param cursor - the new default cursor.
 | 
						|
   */
 | 
						|
  public void setDefaultCursor(Cursor cursor)
 | 
						|
  {
 | 
						|
    defaultCursor = cursor;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Gets the input attributes used for the styled editing actions.
 | 
						|
   *
 | 
						|
   * @return the attribute set
 | 
						|
   */
 | 
						|
  public MutableAttributeSet getInputAttributes()
 | 
						|
  {
 | 
						|
    return inputAttributes;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Get the set of styles currently being used to render the HTML elements.
 | 
						|
   * By default the resource specified by DEFAULT_CSS gets loaded, and is
 | 
						|
   * shared by all HTMLEditorKit instances.
 | 
						|
   *
 | 
						|
   * @return the style sheet.
 | 
						|
   */
 | 
						|
  public StyleSheet getStyleSheet()
 | 
						|
  {
 | 
						|
    if (styleSheet == null)
 | 
						|
      {
 | 
						|
        try
 | 
						|
          {
 | 
						|
            styleSheet = new StyleSheet();
 | 
						|
            Class<?> c = HTMLEditorKit.class;
 | 
						|
            InputStream in = c.getResourceAsStream(DEFAULT_CSS);
 | 
						|
            InputStreamReader r = new InputStreamReader(in);
 | 
						|
            styleSheet.loadRules(r,  null);
 | 
						|
            r.close();
 | 
						|
          }
 | 
						|
        catch (IOException ex)
 | 
						|
          {
 | 
						|
            throw new RuntimeException("No style available.", ex);
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return styleSheet;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Set the set of styles to be used to render the various HTML elements.
 | 
						|
   * These styles are specified in terms of CSS specifications. Each document
 | 
						|
   * produced by the kit will have a copy of the sheet which it can add the
 | 
						|
   * document specific styles to. By default, the StyleSheet specified is shared
 | 
						|
   * by all HTMLEditorKit instances.
 | 
						|
   *
 | 
						|
   * @param s - the new style sheet
 | 
						|
   */
 | 
						|
  public void setStyleSheet(StyleSheet s)
 | 
						|
  {
 | 
						|
    styleSheet = s;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns <code>true</code> when forms should be automatically submitted
 | 
						|
   * by the editor kit. Set this to <code>false</code> when you want to
 | 
						|
   * intercept form submission. In this case you'd want to listen for
 | 
						|
   * hyperlink events on the document and handle FormSubmitEvents specially.
 | 
						|
   *
 | 
						|
   * The default is <code>true</code>.
 | 
						|
   *
 | 
						|
   * @return <code>true</code> when forms should be automatically submitted
 | 
						|
   *         by the editor kit, <code>false</code> otherwise
 | 
						|
   *
 | 
						|
   * @since 1.5
 | 
						|
   *
 | 
						|
   * @see #setAutoFormSubmission(boolean)
 | 
						|
   * @see FormSubmitEvent
 | 
						|
   */
 | 
						|
  public boolean isAutoFormSubmission()
 | 
						|
  {
 | 
						|
    return autoFormSubmission;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Sets whether or not the editor kit should automatically submit forms.
 | 
						|
   *
 | 
						|
   * @param auto <code>true</code> when the editor kit should handle form
 | 
						|
   *        submission, <code>false</code> otherwise
 | 
						|
   *
 | 
						|
   * @since 1.5
 | 
						|
   *
 | 
						|
   * @see #isAutoFormSubmission()
 | 
						|
   */
 | 
						|
  public void setAutoFormSubmission(boolean auto)
 | 
						|
  {
 | 
						|
    autoFormSubmission = auto;
 | 
						|
  }
 | 
						|
}
 |