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:           
 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: }