OSDN Git Service

Imported GNU Classpath 0.20
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / swing / text / html / HTMLEditorKit.java
1 /* HTMLEditorKit.java --
2    Copyright (C) 2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.swing.text.html;
40
41
42 import java.awt.event.ActionEvent;
43 import java.awt.event.MouseAdapter;
44 import java.awt.event.MouseEvent;
45 import java.awt.event.MouseMotionListener;
46 import java.awt.Cursor;
47
48 import java.io.IOException;
49 import java.io.Reader;
50 import java.io.Serializable;
51 import java.io.StringReader;
52 import java.io.Writer;
53
54 import javax.accessibility.Accessible;
55 import javax.accessibility.AccessibleContext;
56
57 import javax.swing.Action;
58 import javax.swing.JEditorPane;
59 import javax.swing.text.AbstractDocument;
60 import javax.swing.text.BadLocationException;
61 import javax.swing.text.BoxView;
62 import javax.swing.text.ComponentView;
63 import javax.swing.text.Document;
64 import javax.swing.text.EditorKit;
65 import javax.swing.text.Element;
66 import javax.swing.text.IconView;
67 import javax.swing.text.LabelView;
68 import javax.swing.text.MutableAttributeSet;
69 import javax.swing.text.ParagraphView;
70 import javax.swing.text.StyleConstants;
71 import javax.swing.text.StyleContext;
72 import javax.swing.text.StyledEditorKit;
73 import javax.swing.text.TextAction;
74 import javax.swing.text.View;
75 import javax.swing.text.ViewFactory;
76 import javax.swing.text.html.parser.ParserDelegator;
77
78 /**
79  * @author Lillian Angel (langel at redhat dot com)
80  */
81 public class HTMLEditorKit
82   extends StyledEditorKit
83   implements Serializable, Cloneable, Accessible
84 {
85   
86   /**
87    * Fires the hyperlink events on the associated component
88    * when needed.
89    */
90   public static class LinkController
91     extends MouseAdapter
92     implements MouseMotionListener, Serializable
93     {
94       
95       /**
96        * Constructor
97        */
98       public LinkController() 
99       {
100         super();
101       }
102       
103       /**
104        * Dispatched when the mouse is clicked. If the component
105        * is read-only, then the clicked event is used to drive an
106        * attempt to follow the reference specified by a link
107        * 
108        * @param e - the mouse event
109        */
110       public void mouseClicked(MouseEvent e)
111       {
112         /*
113          These MouseInputAdapter methods generate mouse appropriate events around
114          hyperlinks (entering, exiting, and activating).
115          */
116         // FIXME: Not implemented.
117       }
118       
119       /**
120        * Dispatched when the mouse is dragged on a component.
121        * 
122        * @param e - the mouse event.
123        */
124       public void mouseDragged(MouseEvent e)
125       {
126         /*
127         These MouseInputAdapter methods generate mouse appropriate events around
128         hyperlinks (entering, exiting, and activating).
129         */
130         // FIXME: Not implemented.     
131       }
132       
133       /**
134        * Dispatched when the mouse cursor has moved into the component.
135        * 
136        * @param e - the mouse event.
137        */
138       public void mouseMoved(MouseEvent e)
139       {
140         /*
141         These MouseInputAdapter methods generate mouse appropriate events around
142         hyperlinks (entering, exiting, and activating).
143         */
144         // FIXME: Not implemented.
145       }
146       
147       /**
148        * If the given position represents a link, then linkActivated is called
149        * on the JEditorPane. Implemented to forward to the method with the same
150        * name, but pos == editor == -1.
151        * 
152        * @param pos - the position
153        * @param editor - the editor pane
154        */
155       protected void activateLink(int pos,
156                                   JEditorPane editor)
157       {
158         /*
159           This method creates and fires a HyperlinkEvent if the document is an
160           instance of HTMLDocument and the href tag of the link is not null.
161          */
162         // FIXME: Not implemented.
163       }
164     }
165   
166   /**
167    * This class is used to insert a string of HTML into an existing
168    * document. At least 2 HTML.Tags need to be supplied. The first Tag (parentTag)
169    * identifies the parent in the document to add the elements to. The second, (addTag), 
170    * identifies that the first tag should be added to the document as seen in the string.
171    * The parser will generate all appropriate (opening/closing tags_ even if they are not
172    * in the HTML string passed in.
173    */
174   public static class InsertHTMLTextAction
175     extends HTMLTextAction
176     {
177       
178       /**
179        * Tag in HTML to start adding tags from.
180        */
181       protected HTML.Tag addTag;
182       
183       /**
184        * Alternate tag in HTML to start adding tags from if parentTag is
185        * not found and alternateParentTag is not found.
186        */      
187       protected HTML.Tag alternateAddTag;
188       
189       /**
190        * Alternate tag to check if parentTag is not found.
191        */
192       protected HTML.Tag alternateParentTag;
193       
194       /**
195        * HTML to insert.
196        */
197       protected String html;
198       
199       /**
200        * Tag to check for in the document.
201        */
202       protected HTML.Tag parentTag;
203       
204       /**
205        * Initializes all fields.
206        * 
207        * @param name - the name of the document.
208        * @param html - the html to insert
209        * @param parentTag - the parent tag to check for
210        * @param addTag - the tag to start adding from
211        */
212       public InsertHTMLTextAction(String name, String html, 
213                                   HTML.Tag parentTag, HTML.Tag addTag)
214       {
215         this(name, html, parentTag, addTag, null, null);
216       }
217       
218       /**
219        * Initializes all fields and calls super
220        * 
221        * @param name - the name of the document.
222        * @param html - the html to insert
223        * @param parentTag - the parent tag to check for
224        * @param addTag - the tag to start adding from
225        * @param alternateParentTag - the alternate parent tag
226        * @param alternateAddTag - the alternate add tag
227        */
228       public InsertHTMLTextAction(String name, String html, HTML.Tag parentTag, 
229                                   HTML.Tag addTag, HTML.Tag alternateParentTag, 
230                                   HTML.Tag alternateAddTag) 
231       {
232         super(name);
233         // Fields are for easy access when the action is applied to an actual
234         // document.
235         this.html = html;
236         this.parentTag = parentTag;
237         this.addTag = addTag;
238         this.alternateParentTag = alternateParentTag;
239         this.alternateAddTag = alternateAddTag;
240       }
241       
242       /**
243        * HTMLEditorKit.insertHTML is called. If an exception is
244        * thrown, it is wrapped in a RuntimeException and thrown.
245        * 
246        * @param editor - the editor to use to get the editorkit
247        * @param doc -
248        *          the Document to insert the HTML into.
249        * @param offset -
250        *          where to begin inserting the HTML.
251        * @param html -
252        *          the String to insert
253        * @param popDepth -
254        *          the number of ElementSpec.EndTagTypes to generate before
255        *          inserting
256        * @param pushDepth -
257        *          the number of ElementSpec.StartTagTypes with a direction of
258        *          ElementSpec.JoinNextDirection that should be generated before
259        * @param addTag -
260        *          the first tag to start inserting into document
261        */
262       protected void insertHTML(JEditorPane editor, HTMLDocument doc, int offset,
263                               String html, int popDepth, int pushDepth,
264                               HTML.Tag addTag)
265       {
266         try
267           {
268             super.getHTMLEditorKit(editor).insertHTML(doc, offset, html,
269                                                       popDepth, pushDepth, addTag);
270           }
271         catch (IOException e)
272           {
273             throw (RuntimeException) new RuntimeException("Parser is null.").initCause(e);
274           }
275         catch (BadLocationException ex)
276           {
277             throw (RuntimeException) new RuntimeException("BadLocationException: "
278                                               + offset).initCause(ex);
279           }
280       }
281       
282       /**
283        * Invoked when inserting at a boundary. Determines the number of pops,
284        * and then the number of pushes that need to be performed. The it calls
285        * insertHTML.
286        * 
287        * @param editor -
288        *          the editor to use to get the editorkit
289        * @param doc -
290        *          the Document to insert the HTML into.
291        * @param offset -
292        *          where to begin inserting the HTML.
293        * @param insertElement -
294        *          the element to insert
295        * @param html -
296        *          the html to insert
297        * @param parentTag -
298        *          the parent tag
299        * @param addTag -
300        *          the first tag
301        */
302       protected void insertAtBoundary(JEditorPane editor,
303                                       HTMLDocument doc, int offset,
304                                       Element insertElement,
305                                       String html, HTML.Tag parentTag,
306                                       HTML.Tag addTag)
307       {
308         /*
309         As its name implies, this protected method is used when HTML is inserted at a
310         boundary. (A boundary in this case is an offset in doc that exactly matches the
311         beginning offset of the parentTag.) It performs the extra work required to keep
312         the tag stack in shape and then calls insertHTML(). The editor and doc argu-
313         ments are the editor pane and document where the HTML should go. The offset
314         argument represents the cursor location or selection start in doc. The insert-
315         Element and parentTag arguments are used to calculate the proper number of
316         tag pops and pushes before inserting the HTML (via html and addTag, which are
317         passed directly to insertHTML()).
318         */
319         // FIXME: not implemented
320       }
321       
322       /**
323        * Invoked when inserting at a boundary. Determines the number of pops, 
324        * and then the number of pushes that need to be performed. The it calls
325        * insertHTML.
326        * 
327        * @param editor - the editor to use to get the editorkit
328        * @param doc -
329        *          the Document to insert the HTML into.
330        * @param offset -
331        *          where to begin inserting the HTML.
332        * @param insertElement - the element to insert
333        * @param html - the html to insert
334        * @param parentTag - the parent tag
335        * @param addTag - the first tag
336        * 
337        * @deprecated as of v1.3, use insertAtBoundary
338        */
339       protected void insertAtBoundry(JEditorPane editor,
340                                      HTMLDocument doc,
341                                      int offset, Element insertElement,
342                                      String html, HTML.Tag parentTag,
343                                      HTML.Tag addTag)
344       {
345         insertAtBoundary(editor, doc, offset, insertElement,
346                          html, parentTag, addTag);
347       }
348       
349       /**
350        * Inserts the HTML.
351        * 
352        * @param ae - the action performed
353        */
354       public void actionPerformed(ActionEvent ae)
355       {
356         Object source = ae.getSource();
357         if (source instanceof JEditorPane)
358           {
359             JEditorPane pane = ((JEditorPane) source);
360             Document d = pane.getDocument();
361             if (d instanceof HTMLDocument)
362               insertHTML(pane, (HTMLDocument) d, 0, html, 0, 0, addTag);
363             // FIXME: is this correct parameters?
364           }
365         // FIXME: else not implemented
366       }
367   }
368   
369   /**
370    * Abstract Action class that helps inserting HTML into an existing document.
371    */
372   public abstract static class HTMLTextAction
373     extends StyledEditorKit.StyledTextAction
374     {
375       
376       /**
377        * Constructor
378        */
379       public HTMLTextAction(String name) 
380       {
381         super(name);
382       }
383       
384       /**
385        * Gets the HTMLDocument from the JEditorPane.
386        * 
387        * @param e - the editor pane
388        * @return the html document.
389        */
390       protected HTMLDocument getHTMLDocument(JEditorPane e)
391       {
392         Document d = e.getDocument();
393         if (d instanceof HTMLDocument)
394           return (HTMLDocument) d;
395         throw new IllegalArgumentException("Document is not a HTMLDocument.");
396       }
397       
398       /**
399        * Gets the HTMLEditorKit
400        *  
401        * @param e - the JEditorPane to get the HTMLEditorKit from.
402        * @return the HTMLEditorKit
403        */
404       protected HTMLEditorKit getHTMLEditorKit(JEditorPane e) 
405       {
406         EditorKit d = e.getEditorKit();
407         if (d instanceof HTMLEditorKit)
408           return (HTMLEditorKit) d;
409         throw new IllegalArgumentException("EditorKit is not a HTMLEditorKit.");
410       }
411       
412       /**
413        * Returns an array of Elements that contain the offset.
414        * The first elements corresponds to the roots of the doc.
415        * 
416        * @param doc - the document to get the Elements from.
417        * @param offset - the offset the Elements must contain
418        * @return an array of all the elements containing the offset.
419        */
420       protected Element[] getElementsAt(HTMLDocument doc,
421                                         int offset)
422       {
423         return getElementsAt(doc.getDefaultRootElement(), offset, 0);
424       }
425       
426       /**
427        * Helper function to get all elements using recursion.
428        */
429       private Element[] getElementsAt(Element root, int offset, int depth)
430       {
431         Element[] elements = null;
432         if (root != null)
433           {
434             if (root.isLeaf())
435               {
436                 elements = new Element[depth + 1];
437                 elements[depth] = root;
438                 return elements;
439               }
440             elements = getElementsAt(root.getElement(root.getElementIndex(offset)),
441                                      offset, depth + 1);
442             elements[depth] = root;
443           }
444         return elements;
445       }
446       
447       /**
448        * Returns the number of elements, starting at the deepest point, needed
449        * to get an element representing tag. -1 if no elements are found, 0 if
450        * the parent of the leaf at offset represents the tag.
451        * 
452        * @param doc -
453        *          the document to search
454        * @param offset -
455        *          the offset to check
456        * @param tag -
457        *          the tag to look for
458        * @return - the number of elements needed to get an element representing
459        *         tag.
460        */
461       protected int elementCountToTag(HTMLDocument doc,
462                                       int offset, HTML.Tag tag)
463       {
464         Element root = doc.getDefaultRootElement();
465         int num = -1;
466         Element next = root.getElement(root.getElementIndex(offset));
467         
468         while (!next.isLeaf())
469           {
470             num++;
471             if (next.getAttributes().
472                 getAttribute(StyleConstants.NameAttribute).equals(tag))
473               return num;
474             next = next.getElement(next.getElementIndex(offset));
475           }
476         return num;
477       }
478       
479       /**
480        * Gets the deepest element at offset with the
481        * matching tag.
482        * 
483        * @param doc - the document to search
484        * @param offset - the offset to check for
485        * @param tag - the tag to match
486        * @return - the element that is found, null if not found.
487        */
488       protected Element findElementMatchingTag(HTMLDocument doc,
489                                                int offset, HTML.Tag tag)
490       {
491         Element element = doc.getDefaultRootElement();
492         Element tagElement = null;
493         
494         while (element != null)
495           {
496             Object otag = element.getAttributes().getAttribute(
497                                      StyleConstants.NameAttribute);
498             if (otag instanceof HTML.Tag && otag.equals(tag))
499               tagElement = element;
500             element = element.getElement(element.getElementIndex(offset));
501           }
502         
503         return tagElement;
504       }
505     }
506   
507   /**
508    * A {@link ViewFactory} that is able to create {@link View}s for
509    * the <code>Element</code>s that are supported.
510    */
511   public static class HTMLFactory
512     implements ViewFactory
513   {
514     
515     /**
516      * Constructor
517      */
518     public HTMLFactory()
519     {
520       // Do Nothing here.
521     }
522     
523     /**
524      * Creates a {@link View} for the specified <code>Element</code>.
525      *
526      * @param element the <code>Element</code> to create a <code>View</code>
527      *        for
528      * @return the <code>View</code> for the specified <code>Element</code>
529      *         or <code>null</code> if the type of <code>element</code> is
530      *         not supported
531      */
532     public View create(Element element)
533     {
534       View view = null;
535       Object attr = element.getAttributes().getAttribute(
536                                 StyleConstants.NameAttribute);
537       if (attr instanceof HTML.Tag)
538         {
539           HTML.Tag tag = (HTML.Tag) attr;
540
541           if (tag.equals(HTML.Tag.IMPLIED) || tag.equals(HTML.Tag.P)
542               || tag.equals(HTML.Tag.H1) || tag.equals(HTML.Tag.H2)
543               || tag.equals(HTML.Tag.H3) || tag.equals(HTML.Tag.H4)
544               || tag.equals(HTML.Tag.H5) || tag.equals(HTML.Tag.H6)
545               || tag.equals(HTML.Tag.DT))
546             view = new ParagraphView(element);
547           else if (tag.equals(HTML.Tag.LI) || tag.equals(HTML.Tag.DL)
548                    || tag.equals(HTML.Tag.DD) || tag.equals(HTML.Tag.BODY)
549                    || tag.equals(HTML.Tag.HTML) || tag.equals(HTML.Tag.CENTER)
550                    || tag.equals(HTML.Tag.DIV)
551                    || tag.equals(HTML.Tag.BLOCKQUOTE)
552                    || tag.equals(HTML.Tag.PRE))
553             view = new BlockView(element, View.Y_AXIS);
554           
555           // FIXME: Uncomment when the views have been implemented
556          /* else if (tag.equals(HTML.Tag.CONTENT))
557             view = new InlineView(element); 
558           else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR)
559                    || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL))
560             view = new ListView(element);
561           else if (tag.equals(HTML.Tag.IMG))
562             view = new ImageView(element);
563           else if (tag.equals(HTML.Tag.HR))
564             view = new HRuleView(element);
565           else if (tag.equals(HTML.Tag.BR))
566             view = new BRView(element);
567           else if (tag.equals(HTML.Tag.TABLE))
568             view = new TableView(element);
569           else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT)
570                    || tag.equals(HTML.Tag.TEXTAREA))
571             view = new FormView(element);
572           else if (tag.equals(HTML.Tag.OBJECT))
573             view = new ObjectView(element);
574           else if (tag.equals(HTML.Tag.FRAMESET))
575             view = new FrameSetView(element);
576           else if (tag.equals(HTML.Tag.FRAME))
577             view = new FrameView(element); */
578         }      
579       
580       if (view == null)
581         {
582           String name = element.getName();
583           if (name.equals(AbstractDocument.ContentElementName))
584             view = new LabelView(element);
585           else if (name.equals(AbstractDocument.ParagraphElementName))
586             view = new ParagraphView(element);
587           else if (name.equals(AbstractDocument.SectionElementName))
588             view = new BoxView(element, View.Y_AXIS);
589           else if (name.equals(StyleConstants.ComponentElementName))
590             view = new ComponentView(element);
591           else if (name.equals(StyleConstants.IconElementName))
592             view = new IconView(element);
593         }
594       return view;
595     }
596   }
597   
598   /**
599    * The abstract HTML parser declaration.
600    */
601   public abstract static class Parser
602   {
603     /**
604      * Parse the HTML text, calling various methods of the provided callback
605      * in response to the occurence of the corresponding HTML constructions.
606      * @param reader The reader to read the source HTML from.
607      * @param callback The callback to receive information about the parsed
608      * HTML structures
609      * @param ignoreCharSet If true, the parser ignores all charset information
610      * that may be present in HTML documents.
611      * @throws IOException, normally if the reader throws one.
612      */
613     public abstract void parse(Reader reader, ParserCallback callback,
614                                boolean ignoreCharSet) throws IOException;
615   }
616
617   /**
618    * The "hook" that receives all information about the HTML document
619    * structure while parsing it. The methods are invoked by parser
620    * and should be normally overridden.
621    */
622   public static class ParserCallback
623   {
624     /**
625      * If the tag does not occurs in the html stream directly, but
626      * is supposed by parser, the tag attribute set contains this additional
627      * attribute, having value Boolean.True.
628      */
629     public static final Object IMPLIED = "_implied_";
630
631     /**
632      * Constructor
633      */
634     public ParserCallback()
635     {
636       // Nothing to do here.
637     }
638     
639     /**
640      * The parser calls this method after it finishes parsing the document.
641      */
642     public void flush() throws BadLocationException
643     {
644       // Nothing to do here.
645     }
646
647     /**
648      * Handle HTML comment, present in the given position.
649      * @param comment the comment
650      * @position the position of the comment in the text being parsed.
651      */
652     public void handleComment(char[] comment, int position)
653     {
654       // Nothing to do here.
655     }
656
657     /**
658      * Notifies about the character sequences, used to separate lines in
659      * this document. The parser calls this method after it finishes
660      * parsing the document, but before flush().
661      * @param end_of_line The "end of line sequence", one of: \r or \n or \r\n.
662      */
663     public void handleEndOfLineString(String end_of_line)
664     {
665       // Nothing to do here.
666     }
667
668     /**
669      * The method is called when the HTML closing tag ((like &lt;/table&gt;)
670      * is found or if the parser concludes that the one should be present
671      * in the current position.
672      * @param tag The tag being handled
673      * @param position the tag position in the text being parsed.
674      */
675     public void handleEndTag(HTML.Tag tag, int position)
676     {
677       // Nothing to do here.
678     }
679
680     /**
681      * Handle the error.
682      * @param message The message, explaining the error.
683      * @param position The starting position of the fragment that has caused
684      * the error in the html document being parsed.
685      */
686     public void handleError(String message, int position)
687     {
688       // Nothing to do here.
689     }
690
691     /**
692      * Handle the tag with no content, like &lt;br&gt;. The method is
693      * called for the elements that, in accordance with the current DTD,
694      * has an empty content.
695      * @param tag The tag being handled.
696      * @param position The tag position in the text being parsed.
697      */
698     public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes,
699                                 int position)
700     {
701       // Nothing to do here.
702     }
703
704     /**
705      * The method is called when the HTML opening tag ((like &lt;table&gt;)
706      * is found or if the parser concludes that the one should be present
707      * in the current position.
708      * @param tag The tag being handled
709      * @param position The tag position in the text being parsed
710      */
711     public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes,
712                                int position)
713     {
714       // Nothing to do here.
715     }
716
717     /**
718      * Handle the text section.
719      * @param text A section text.
720      * @param position The text position in the HTML document text being parsed.
721      */
722     public void handleText(char[] text, int position)
723     {
724       // Nothing to do here.
725     }
726   }
727
728   /**
729    * Use serialVersionUID (v1.4) for interoperability.
730    */
731   private static final long serialVersionUID = 8751997116710384592L;
732
733   /**
734    * Default cascading stylesheed file ("default.css").
735    */
736   public static final String DEFAULT_CSS = "default.css";
737
738   /**
739    * The <b>bold</b> action identifier.
740    */
741   public static final String BOLD_ACTION = "html-bold-action";
742
743   /**
744    * The <i>italic</i> action identifier.
745    */
746   public static final String ITALIC_ACTION = "html-italic-action";
747
748   /**
749    * The <font color="#FF0000">color</font> action indentifier
750    * (passing the color as an argument).
751    */
752   public static final String COLOR_ACTION = "html-color-action";
753
754   /**
755    * The <font size="+1">increase</font> font action identifier.
756    */
757   public static final String FONT_CHANGE_BIGGER = "html-font-bigger";
758
759   /**
760    * The <font size="-1">decrease</font> font action identifier.
761    */
762   public static final String FONT_CHANGE_SMALLER = "html-font-smaller";
763
764   /**
765    * Align images at the bottom.
766    */
767   public static final String IMG_ALIGN_BOTTOM = "html-image-align-bottom";
768
769   /**
770    * Align images at the middle.
771    */
772   public static final String IMG_ALIGN_MIDDLE = "html-image-align-middle";
773
774   /**
775    * Align images at the top.
776    */
777   public static final String IMG_ALIGN_TOP = "html-image-align-top";
778
779   /**
780    * Align images at the border.
781    */
782   public static final String IMG_BORDER = "html-image-border";
783
784   /**
785    * The "logical style" action identifier, passing that style as parameter.
786    */
787   public static final String LOGICAL_STYLE_ACTION = "html-logical-style-action";
788
789   /**
790    * The "ident paragraph left" action.
791    */
792   public static final String PARA_INDENT_LEFT = "html-para-indent-left";
793
794   /**
795    * The "ident paragraph right" action.
796    */
797   public static final String PARA_INDENT_RIGHT = "html-para-indent-right";
798   
799   /**
800    * Actions for HTML 
801    */
802   private static final Action[] defaultActions = {
803     // FIXME: Add default actions for html
804   };
805   
806   /**
807    * The current style sheet.
808    */
809   StyleSheet styleSheet;
810   
811   /**
812    * The ViewFactory for HTMLFactory.
813    */
814   HTMLFactory viewFactory;
815   
816   /**
817    * The Cursor for links.
818    */
819   Cursor linkCursor;
820   
821   /**
822    * The default cursor.
823    */
824   Cursor defaultCursor;
825   
826   /**
827    * The parser.
828    */
829   Parser parser;
830   
831   /**
832    * The mouse listener used for links.
833    */
834   LinkController mouseListener;
835   
836   /**
837    * Style context for this editor.
838    */
839   StyleContext styleContext;
840   
841   /** The content type */
842   String contentType = "text/html";
843   
844   /** The input attributes defined by default.css */
845   MutableAttributeSet inputAttributes;
846   
847   /** The editor pane used. */
848   JEditorPane editorPane;
849     
850   /**
851    * Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet.
852    */
853   public HTMLEditorKit()
854   {
855     super();    
856     styleContext = new StyleContext();
857     styleSheet = new StyleSheet();
858     styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS));
859     // FIXME: Set inputAttributes with default.css    
860   }
861   
862   /**
863    * Gets a factory suitable for producing views of any 
864    * models that are produced by this kit.
865    * 
866    * @return the view factory suitable for producing views.
867    */
868   public ViewFactory getViewFactory()
869   {
870     if (viewFactory == null)
871       viewFactory = new HTMLFactory();
872     return viewFactory;
873   }
874   
875   /**
876    * Create a text storage model for this type of editor.
877    *
878    * @return the model
879    */
880   public Document createDefaultDocument()
881   {
882     HTMLDocument document = new HTMLDocument(getStyleSheet());
883     document.setParser(getParser());
884     return document;
885   }
886
887   /**
888    * Get the parser that this editor kit uses for reading HTML streams. This
889    * method can be overridden to use the alternative parser.
890    * 
891    * @return the HTML parser (by default, {@link ParserDelegator}).
892    */
893   protected Parser getParser()
894   {
895     if (parser == null)
896       parser = new ParserDelegator();
897     return parser;
898   }
899   
900   /**
901    * Inserts HTML into an existing document.
902    * 
903    * @param doc - the Document to insert the HTML into.
904    * @param offset - where to begin inserting the HTML.
905    * @param html - the String to insert
906    * @param popDepth - the number of ElementSpec.EndTagTypes 
907    * to generate before inserting
908    * @param pushDepth - the number of ElementSpec.StartTagTypes 
909    * with a direction of ElementSpec.JoinNextDirection that 
910    * should be generated before
911    * @param insertTag - the first tag to start inserting into document
912    * @throws IOException - on any I/O error
913    * @throws BadLocationException - if pos represents an invalid location
914    * within the document
915    */
916   public void insertHTML(HTMLDocument doc, int offset, String html,
917                          int popDepth, int pushDepth, HTML.Tag insertTag)
918       throws BadLocationException, IOException
919   {
920     Parser parser = getParser();
921     if (offset < 0 || offset > doc.getLength())
922       throw new BadLocationException("Bad location", offset);
923     if (parser == null)
924       throw new IOException("Parser is null.");
925
926     ParserCallback pc = ((HTMLDocument) doc).getReader
927                           (offset, popDepth, pushDepth, insertTag);
928
929     // FIXME: What should ignoreCharSet be set to?
930     
931     // parser.parse inserts html into the buffer
932     parser.parse(new StringReader(html), pc, false);
933     pc.flush();
934   }
935   
936   /**
937    * Inserts content from the given stream. Inserting HTML into a non-empty 
938    * document must be inside the body Element, if you do not insert into 
939    * the body an exception will be thrown. When inserting into a non-empty 
940    * document all tags outside of the body (head, title) will be dropped.
941    * 
942    * @param in - the stream to read from
943    * @param doc - the destination for the insertion
944    * @param pos - the location in the document to place the content
945    * @throws IOException - on any I/O error
946    * @throws BadLocationException - if pos represents an invalid location
947    * within the document
948    */
949   public void read(Reader in, Document doc, int pos) throws IOException,
950       BadLocationException
951   {
952     if (doc instanceof HTMLDocument)
953       {
954         Parser parser = getParser();
955         if (pos < 0 || pos > doc.getLength())
956           throw new BadLocationException("Bad location", pos);
957         if (parser == null)
958           throw new IOException("Parser is null.");
959         
960         HTMLDocument hd = ((HTMLDocument) doc);
961         hd.setBase(editorPane.getPage());
962         ParserCallback pc = hd.getReader(pos);
963         
964         // FIXME: What should ignoreCharSet be set to?
965         
966         // parser.parse inserts html into the buffer
967         parser.parse(in, pc, false);
968         pc.flush();
969       }
970     else
971       // read in DefaultEditorKit is called.
972       // the string is inserted in the document as usual.
973       super.read(in, doc, pos);
974   }
975   
976   /**
977    * Writes content from a document to the given stream in 
978    * an appropriate format.
979    * 
980    * @param out - the stream to write to
981    * @param doc - the source for the write
982    * @param pos - the location in the document to get the content.
983    * @param len - the amount to write out
984    * @throws IOException - on any I/O error
985    * @throws BadLocationException - if pos represents an invalid location
986    * within the document
987    */
988   public void write(Writer out, Document doc, int pos, int len)
989       throws IOException, BadLocationException
990   {
991     if (doc instanceof HTMLDocument)
992       {
993         // FIXME: Not implemented. Use HTMLWriter.
994         out.write(doc.getText(pos, len));
995       }
996     else
997       super.write(out, doc, pos, len);
998   }
999   
1000   /**
1001    * Gets the content type that the kit supports.
1002    * This kit supports the type text/html.
1003    * 
1004    * @returns the content type supported.
1005    */
1006   public String getContentType()
1007   {
1008     return contentType;
1009   } 
1010   
1011   /**
1012    * Creates a copy of the editor kit.
1013    * 
1014    * @return a copy of this.
1015    */
1016   public Object clone()
1017   {
1018     // FIXME: Need to clone all fields
1019     return (HTMLEditorKit) super.clone();
1020   }
1021   
1022   /**
1023    * Copies the key/values in elements AttributeSet into set. 
1024    * This does not copy component, icon, or element names attributes.
1025    * This is called anytime the caret moves over a different location. 
1026    * 
1027    * @param element - the element to create the input attributes for.
1028    * @param set - the set to copy the values into.
1029    */
1030   protected void createInputAttributes(Element element,
1031                                        MutableAttributeSet set)
1032   {
1033     set.removeAttributes(set);
1034     set.addAttributes(element.getAttributes());
1035     // FIXME: Not fully implemented.
1036   }
1037   
1038   /**
1039    * Called when this is installed into the JEditorPane.
1040    * 
1041    * @param c - the JEditorPane installed into.
1042    */
1043   public void install(JEditorPane c)
1044   {
1045     super.install(c);
1046     mouseListener = new LinkController();
1047     c.addMouseListener(mouseListener);
1048     editorPane = c;
1049     // FIXME: need to set up hyperlinklistener object
1050   }
1051   
1052   /**
1053    * Called when the this is removed from the JEditorPane.
1054    * It unregisters any listeners.
1055    * 
1056    * @param c - the JEditorPane being removed from.
1057    */
1058   public void deinstall(JEditorPane c)
1059   {
1060     super.deinstall(c);
1061     c.removeMouseListener(mouseListener);
1062     mouseListener = null;
1063     editorPane = null;
1064   }
1065   
1066   /**
1067    * Gets the AccessibleContext associated with this.
1068    * 
1069    * @return the AccessibleContext for this.
1070    */
1071   public AccessibleContext getAccessibleContext()
1072   {
1073     // FIXME: Should return an instance of 
1074     // javax.swing.text.html.AccessibleHTML$RootHTMLAccessibleContext
1075     // Not implemented yet.
1076     return null;
1077   }
1078   
1079   /**
1080    * Gets the action list. This list is supported by the superclass
1081    * augmented by the collection of actions defined locally for style
1082    * operations.
1083    * 
1084    * @return an array of all the actions
1085    */
1086   public Action[] getActions()
1087   {
1088     return TextAction.augmentList(super.getActions(), defaultActions);
1089   }
1090   
1091   /**
1092    * Returns the default cursor.
1093    * 
1094    * @return the default cursor
1095    */
1096   public Cursor getDefaultCursor()
1097   {
1098     if (defaultCursor == null)
1099       defaultCursor = Cursor.getDefaultCursor();
1100     return defaultCursor;
1101   }
1102   
1103   /**
1104    * Returns the cursor for links.
1105    * 
1106    * @return the cursor for links.
1107    */
1108   public Cursor getLinkCursor()
1109   {
1110     if (linkCursor == null)
1111       linkCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
1112     return linkCursor;
1113   }
1114   
1115   /**
1116    * Sets the Cursor for links.
1117    * 
1118    * @param cursor - the new cursor for links.
1119    */
1120   public void setLinkCursor(Cursor cursor)
1121   {
1122     linkCursor = cursor;
1123   }
1124   
1125   /**
1126    * Sets the default cursor.
1127    * 
1128    * @param cursor - the new default cursor.
1129    */
1130   public void setDefaultCursor(Cursor cursor)
1131   {
1132     defaultCursor = cursor;
1133   }
1134   
1135   /**
1136    * Gets the input attributes used for the styled editing actions.
1137    * 
1138    * @return the attribute set
1139    */
1140   public MutableAttributeSet getInputAttributes()
1141   {
1142     return inputAttributes;
1143   }
1144   
1145   /**
1146    * Get the set of styles currently being used to render the HTML elements. 
1147    * By default the resource specified by DEFAULT_CSS gets loaded, and is 
1148    * shared by all HTMLEditorKit instances.
1149    * 
1150    * @return the style sheet.
1151    */
1152   public StyleSheet getStyleSheet()
1153   {
1154     if (styleSheet == null)
1155       {
1156         styleSheet = new StyleSheet();
1157         styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS));
1158       }
1159     return styleSheet;
1160   }
1161   
1162   /**
1163    * Set the set of styles to be used to render the various HTML elements. 
1164    * These styles are specified in terms of CSS specifications. Each document 
1165    * produced by the kit will have a copy of the sheet which it can add the 
1166    * document specific styles to. By default, the StyleSheet specified is shared 
1167    * by all HTMLEditorKit instances. 
1168    * 
1169    * @param s - the new style sheet
1170    */
1171   public void setStyleSheet(StyleSheet s)
1172   {
1173     styleSheet = s;
1174   }
1175 }