OSDN Git Service

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