Source for javax.swing.text.html.HTMLEditorKit

   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:           else if (tag.equals(HTML.Tag.IMG))
 552:             view = new ImageView(element);
 553:           
 554:           // FIXME: Uncomment when the views have been implemented
 555:           else if (tag.equals(HTML.Tag.CONTENT))
 556:             view = new InlineView(element);
 557:           else if (tag == HTML.Tag.HEAD)
 558:             view = new NullView(element);
 559:           else if (tag.equals(HTML.Tag.TABLE))
 560:             view = new HTMLTableView(element);
 561:           else if (tag.equals(HTML.Tag.TD))
 562:             view = new ParagraphView(element);
 563:             
 564: 
 565:           /*
 566:           else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR)
 567:                    || tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL))
 568:             view = new ListView(element);
 569:           else if (tag.equals(HTML.Tag.HR))
 570:             view = new HRuleView(element);
 571:           else if (tag.equals(HTML.Tag.BR))
 572:             view = new BRView(element);
 573:           else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT)
 574:                    || tag.equals(HTML.Tag.TEXTAREA))
 575:             view = new FormView(element);
 576:           else if (tag.equals(HTML.Tag.OBJECT))
 577:             view = new ObjectView(element);
 578:           else if (tag.equals(HTML.Tag.FRAMESET))
 579:             view = new FrameSetView(element);
 580:           else if (tag.equals(HTML.Tag.FRAME))
 581:             view = new FrameView(element); */
 582:         }
 583:       if (view == null)
 584:         {
 585:           System.err.println("missing tag->view mapping for: " + element);
 586:           view = new NullView(element);
 587:         }
 588:       return view;
 589:     }
 590:   }
 591:   
 592:   /**
 593:    * The abstract HTML parser declaration.
 594:    */
 595:   public abstract static class Parser
 596:   {
 597:     /**
 598:      * Parse the HTML text, calling various methods of the provided callback
 599:      * in response to the occurence of the corresponding HTML constructions.
 600:      * @param reader The reader to read the source HTML from.
 601:      * @param callback The callback to receive information about the parsed
 602:      * HTML structures
 603:      * @param ignoreCharSet If true, the parser ignores all charset information
 604:      * that may be present in HTML documents.
 605:      * @throws IOException, normally if the reader throws one.
 606:      */
 607:     public abstract void parse(Reader reader, ParserCallback callback,
 608:                                boolean ignoreCharSet) throws IOException;
 609:   }
 610: 
 611:   /**
 612:    * The "hook" that receives all information about the HTML document
 613:    * structure while parsing it. The methods are invoked by parser
 614:    * and should be normally overridden.
 615:    */
 616:   public static class ParserCallback
 617:   {
 618:     /**
 619:      * If the tag does not occurs in the html stream directly, but
 620:      * is supposed by parser, the tag attribute set contains this additional
 621:      * attribute, having value Boolean.True.
 622:      */
 623:     public static final Object IMPLIED = "_implied_";
 624: 
 625:     /**
 626:      * Constructor
 627:      */
 628:     public ParserCallback()
 629:     {
 630:       // Nothing to do here.
 631:     }
 632:     
 633:     /**
 634:      * The parser calls this method after it finishes parsing the document.
 635:      */
 636:     public void flush() throws BadLocationException
 637:     {
 638:       // Nothing to do here.
 639:     }
 640: 
 641:     /**
 642:      * Handle HTML comment, present in the given position.
 643:      * @param comment the comment
 644:      * @position the position of the comment in the text being parsed.
 645:      */
 646:     public void handleComment(char[] comment, int position)
 647:     {
 648:       // Nothing to do here.
 649:     }
 650: 
 651:     /**
 652:      * Notifies about the character sequences, used to separate lines in
 653:      * this document. The parser calls this method after it finishes
 654:      * parsing the document, but before flush().
 655:      * @param end_of_line The "end of line sequence", one of: \r or \n or \r\n.
 656:      */
 657:     public void handleEndOfLineString(String end_of_line)
 658:     {
 659:       // Nothing to do here.
 660:     }
 661: 
 662:     /**
 663:      * The method is called when the HTML closing tag ((like &lt;/table&gt;)
 664:      * is found or if the parser concludes that the one should be present
 665:      * in the current position.
 666:      * @param tag The tag being handled
 667:      * @param position the tag position in the text being parsed.
 668:      */
 669:     public void handleEndTag(HTML.Tag tag, int position)
 670:     {
 671:       // Nothing to do here.
 672:     }
 673: 
 674:     /**
 675:      * Handle the error.
 676:      * @param message The message, explaining the error.
 677:      * @param position The starting position of the fragment that has caused
 678:      * the error in the html document being parsed.
 679:      */
 680:     public void handleError(String message, int position)
 681:     {
 682:       // Nothing to do here.
 683:     }
 684: 
 685:     /**
 686:      * Handle the tag with no content, like &lt;br&gt;. The method is
 687:      * called for the elements that, in accordance with the current DTD,
 688:      * has an empty content.
 689:      * @param tag The tag being handled.
 690:      * @param position The tag position in the text being parsed.
 691:      */
 692:     public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes,
 693:                                 int position)
 694:     {
 695:       // Nothing to do here.
 696:     }
 697: 
 698:     /**
 699:      * The method is called when the HTML opening tag ((like &lt;table&gt;)
 700:      * is found or if the parser concludes that the one should be present
 701:      * in the current position.
 702:      * @param tag The tag being handled
 703:      * @param position The tag position in the text being parsed
 704:      */
 705:     public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes,
 706:                                int position)
 707:     {
 708:       // Nothing to do here.
 709:     }
 710: 
 711:     /**
 712:      * Handle the text section.
 713:      * @param text A section text.
 714:      * @param position The text position in the HTML document text being parsed.
 715:      */
 716:     public void handleText(char[] text, int position)
 717:     {
 718:       // Nothing to do here.
 719:     }
 720:   }
 721: 
 722:   /**
 723:    * Use serialVersionUID (v1.4) for interoperability.
 724:    */
 725:   private static final long serialVersionUID = 8751997116710384592L;
 726: 
 727:   /**
 728:    * Default cascading stylesheed file ("default.css").
 729:    */
 730:   public static final String DEFAULT_CSS = "default.css";
 731: 
 732:   /**
 733:    * The <b>bold</b> action identifier.
 734:    */
 735:   public static final String BOLD_ACTION = "html-bold-action";
 736: 
 737:   /**
 738:    * The <i>italic</i> action identifier.
 739:    */
 740:   public static final String ITALIC_ACTION = "html-italic-action";
 741: 
 742:   /**
 743:    * The <font color="#FF0000">color</font> action indentifier
 744:    * (passing the color as an argument).
 745:    */
 746:   public static final String COLOR_ACTION = "html-color-action";
 747: 
 748:   /**
 749:    * The <font size="+1">increase</font> font action identifier.
 750:    */
 751:   public static final String FONT_CHANGE_BIGGER = "html-font-bigger";
 752: 
 753:   /**
 754:    * The <font size="-1">decrease</font> font action identifier.
 755:    */
 756:   public static final String FONT_CHANGE_SMALLER = "html-font-smaller";
 757: 
 758:   /**
 759:    * Align images at the bottom.
 760:    */
 761:   public static final String IMG_ALIGN_BOTTOM = "html-image-align-bottom";
 762: 
 763:   /**
 764:    * Align images at the middle.
 765:    */
 766:   public static final String IMG_ALIGN_MIDDLE = "html-image-align-middle";
 767: 
 768:   /**
 769:    * Align images at the top.
 770:    */
 771:   public static final String IMG_ALIGN_TOP = "html-image-align-top";
 772: 
 773:   /**
 774:    * Align images at the border.
 775:    */
 776:   public static final String IMG_BORDER = "html-image-border";
 777: 
 778:   /**
 779:    * The "logical style" action identifier, passing that style as parameter.
 780:    */
 781:   public static final String LOGICAL_STYLE_ACTION = "html-logical-style-action";
 782: 
 783:   /**
 784:    * The "ident paragraph left" action.
 785:    */
 786:   public static final String PARA_INDENT_LEFT = "html-para-indent-left";
 787: 
 788:   /**
 789:    * The "ident paragraph right" action.
 790:    */
 791:   public static final String PARA_INDENT_RIGHT = "html-para-indent-right";
 792:   
 793:   /**
 794:    * Actions for HTML 
 795:    */
 796:   private static final Action[] defaultActions = {
 797:     // FIXME: Add default actions for html
 798:   };
 799:   
 800:   /**
 801:    * The current style sheet.
 802:    */
 803:   StyleSheet styleSheet;
 804:   
 805:   /**
 806:    * The ViewFactory for HTMLFactory.
 807:    */
 808:   HTMLFactory viewFactory;
 809:   
 810:   /**
 811:    * The Cursor for links.
 812:    */
 813:   Cursor linkCursor;
 814:   
 815:   /**
 816:    * The default cursor.
 817:    */
 818:   Cursor defaultCursor;
 819:   
 820:   /**
 821:    * The parser.
 822:    */
 823:   Parser parser;
 824:   
 825:   /**
 826:    * The mouse listener used for links.
 827:    */
 828:   LinkController mouseListener;
 829:   
 830:   /**
 831:    * Style context for this editor.
 832:    */
 833:   StyleContext styleContext;
 834:   
 835:   /** The content type */
 836:   String contentType = "text/html";
 837:   
 838:   /** The input attributes defined by default.css */
 839:   MutableAttributeSet inputAttributes;
 840:   
 841:   /** The editor pane used. */
 842:   JEditorPane editorPane;
 843:     
 844:   /**
 845:    * Constructs an HTMLEditorKit, creates a StyleContext, and loads the style sheet.
 846:    */
 847:   public HTMLEditorKit()
 848:   {
 849:     super();    
 850:     styleContext = new StyleContext();
 851:     styleSheet = new StyleSheet();
 852:     styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS));
 853:     // FIXME: Set inputAttributes with default.css    
 854:   }
 855:   
 856:   /**
 857:    * Gets a factory suitable for producing views of any 
 858:    * models that are produced by this kit.
 859:    * 
 860:    * @return the view factory suitable for producing views.
 861:    */
 862:   public ViewFactory getViewFactory()
 863:   {
 864:     if (viewFactory == null)
 865:       viewFactory = new HTMLFactory();
 866:     return viewFactory;
 867:   }
 868:   
 869:   /**
 870:    * Create a text storage model for this type of editor.
 871:    *
 872:    * @return the model
 873:    */
 874:   public Document createDefaultDocument()
 875:   {
 876:     HTMLDocument document = new HTMLDocument(getStyleSheet());
 877:     document.setParser(getParser());
 878:     return document;
 879:   }
 880: 
 881:   /**
 882:    * Get the parser that this editor kit uses for reading HTML streams. This
 883:    * method can be overridden to use the alternative parser.
 884:    * 
 885:    * @return the HTML parser (by default, {@link ParserDelegator}).
 886:    */
 887:   protected Parser getParser()
 888:   {
 889:     if (parser == null)
 890:       parser = new ParserDelegator();
 891:     return parser;
 892:   }
 893:   
 894:   /**
 895:    * Inserts HTML into an existing document.
 896:    * 
 897:    * @param doc - the Document to insert the HTML into.
 898:    * @param offset - where to begin inserting the HTML.
 899:    * @param html - the String to insert
 900:    * @param popDepth - the number of ElementSpec.EndTagTypes 
 901:    * to generate before inserting
 902:    * @param pushDepth - the number of ElementSpec.StartTagTypes 
 903:    * with a direction of ElementSpec.JoinNextDirection that 
 904:    * should be generated before
 905:    * @param insertTag - the first tag to start inserting into document
 906:    * @throws IOException - on any I/O error
 907:    * @throws BadLocationException - if pos represents an invalid location
 908:    * within the document
 909:    */
 910:   public void insertHTML(HTMLDocument doc, int offset, String html,
 911:                          int popDepth, int pushDepth, HTML.Tag insertTag)
 912:       throws BadLocationException, IOException
 913:   {
 914:     Parser parser = getParser();
 915:     if (offset < 0 || offset > doc.getLength())
 916:       throw new BadLocationException("Bad location", offset);
 917:     if (parser == null)
 918:       throw new IOException("Parser is null.");
 919: 
 920:     ParserCallback pc = ((HTMLDocument) doc).getReader
 921:                           (offset, popDepth, pushDepth, insertTag);
 922: 
 923:     // FIXME: What should ignoreCharSet be set to?
 924:     
 925:     // parser.parse inserts html into the buffer
 926:     parser.parse(new StringReader(html), pc, false);
 927:     pc.flush();
 928:   }
 929:   
 930:   /**
 931:    * Inserts content from the given stream. Inserting HTML into a non-empty 
 932:    * document must be inside the body Element, if you do not insert into 
 933:    * the body an exception will be thrown. When inserting into a non-empty 
 934:    * document all tags outside of the body (head, title) will be dropped.
 935:    * 
 936:    * @param in - the stream to read from
 937:    * @param doc - the destination for the insertion
 938:    * @param pos - the location in the document to place the content
 939:    * @throws IOException - on any I/O error
 940:    * @throws BadLocationException - if pos represents an invalid location
 941:    * within the document
 942:    */
 943:   public void read(Reader in, Document doc, int pos) throws IOException,
 944:       BadLocationException
 945:   {
 946:     if (doc instanceof HTMLDocument)
 947:       {
 948:         Parser parser = getParser();
 949:         if (pos < 0 || pos > doc.getLength())
 950:           throw new BadLocationException("Bad location", pos);
 951:         if (parser == null)
 952:           throw new IOException("Parser is null.");
 953:         
 954:         HTMLDocument hd = ((HTMLDocument) doc);
 955:         if (editorPane != null)
 956:           hd.setBase(editorPane.getPage());
 957:         ParserCallback pc = hd.getReader(pos);
 958:         
 959:         // FIXME: What should ignoreCharSet be set to?
 960:         
 961:         // parser.parse inserts html into the buffer
 962:         parser.parse(in, pc, false);
 963:         pc.flush();
 964:       }
 965:     else
 966:       // read in DefaultEditorKit is called.
 967:       // the string is inserted in the document as usual.
 968:       super.read(in, doc, pos);
 969:   }
 970:   
 971:   /**
 972:    * Writes content from a document to the given stream in 
 973:    * an appropriate format.
 974:    * 
 975:    * @param out - the stream to write to
 976:    * @param doc - the source for the write
 977:    * @param pos - the location in the document to get the content.
 978:    * @param len - the amount to write out
 979:    * @throws IOException - on any I/O error
 980:    * @throws BadLocationException - if pos represents an invalid location
 981:    * within the document
 982:    */
 983:   public void write(Writer out, Document doc, int pos, int len)
 984:       throws IOException, BadLocationException
 985:   {
 986:     if (doc instanceof HTMLDocument)
 987:       {
 988:         // FIXME: Not implemented. Use HTMLWriter.
 989:         out.write(doc.getText(pos, len));
 990:       }
 991:     else
 992:       super.write(out, doc, pos, len);
 993:   }
 994:   
 995:   /**
 996:    * Gets the content type that the kit supports.
 997:    * This kit supports the type text/html.
 998:    * 
 999:    * @returns the content type supported.
1000:    */
1001:   public String getContentType()
1002:   {
1003:     return contentType;
1004:   } 
1005:   
1006:   /**
1007:    * Creates a copy of the editor kit.
1008:    * 
1009:    * @return a copy of this.
1010:    */
1011:   public Object clone()
1012:   {
1013:     // FIXME: Need to clone all fields
1014:     return (HTMLEditorKit) super.clone();
1015:   }
1016:   
1017:   /**
1018:    * Copies the key/values in elements AttributeSet into set. 
1019:    * This does not copy component, icon, or element names attributes.
1020:    * This is called anytime the caret moves over a different location. 
1021:    * 
1022:    * @param element - the element to create the input attributes for.
1023:    * @param set - the set to copy the values into.
1024:    */
1025:   protected void createInputAttributes(Element element,
1026:                                        MutableAttributeSet set)
1027:   {
1028:     set.removeAttributes(set);
1029:     set.addAttributes(element.getAttributes());
1030:     // FIXME: Not fully implemented.
1031:   }
1032:   
1033:   /**
1034:    * Called when this is installed into the JEditorPane.
1035:    * 
1036:    * @param c - the JEditorPane installed into.
1037:    */
1038:   public void install(JEditorPane c)
1039:   {
1040:     super.install(c);
1041:     mouseListener = new LinkController();
1042:     c.addMouseListener(mouseListener);
1043:     editorPane = c;
1044:     // FIXME: need to set up hyperlinklistener object
1045:   }
1046:   
1047:   /**
1048:    * Called when the this is removed from the JEditorPane.
1049:    * It unregisters any listeners.
1050:    * 
1051:    * @param c - the JEditorPane being removed from.
1052:    */
1053:   public void deinstall(JEditorPane c)
1054:   {
1055:     super.deinstall(c);
1056:     c.removeMouseListener(mouseListener);
1057:     mouseListener = null;
1058:     editorPane = null;
1059:   }
1060:   
1061:   /**
1062:    * Gets the AccessibleContext associated with this.
1063:    * 
1064:    * @return the AccessibleContext for this.
1065:    */
1066:   public AccessibleContext getAccessibleContext()
1067:   {
1068:     // FIXME: Should return an instance of 
1069:     // javax.swing.text.html.AccessibleHTML$RootHTMLAccessibleContext
1070:     // Not implemented yet.
1071:     return null;
1072:   }
1073:   
1074:   /**
1075:    * Gets the action list. This list is supported by the superclass
1076:    * augmented by the collection of actions defined locally for style
1077:    * operations.
1078:    * 
1079:    * @return an array of all the actions
1080:    */
1081:   public Action[] getActions()
1082:   {
1083:     return TextAction.augmentList(super.getActions(), defaultActions);
1084:   }
1085:   
1086:   /**
1087:    * Returns the default cursor.
1088:    * 
1089:    * @return the default cursor
1090:    */
1091:   public Cursor getDefaultCursor()
1092:   {
1093:     if (defaultCursor == null)
1094:       defaultCursor = Cursor.getDefaultCursor();
1095:     return defaultCursor;
1096:   }
1097:   
1098:   /**
1099:    * Returns the cursor for links.
1100:    * 
1101:    * @return the cursor for links.
1102:    */
1103:   public Cursor getLinkCursor()
1104:   {
1105:     if (linkCursor == null)
1106:       linkCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
1107:     return linkCursor;
1108:   }
1109:   
1110:   /**
1111:    * Sets the Cursor for links.
1112:    * 
1113:    * @param cursor - the new cursor for links.
1114:    */
1115:   public void setLinkCursor(Cursor cursor)
1116:   {
1117:     linkCursor = cursor;
1118:   }
1119:   
1120:   /**
1121:    * Sets the default cursor.
1122:    * 
1123:    * @param cursor - the new default cursor.
1124:    */
1125:   public void setDefaultCursor(Cursor cursor)
1126:   {
1127:     defaultCursor = cursor;
1128:   }
1129:   
1130:   /**
1131:    * Gets the input attributes used for the styled editing actions.
1132:    * 
1133:    * @return the attribute set
1134:    */
1135:   public MutableAttributeSet getInputAttributes()
1136:   {
1137:     return inputAttributes;
1138:   }
1139:   
1140:   /**
1141:    * Get the set of styles currently being used to render the HTML elements. 
1142:    * By default the resource specified by DEFAULT_CSS gets loaded, and is 
1143:    * shared by all HTMLEditorKit instances.
1144:    * 
1145:    * @return the style sheet.
1146:    */
1147:   public StyleSheet getStyleSheet()
1148:   {
1149:     if (styleSheet == null)
1150:       {
1151:         styleSheet = new StyleSheet();
1152:         styleSheet.importStyleSheet(getClass().getResource(DEFAULT_CSS));
1153:       }
1154:     return styleSheet;
1155:   }
1156:   
1157:   /**
1158:    * Set the set of styles to be used to render the various HTML elements. 
1159:    * These styles are specified in terms of CSS specifications. Each document 
1160:    * produced by the kit will have a copy of the sheet which it can add the 
1161:    * document specific styles to. By default, the StyleSheet specified is shared 
1162:    * by all HTMLEditorKit instances. 
1163:    * 
1164:    * @param s - the new style sheet
1165:    */
1166:   public void setStyleSheet(StyleSheet s)
1167:   {
1168:     styleSheet = s;
1169:   }
1170: }