Source for javax.swing.text.html.HTMLDocument

   1: /* HTMLDocument.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: import gnu.classpath.NotImplementedException;
  42: import gnu.javax.swing.text.html.CharacterAttributeTranslator;
  43: 
  44: import java.io.IOException;
  45: import java.net.URL;
  46: import java.util.HashMap;
  47: import java.util.Stack;
  48: import java.util.Vector;
  49: 
  50: import javax.swing.JEditorPane;
  51: import javax.swing.text.AbstractDocument;
  52: import javax.swing.text.AttributeSet;
  53: import javax.swing.text.BadLocationException;
  54: import javax.swing.text.DefaultStyledDocument;
  55: import javax.swing.text.Element;
  56: import javax.swing.text.ElementIterator;
  57: import javax.swing.text.GapContent;
  58: import javax.swing.text.MutableAttributeSet;
  59: import javax.swing.text.SimpleAttributeSet;
  60: import javax.swing.text.StyleConstants;
  61: import javax.swing.text.html.HTML.Tag;
  62: 
  63: /**
  64:  * Represents the HTML document that is constructed by defining the text and
  65:  * other components (images, buttons, etc) in HTML language. This class can
  66:  * becomes the default document for {@link JEditorPane} after setting its
  67:  * content type to "text/html". HTML document also serves as an intermediate
  68:  * data structure when it is needed to parse HTML and then obtain the content of
  69:  * the certain types of tags. This class also has methods for modifying the HTML
  70:  * content.
  71:  * 
  72:  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
  73:  * @author Anthony Balkissoon (abalkiss@redhat.com)
  74:  * @author Lillian Angel (langel@redhat.com)
  75:  */
  76: public class HTMLDocument extends DefaultStyledDocument
  77: {
  78:   /** A key for document properies.  The value for the key is
  79:    * a Vector of Strings of comments not found in the body.
  80:    */  
  81:   public static final String AdditionalComments = "AdditionalComments";
  82:   URL baseURL = null;
  83:   boolean preservesUnknownTags = true;
  84:   int tokenThreshold = Integer.MAX_VALUE;
  85:   HTMLEditorKit.Parser parser;
  86:   StyleSheet styleSheet;
  87:   AbstractDocument.Content content;
  88:   
  89:   /**
  90:    * Constructs an HTML document using the default buffer size and a default
  91:    * StyleSheet.
  92:    */
  93:   public HTMLDocument()
  94:   {
  95:     this(null);
  96:   }
  97:   
  98:   /**
  99:    * Constructs an HTML document with the default content storage 
 100:    * implementation and the specified style/attribute storage mechanism.
 101:    * 
 102:    * @param styles - the style sheet
 103:    */
 104:   public HTMLDocument(StyleSheet styles)
 105:   {
 106:    this(new GapContent(BUFFER_SIZE_DEFAULT), styles);
 107:   }
 108:   
 109:   /**
 110:    * Constructs an HTML document with the given content storage implementation 
 111:    * and the given style/attribute storage mechanism.
 112:    * 
 113:    * @param c - the document's content
 114:    * @param styles - the style sheet
 115:    */
 116:   public HTMLDocument(AbstractDocument.Content c, StyleSheet styles)
 117:   {
 118:     this.content = c;
 119:     if (styles == null)
 120:       {
 121:         styles = new StyleSheet();
 122:         styles.importStyleSheet(getClass().getResource(HTMLEditorKit.
 123:                                                        DEFAULT_CSS));
 124:       }
 125:     this.styleSheet = styles;
 126:   }
 127:   
 128:   /**
 129:    * Gets the style sheet with the document display rules (CSS) that were specified 
 130:    * in the HTML document.
 131:    * 
 132:    * @return - the style sheet
 133:    */
 134:   public StyleSheet getStyleSheet()
 135:   {
 136:     return styleSheet;
 137:   }
 138:   
 139:   /**
 140:    * This method creates a root element for the new document.
 141:    * 
 142:    * @return the new default root
 143:    */
 144:   protected AbstractElement createDefaultRoot()
 145:   {
 146:     AbstractDocument.AttributeContext ctx = getAttributeContext();
 147: 
 148:     // Create html element.
 149:     AttributeSet atts = ctx.getEmptySet();
 150:     atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.HTML);
 151:     BranchElement html = (BranchElement) createBranchElement(null, atts);
 152: 
 153:     // Create body element.
 154:     atts = ctx.getEmptySet();
 155:     atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.BODY);
 156:     BranchElement body = (BranchElement) createBranchElement(html, atts);
 157:     html.replace(0, 0, new Element[] { body });
 158: 
 159:     // Create p element.
 160:     atts = ctx.getEmptySet();
 161:     atts = ctx.addAttribute(atts, StyleConstants.NameAttribute, HTML.Tag.P);
 162:     BranchElement p = (BranchElement) createBranchElement(body, atts);
 163:     body.replace(0, 0, new Element[] { p });
 164: 
 165:     // Create an empty leaf element.
 166:     atts = ctx.getEmptySet();
 167:     atts = ctx.addAttribute(atts, StyleConstants.NameAttribute,
 168:                             HTML.Tag.CONTENT);
 169:     Element leaf = createLeafElement(p, atts, 0, 1);
 170:     p.replace(0, 0, new Element[]{ leaf });
 171: 
 172:     return html;
 173:   }
 174:   
 175:   /**
 176:    * This method returns an HTMLDocument.RunElement object attached to
 177:    * parent representing a run of text from p0 to p1. The run has 
 178:    * attributes described by a.
 179:    * 
 180:    * @param parent - the parent element
 181:    * @param a - the attributes for the element
 182:    * @param p0 - the beginning of the range >= 0
 183:    * @param p1 - the end of the range >= p0
 184:    *
 185:    * @return the new element
 186:    */
 187:   protected Element createLeafElement(Element parent, AttributeSet a, int p0,
 188:                                       int p1)
 189:   {
 190:     RunElement el = new RunElement(parent, a, p0, p1);
 191:     el.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT);
 192:     return new RunElement(parent, a, p0, p1);
 193:   }
 194: 
 195:   /**
 196:    * This method returns an HTMLDocument.BlockElement object representing the
 197:    * attribute set a and attached to parent.
 198:    * 
 199:    * @param parent - the parent element
 200:    * @param a - the attributes for the element
 201:    *
 202:    * @return the new element
 203:    */
 204:   protected Element createBranchElement(Element parent, AttributeSet a)
 205:   {
 206:     return new BlockElement(parent, a);
 207:   }
 208:   
 209:   /**
 210:    * Returns the parser used by this HTMLDocument to insert HTML.
 211:    * 
 212:    * @return the parser used by this HTMLDocument to insert HTML.
 213:    */
 214:   public HTMLEditorKit.Parser getParser()
 215:   {
 216:     return parser; 
 217:   }
 218:   
 219:   /**
 220:    * Sets the parser used by this HTMLDocument to insert HTML.
 221:    * 
 222:    * @param p the parser to use
 223:    */
 224:   public void setParser (HTMLEditorKit.Parser p)
 225:   {
 226:     parser = p;
 227:   }
 228:   /**
 229:    * Sets the number of tokens to buffer before trying to display the
 230:    * Document.
 231:    * 
 232:    * @param n the number of tokens to buffer
 233:    */
 234:   public void setTokenThreshold (int n)
 235:   {
 236:     tokenThreshold = n;
 237:   }
 238:   
 239:   /**
 240:    * Returns the number of tokens that are buffered before the document
 241:    * is rendered.
 242:    * 
 243:    * @return the number of tokens buffered
 244:    */
 245:   public int getTokenThreshold ()
 246:   {
 247:     return tokenThreshold;
 248:   }
 249:   
 250:   /**
 251:    * Returns the location against which to resolve relative URLs.
 252:    * This is the document's URL if the document was loaded from a URL.
 253:    * If a <code>base</code> tag is found, it will be used.
 254:    * @return the base URL
 255:    */
 256:   public URL getBase()
 257:   {
 258:     return baseURL;
 259:   }
 260:   
 261:   /**
 262:    * Sets the location against which to resolve relative URLs.
 263:    * @param u the new base URL
 264:    */
 265:   public void setBase(URL u)
 266:   {
 267:     baseURL = u;
 268:     styleSheet.setBase(u);
 269:   }
 270:   
 271:   /**
 272:    * Returns whether or not the parser preserves unknown HTML tags.
 273:    * @return true if the parser preserves unknown tags
 274:    */
 275:   public boolean getPreservesUnknownTags()
 276:   {
 277:     return preservesUnknownTags;
 278:   }
 279:   
 280:   /**
 281:    * Sets the behaviour of the parser when it encounters unknown HTML tags.
 282:    * @param preservesTags true if the parser should preserve unknown tags.
 283:    */
 284:   public void setPreservesUnknownTags(boolean preservesTags)
 285:   {
 286:     preservesUnknownTags = preservesTags;
 287:   }
 288:   
 289:   /**
 290:    * An iterator to iterate through LeafElements in the document.
 291:    */
 292:   class LeafIterator extends Iterator
 293:   {
 294:     HTML.Tag tag;
 295:     HTMLDocument doc;
 296:     ElementIterator it;
 297: 
 298:     public LeafIterator (HTML.Tag t, HTMLDocument d)
 299:     {
 300:       doc = d;
 301:       tag = t;
 302:       it = new ElementIterator(doc);
 303:     }
 304:     
 305:     /**
 306:      * Return the attributes for the tag associated with this iteartor
 307:      * @return the AttributeSet
 308:      */
 309:     public AttributeSet getAttributes()
 310:     {
 311:       if (it.current() != null)
 312:         return it.current().getAttributes();
 313:       return null;
 314:     }
 315: 
 316:     /**
 317:      * Get the end of the range for the current occurrence of the tag
 318:      * being defined and having the same attributes.
 319:      * @return the end of the range
 320:      */
 321:     public int getEndOffset()
 322:     {
 323:       if (it.current() != null)
 324:         return it.current().getEndOffset();
 325:       return -1;
 326:     }
 327: 
 328:     /**
 329:      * Get the start of the range for the current occurrence of the tag
 330:      * being defined and having the same attributes.
 331:      * @return the start of the range (-1 if it can't be found).
 332:      */
 333: 
 334:     public int getStartOffset()
 335:     {
 336:       if (it.current() != null)
 337:         return it.current().getStartOffset();
 338:       return -1;
 339:     }
 340: 
 341:     /**
 342:      * Advance the iterator to the next LeafElement .
 343:      */
 344:     public void next()
 345:     {
 346:       it.next();
 347:       while (it.current()!= null && !it.current().isLeaf())
 348:         it.next();
 349:     }
 350: 
 351:     /**
 352:      * Indicates whether or not the iterator currently represents an occurrence
 353:      * of the tag.
 354:      * @return true if the iterator currently represents an occurrence of the
 355:      * tag.
 356:      */
 357:     public boolean isValid()
 358:     {
 359:       return it.current() != null;
 360:     }
 361: 
 362:     /**
 363:      * Type of tag for this iterator.
 364:      */
 365:     public Tag getTag()
 366:     {
 367:       return tag;
 368:     }
 369: 
 370:   }
 371: 
 372:   public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event)
 373:   throws NotImplementedException
 374:   {
 375:     // TODO: Implement this properly.
 376:   }
 377:   
 378:   /**
 379:    * Gets an iterator for the given HTML.Tag.
 380:    * @param t the requested HTML.Tag
 381:    * @return the Iterator
 382:    */
 383:   public HTMLDocument.Iterator getIterator (HTML.Tag t)
 384:   {
 385:     return new HTMLDocument.LeafIterator(t, this);
 386:   }
 387:   
 388:   /**
 389:    * An iterator over a particular type of tag.
 390:    */
 391:   public abstract static class Iterator
 392:   {
 393:     /**
 394:      * Return the attribute set for this tag.
 395:      * @return the <code>AttributeSet</code> (null if none found).
 396:      */
 397:     public abstract AttributeSet getAttributes();
 398:     
 399:     /**
 400:      * Get the end of the range for the current occurrence of the tag
 401:      * being defined and having the same attributes.
 402:      * @return the end of the range
 403:      */
 404:     public abstract int getEndOffset();
 405:     
 406:     /**
 407:      * Get the start of the range for the current occurrence of the tag
 408:      * being defined and having the same attributes.
 409:      * @return the start of the range (-1 if it can't be found).
 410:      */
 411:     public abstract int getStartOffset();
 412:     
 413:     /**
 414:      * Move the iterator forward.
 415:      */
 416:     public abstract void next();
 417:     
 418:     /**
 419:      * Indicates whether or not the iterator currently represents an occurrence
 420:      * of the tag.
 421:      * @return true if the iterator currently represents an occurrence of the
 422:      * tag.
 423:      */
 424:     public abstract boolean isValid();
 425:     
 426:     /**
 427:      * Type of tag this iterator represents.
 428:      * @return the tag.
 429:      */
 430:     public abstract HTML.Tag getTag();
 431:   }
 432:   
 433:   public class BlockElement extends AbstractDocument.BranchElement
 434:   {
 435:     public BlockElement (Element parent, AttributeSet a)
 436:     {
 437:       super(parent, a);
 438:     }
 439:     
 440:     /**
 441:      * Gets the resolving parent.  Since HTML attributes are not 
 442:      * inherited at the model level, this returns null.
 443:      */
 444:     public AttributeSet getResolveParent()
 445:     {
 446:       return null;
 447:     }
 448:     
 449:     /**
 450:      * Gets the name of the element.
 451:      * 
 452:      * @return the name of the element if it exists, null otherwise.
 453:      */
 454:     public String getName()
 455:     {
 456:       Object tag = getAttribute(StyleConstants.NameAttribute);
 457:       String name = null;
 458:       if (tag != null)
 459:         name = tag.toString();
 460:       return name;
 461:     }
 462:   }
 463: 
 464:   /**
 465:    * RunElement represents a section of text that has a set of 
 466:    * HTML character level attributes assigned to it.
 467:    */
 468:   public class RunElement extends AbstractDocument.LeafElement
 469:   {
 470:     
 471:     /**
 472:      * Constructs an element that has no children. It represents content
 473:      * within the document.
 474:      * 
 475:      * @param parent - parent of this
 476:      * @param a - elements attributes
 477:      * @param start - the start offset >= 0
 478:      * @param end - the end offset 
 479:      */
 480:     public RunElement(Element parent, AttributeSet a, int start, int end)
 481:     {
 482:       super(parent, a, start, end);
 483:     }
 484:     
 485:     /**
 486:      * Gets the name of the element.
 487:      * 
 488:      * @return the name of the element if it exists, null otherwise.
 489:      */
 490:     public String getName()
 491:     {
 492:       Object tag = getAttribute(StyleConstants.NameAttribute);
 493:       String name = null;
 494:       if (tag != null)
 495:         name = tag.toString();
 496:       return name;
 497:     }
 498:     
 499:     /**
 500:      * Gets the resolving parent. HTML attributes do not inherit at the
 501:      * model level, so this method returns null.
 502:      * 
 503:      * @return null
 504:      */
 505:     public AttributeSet getResolveParent()
 506:     {
 507:       return null;
 508:     }
 509:   }
 510:   
 511:   /**
 512:    * A reader to load an HTMLDocument with HTML structure.
 513:    * 
 514:    * @author Anthony Balkissoon abalkiss at redhat dot com
 515:    */
 516:   public class HTMLReader extends HTMLEditorKit.ParserCallback
 517:   {    
 518:     /** Holds the current character attribute set **/
 519:     protected MutableAttributeSet charAttr = new SimpleAttributeSet();
 520:     
 521:     protected Vector parseBuffer = new Vector();
 522:     
 523:     /** A stack for character attribute sets **/
 524:     Stack charAttrStack = new Stack();
 525: 
 526:     /**
 527:      * The parse stack. This stack holds HTML.Tag objects that reflect the
 528:      * current position in the parsing process.
 529:      */
 530:     private Stack parseStack = new Stack();
 531:    
 532:     /** A mapping between HTML.Tag objects and the actions that handle them **/
 533:     HashMap tagToAction;
 534:     
 535:     /** Tells us whether we've received the '</html>' tag yet **/
 536:     boolean endHTMLEncountered = false;
 537:     
 538:     /** Variables related to the constructor with explicit insertTag **/
 539:     int popDepth, pushDepth, offset;
 540:     HTML.Tag insertTag;
 541:     boolean insertTagEncountered = false;
 542:     
 543:     /** A temporary variable that helps with the printing out of debug information **/
 544:     boolean debug = false;
 545:     
 546:     void print (String line)
 547:     {
 548:       if (debug)
 549:         System.out.println (line);
 550:     }
 551:     
 552:     public class TagAction
 553:     {
 554:       /**
 555:        * This method is called when a start tag is seen for one of the types
 556:        * of tags associated with this Action.  By default this does nothing.
 557:        */
 558:       public void start(HTML.Tag t, MutableAttributeSet a)
 559:       {
 560:         // Nothing to do here.
 561:       }
 562:       
 563:       /**
 564:        * Called when an end tag is seen for one of the types of tags associated
 565:        * with this Action.  By default does nothing.
 566:        */
 567:       public void end(HTML.Tag t)
 568:       {
 569:         // Nothing to do here.
 570:       }
 571:     }
 572: 
 573:     public class BlockAction extends TagAction
 574:     {      
 575:       /**
 576:        * This method is called when a start tag is seen for one of the types
 577:        * of tags associated with this Action.
 578:        */
 579:       public void start(HTML.Tag t, MutableAttributeSet a)
 580:       {
 581:         // Tell the parse buffer to open a new block for this tag.
 582:         blockOpen(t, a);
 583:       }
 584:       
 585:       /**
 586:        * Called when an end tag is seen for one of the types of tags associated
 587:        * with this Action.
 588:        */
 589:       public void end(HTML.Tag t)
 590:       {
 591:         // Tell the parse buffer to close this block.
 592:         blockClose(t);
 593:       }
 594:     }
 595:     
 596:     public class CharacterAction extends TagAction
 597:     {
 598:       /**
 599:        * This method is called when a start tag is seen for one of the types
 600:        * of tags associated with this Action.
 601:        */
 602:       public void start(HTML.Tag t, MutableAttributeSet a)
 603:       {
 604:         // Put the old attribute set on the stack.
 605:         pushCharacterStyle();
 606: 
 607:     // Translate tag.. return if succesful.
 608:     if(CharacterAttributeTranslator.translateTag(charAttr, t, a))
 609:       return;
 610: 
 611:         // Just add the attributes in <code>a</code>.
 612:      if (a != null)
 613:        charAttr.addAttribute(t, a.copyAttributes());          
 614:       }
 615: 
 616:       /**
 617:        * Called when an end tag is seen for one of the types of tags associated
 618:        * with this Action.
 619:        */
 620:       public void end(HTML.Tag t)
 621:       {
 622:         popCharacterStyle();
 623:       } 
 624:     }
 625:     
 626:     public class FormAction extends SpecialAction
 627:     {
 628:       /**
 629:        * This method is called when a start tag is seen for one of the types
 630:        * of tags associated with this Action.
 631:        */
 632:       public void start(HTML.Tag t, MutableAttributeSet a)
 633:         throws NotImplementedException
 634:       {
 635:         // FIXME: Implement.
 636:         print ("FormAction.start not implemented");
 637:       }
 638:       
 639:       /**
 640:        * Called when an end tag is seen for one of the types of tags associated
 641:        * with this Action.
 642:        */
 643:       public void end(HTML.Tag t)
 644:         throws NotImplementedException
 645:       {
 646:         // FIXME: Implement.
 647:         print ("FormAction.end not implemented");
 648:       } 
 649:     }
 650:     
 651:     /**
 652:      * This action indicates that the content between starting and closing HTML
 653:      * elements (like script - /script) should not be visible. The content is
 654:      * still inserted and can be accessed when iterating the HTML document. The
 655:      * parser will only fire
 656:      * {@link javax.swing.text.html.HTMLEditorKit.ParserCallback#handleText} for
 657:      * the hidden tags, regardless from that html tags the hidden section may
 658:      * contain.
 659:      */
 660:     public class HiddenAction
 661:         extends TagAction
 662:     {
 663:       /**
 664:        * This method is called when a start tag is seen for one of the types
 665:        * of tags associated with this Action.
 666:        */
 667:       public void start(HTML.Tag t, MutableAttributeSet a)
 668:       {
 669:         blockOpen(t, a);
 670:       }
 671:       
 672:       /**
 673:        * Called when an end tag is seen for one of the types of tags associated
 674:        * with this Action.
 675:        */
 676:       public void end(HTML.Tag t)
 677:       {
 678:         blockClose(t);
 679:       } 
 680:     }
 681:     
 682:     public class IsindexAction extends TagAction
 683:     {
 684:       /**
 685:        * This method is called when a start tag is seen for one of the types
 686:        * of tags associated with this Action.
 687:        */
 688:       public void start(HTML.Tag t, MutableAttributeSet a)
 689:         throws NotImplementedException
 690:       {
 691:         // FIXME: Implement.
 692:         print ("IsindexAction.start not implemented");
 693:       }
 694:     }
 695:     
 696:     public class ParagraphAction extends BlockAction
 697:     {
 698:       /**
 699:        * This method is called when a start tag is seen for one of the types
 700:        * of tags associated with this Action.
 701:        */
 702:       public void start(HTML.Tag t, MutableAttributeSet a)
 703:       {
 704:         blockOpen(t, a);
 705:       }
 706:       
 707:       /**
 708:        * Called when an end tag is seen for one of the types of tags associated
 709:        * with this Action.
 710:        */
 711:       public void end(HTML.Tag t)
 712:       {
 713:         blockClose(t);
 714:       } 
 715:     }
 716:     
 717:     public class PreAction extends BlockAction
 718:     {
 719:       /**
 720:        * This method is called when a start tag is seen for one of the types
 721:        * of tags associated with this Action.
 722:        */
 723:       public void start(HTML.Tag t, MutableAttributeSet a)
 724:         throws NotImplementedException
 725:       {
 726:         // FIXME: Implement.
 727:         print ("PreAction.start not implemented");
 728:         super.start(t, a);
 729:       }
 730:       
 731:       /**
 732:        * Called when an end tag is seen for one of the types of tags associated
 733:        * with this Action.
 734:        */
 735:       public void end(HTML.Tag t)
 736:         throws NotImplementedException
 737:       {
 738:         // FIXME: Implement.
 739:         print ("PreAction.end not implemented");
 740:         super.end(t);
 741:       } 
 742:     }
 743:     
 744:     /**
 745:      * Inserts the elements that are represented by ths single tag with 
 746:      * attributes (only). The closing tag, even if present, mut follow
 747:      * immediately after the starting tag without providing any additional
 748:      * information. Hence the {@link TagAction#end} method need not be
 749:      * overridden and still does nothing.
 750:      */
 751:     public class SpecialAction extends TagAction
 752:     {
 753:       /**
 754:        * The functionality is delegated to {@link HTMLReader#addSpecialElement}
 755:        */
 756:       public void start(HTML.Tag t, MutableAttributeSet a)
 757:       {
 758:         addSpecialElement(t, a);
 759:       }
 760:     }
 761:     
 762:     class AreaAction extends TagAction
 763:     {
 764:       /**
 765:        * This method is called when a start tag is seen for one of the types
 766:        * of tags associated with this Action.
 767:        */
 768:       public void start(HTML.Tag t, MutableAttributeSet a)
 769:         throws NotImplementedException
 770:       {
 771:         // FIXME: Implement.
 772:         print ("AreaAction.start not implemented");
 773:       }
 774:       
 775:       /**
 776:        * Called when an end tag is seen for one of the types of tags associated
 777:        * with this Action.
 778:        */
 779:       public void end(HTML.Tag t)
 780:         throws NotImplementedException
 781:       {
 782:         // FIXME: Implement.
 783:         print ("AreaAction.end not implemented");
 784:       } 
 785:     }
 786:     
 787:     class BaseAction extends TagAction
 788:     {
 789:       /**
 790:        * This method is called when a start tag is seen for one of the types
 791:        * of tags associated with this Action.
 792:        */
 793:       public void start(HTML.Tag t, MutableAttributeSet a)
 794:         throws NotImplementedException
 795:       {
 796:         // FIXME: Implement.
 797:         print ("BaseAction.start not implemented");
 798:       }
 799:       
 800:       /**
 801:        * Called when an end tag is seen for one of the types of tags associated
 802:        * with this Action.
 803:        */
 804:       public void end(HTML.Tag t)
 805:         throws NotImplementedException
 806:       {
 807:         // FIXME: Implement.
 808:         print ("BaseAction.end not implemented");
 809:       } 
 810:     }
 811:     
 812:     class HeadAction extends BlockAction
 813:     {
 814:       /**
 815:        * This method is called when a start tag is seen for one of the types
 816:        * of tags associated with this Action.
 817:        */
 818:       public void start(HTML.Tag t, MutableAttributeSet a)
 819:         throws NotImplementedException
 820:       {
 821:         // FIXME: Implement.
 822:         print ("HeadAction.start not implemented: "+t);
 823:         super.start(t, a);
 824:       }
 825:       
 826:       /**
 827:        * Called when an end tag is seen for one of the types of tags associated
 828:        * with this Action.
 829:        */
 830:       public void end(HTML.Tag t)
 831:         throws NotImplementedException
 832:       {
 833:         // FIXME: Implement.
 834:         print ("HeadAction.end not implemented: "+t);
 835:         super.end(t);
 836:       } 
 837:     }
 838:     
 839:     class LinkAction extends TagAction
 840:     {
 841:       /**
 842:        * This method is called when a start tag is seen for one of the types
 843:        * of tags associated with this Action.
 844:        */
 845:       public void start(HTML.Tag t, MutableAttributeSet a)
 846:         throws NotImplementedException
 847:       {
 848:         // FIXME: Implement.
 849:         print ("LinkAction.start not implemented");
 850:       }
 851:       
 852:       /**
 853:        * Called when an end tag is seen for one of the types of tags associated
 854:        * with this Action.
 855:        */
 856:       public void end(HTML.Tag t)
 857:         throws NotImplementedException
 858:       {
 859:         // FIXME: Implement.
 860:         print ("LinkAction.end not implemented");
 861:       } 
 862:     }
 863:     
 864:     class MapAction extends TagAction
 865:     {
 866:       /**
 867:        * This method is called when a start tag is seen for one of the types
 868:        * of tags associated with this Action.
 869:        */
 870:       public void start(HTML.Tag t, MutableAttributeSet a)
 871:         throws NotImplementedException
 872:       {
 873:         // FIXME: Implement.
 874:         print ("MapAction.start not implemented");
 875:       }
 876:       
 877:       /**
 878:        * Called when an end tag is seen for one of the types of tags associated
 879:        * with this Action.
 880:        */
 881:       public void end(HTML.Tag t)
 882:         throws NotImplementedException
 883:       {
 884:         // FIXME: Implement.
 885:         print ("MapAction.end not implemented");
 886:       } 
 887:     }
 888:     
 889:     class MetaAction extends TagAction
 890:     {
 891:       /**
 892:        * This method is called when a start tag is seen for one of the types
 893:        * of tags associated with this Action.
 894:        */
 895:       public void start(HTML.Tag t, MutableAttributeSet a)
 896:         throws NotImplementedException
 897:       {
 898:         // FIXME: Implement.
 899:         print ("MetaAction.start not implemented");
 900:       }
 901:       
 902:       /**
 903:        * Called when an end tag is seen for one of the types of tags associated
 904:        * with this Action.
 905:        */
 906:       public void end(HTML.Tag t)
 907:         throws NotImplementedException
 908:       {
 909:         // FIXME: Implement.
 910:         print ("MetaAction.end not implemented");
 911:       } 
 912:     }
 913:     
 914:     class StyleAction extends TagAction
 915:     {
 916:       /**
 917:        * This method is called when a start tag is seen for one of the types
 918:        * of tags associated with this Action.
 919:        */
 920:       public void start(HTML.Tag t, MutableAttributeSet a)
 921:         throws NotImplementedException
 922:       {
 923:         // FIXME: Implement.
 924:         print ("StyleAction.start not implemented");
 925:       }
 926:       
 927:       /**
 928:        * Called when an end tag is seen for one of the types of tags associated
 929:        * with this Action.
 930:        */
 931:       public void end(HTML.Tag t)
 932:         throws NotImplementedException
 933:       {
 934:         // FIXME: Implement.
 935:         print ("StyleAction.end not implemented");
 936:       } 
 937:     }
 938:     
 939:     class TitleAction extends TagAction
 940:     {
 941:       /**
 942:        * This method is called when a start tag is seen for one of the types
 943:        * of tags associated with this Action.
 944:        */
 945:       public void start(HTML.Tag t, MutableAttributeSet a)
 946:         throws NotImplementedException
 947:       {
 948:         // FIXME: Implement.
 949:         print ("TitleAction.start not implemented");
 950:       }
 951:       
 952:       /**
 953:        * Called when an end tag is seen for one of the types of tags associated
 954:        * with this Action.
 955:        */
 956:       public void end(HTML.Tag t)
 957:         throws NotImplementedException
 958:       {
 959:         // FIXME: Implement.
 960:         print ("TitleAction.end not implemented");
 961:       } 
 962:     }    
 963:     
 964:     public HTMLReader(int offset)
 965:     {
 966:       this (offset, 0, 0, null);
 967:     }
 968:     
 969:     public HTMLReader(int offset, int popDepth, int pushDepth,
 970:                       HTML.Tag insertTag)
 971:     {
 972:       print ("HTMLReader created with pop: "+popDepth
 973:                           + " push: "+pushDepth + " offset: "+offset
 974:                           + " tag: "+insertTag);
 975:       this.insertTag = insertTag;
 976:       this.offset = offset;
 977:       this.popDepth = popDepth;
 978:       this.pushDepth = pushDepth;
 979:       initTags();
 980:     }
 981:     
 982:     void initTags()
 983:     {
 984:       tagToAction = new HashMap(72);
 985:       CharacterAction characterAction = new CharacterAction();
 986:       HiddenAction hiddenAction = new HiddenAction();
 987:       AreaAction areaAction = new AreaAction();
 988:       BaseAction baseAction = new BaseAction();
 989:       BlockAction blockAction = new BlockAction();
 990:       SpecialAction specialAction = new SpecialAction();
 991:       ParagraphAction paragraphAction = new ParagraphAction();
 992:       HeadAction headAction = new HeadAction();
 993:       FormAction formAction = new FormAction();
 994:       IsindexAction isindexAction = new IsindexAction();
 995:       LinkAction linkAction = new LinkAction();
 996:       MapAction mapAction = new MapAction();
 997:       PreAction preAction = new PreAction();
 998:       MetaAction metaAction = new MetaAction();
 999:       StyleAction styleAction = new StyleAction();
1000:       TitleAction titleAction = new TitleAction();
1001:       
1002:       
1003:       tagToAction.put(HTML.Tag.A, characterAction);
1004:       tagToAction.put(HTML.Tag.ADDRESS, characterAction);
1005:       tagToAction.put(HTML.Tag.APPLET, hiddenAction);
1006:       tagToAction.put(HTML.Tag.AREA, areaAction);
1007:       tagToAction.put(HTML.Tag.B, characterAction);
1008:       tagToAction.put(HTML.Tag.BASE, baseAction);
1009:       tagToAction.put(HTML.Tag.BASEFONT, characterAction);
1010:       tagToAction.put(HTML.Tag.BIG, characterAction);
1011:       tagToAction.put(HTML.Tag.BLOCKQUOTE, blockAction);
1012:       tagToAction.put(HTML.Tag.BODY, blockAction);
1013:       tagToAction.put(HTML.Tag.BR, specialAction);
1014:       tagToAction.put(HTML.Tag.CAPTION, blockAction);
1015:       tagToAction.put(HTML.Tag.CENTER, blockAction);
1016:       tagToAction.put(HTML.Tag.CITE, characterAction);
1017:       tagToAction.put(HTML.Tag.CODE, characterAction);
1018:       tagToAction.put(HTML.Tag.DD, blockAction);
1019:       tagToAction.put(HTML.Tag.DFN, characterAction);
1020:       tagToAction.put(HTML.Tag.DIR, blockAction);
1021:       tagToAction.put(HTML.Tag.DIV, blockAction);
1022:       tagToAction.put(HTML.Tag.DL, blockAction);
1023:       tagToAction.put(HTML.Tag.DT, paragraphAction);
1024:       tagToAction.put(HTML.Tag.EM, characterAction);
1025:       tagToAction.put(HTML.Tag.FONT, characterAction);
1026:       tagToAction.put(HTML.Tag.FORM, blockAction);
1027:       tagToAction.put(HTML.Tag.FRAME, specialAction);
1028:       tagToAction.put(HTML.Tag.FRAMESET, blockAction);
1029:       tagToAction.put(HTML.Tag.H1, paragraphAction);
1030:       tagToAction.put(HTML.Tag.H2, paragraphAction);
1031:       tagToAction.put(HTML.Tag.H3, paragraphAction);
1032:       tagToAction.put(HTML.Tag.H4, paragraphAction);
1033:       tagToAction.put(HTML.Tag.H5, paragraphAction);
1034:       tagToAction.put(HTML.Tag.H6, paragraphAction);
1035:       tagToAction.put(HTML.Tag.HEAD, headAction);
1036:       tagToAction.put(HTML.Tag.HR, specialAction);
1037:       tagToAction.put(HTML.Tag.HTML, blockAction);
1038:       tagToAction.put(HTML.Tag.I, characterAction);
1039:       tagToAction.put(HTML.Tag.IMG, specialAction);
1040:       tagToAction.put(HTML.Tag.INPUT, formAction);
1041:       tagToAction.put(HTML.Tag.ISINDEX, isindexAction);
1042:       tagToAction.put(HTML.Tag.KBD, characterAction);
1043:       tagToAction.put(HTML.Tag.LI, blockAction);
1044:       tagToAction.put(HTML.Tag.LINK, linkAction);
1045:       tagToAction.put(HTML.Tag.MAP, mapAction);
1046:       tagToAction.put(HTML.Tag.MENU, blockAction);
1047:       tagToAction.put(HTML.Tag.META, metaAction);
1048:       tagToAction.put(HTML.Tag.NOFRAMES, blockAction);
1049:       tagToAction.put(HTML.Tag.OBJECT, specialAction);
1050:       tagToAction.put(HTML.Tag.OL, blockAction);
1051:       tagToAction.put(HTML.Tag.OPTION, formAction);
1052:       tagToAction.put(HTML.Tag.P, paragraphAction);
1053:       tagToAction.put(HTML.Tag.PARAM, hiddenAction);
1054:       tagToAction.put(HTML.Tag.PRE, preAction);
1055:       tagToAction.put(HTML.Tag.SAMP, characterAction);
1056:       tagToAction.put(HTML.Tag.SCRIPT, hiddenAction);
1057:       tagToAction.put(HTML.Tag.SELECT, formAction);
1058:       tagToAction.put(HTML.Tag.SMALL, characterAction);
1059:       tagToAction.put(HTML.Tag.STRIKE, characterAction);
1060:       tagToAction.put(HTML.Tag.S, characterAction);      
1061:       tagToAction.put(HTML.Tag.STRONG, characterAction);
1062:       tagToAction.put(HTML.Tag.STYLE, styleAction);
1063:       tagToAction.put(HTML.Tag.SUB, characterAction);
1064:       tagToAction.put(HTML.Tag.SUP, characterAction);
1065:       tagToAction.put(HTML.Tag.TABLE, blockAction);
1066:       tagToAction.put(HTML.Tag.TD, blockAction);
1067:       tagToAction.put(HTML.Tag.TEXTAREA, formAction);
1068:       tagToAction.put(HTML.Tag.TH, blockAction);
1069:       tagToAction.put(HTML.Tag.TITLE, titleAction);
1070:       tagToAction.put(HTML.Tag.TR, blockAction);
1071:       tagToAction.put(HTML.Tag.TT, characterAction);
1072:       tagToAction.put(HTML.Tag.U, characterAction);
1073:       tagToAction.put(HTML.Tag.UL, blockAction);
1074:       tagToAction.put(HTML.Tag.VAR, characterAction);
1075:     }
1076:     
1077:     /**
1078:      * Pushes the current character style onto the stack.
1079:      *
1080:      */
1081:     protected void pushCharacterStyle()
1082:     {
1083:       charAttrStack.push(charAttr.copyAttributes());
1084:     }
1085:     
1086:     /**
1087:      * Pops a character style off of the stack and uses it as the 
1088:      * current character style.
1089:      *
1090:      */
1091:     protected void popCharacterStyle()
1092:     {
1093:       if (!charAttrStack.isEmpty())
1094:         charAttr = (MutableAttributeSet) charAttrStack.pop();
1095:     }
1096:     
1097:     /**
1098:      * Registers a given tag with a given Action.  All of the well-known tags
1099:      * are registered by default, but this method can change their behaviour
1100:      * or add support for custom or currently unsupported tags.
1101:      * 
1102:      * @param t the Tag to register
1103:      * @param a the Action for the Tag
1104:      */
1105:     protected void registerTag(HTML.Tag t, HTMLDocument.HTMLReader.TagAction a)
1106:     {
1107:       tagToAction.put (t, a);
1108:     }
1109:     
1110:     /**
1111:      * This is the last method called on the HTMLReader, allowing any pending
1112:      * changes to be flushed to the HTMLDocument.
1113:      */
1114:     public void flush() throws BadLocationException
1115:     {
1116:       DefaultStyledDocument.ElementSpec[] elements;
1117:       elements = new DefaultStyledDocument.ElementSpec[parseBuffer.size()];
1118:       parseBuffer.copyInto(elements);
1119:       parseBuffer.removeAllElements();
1120:       if (offset == 0)
1121:         create(elements);
1122:       else
1123:         insert(offset, elements);
1124: 
1125:       offset += HTMLDocument.this.getLength() - offset;
1126:     }
1127:     
1128:     /**
1129:      * This method is called by the parser to indicate a block of 
1130:      * text was encountered.  Should insert the text appropriately.
1131:      * 
1132:      * @param data the text that was inserted
1133:      * @param pos the position at which the text was inserted
1134:      */
1135:     public void handleText(char[] data, int pos)
1136:     {
1137:       if (data != null && data.length > 0)
1138:         addContent(data, 0, data.length);
1139:     }
1140:     
1141:     /**
1142:      * This method is called by the parser and should route the call to 
1143:      * the proper handler for the tag.
1144:      * 
1145:      * @param t the HTML.Tag
1146:      * @param a the attribute set
1147:      * @param pos the position at which the tag was encountered
1148:      */
1149:     public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
1150:     {
1151:       // Don't call the Action if we've already seen </html>.
1152:       if (endHTMLEncountered)
1153:         return;
1154:         
1155:       TagAction action = (TagAction) tagToAction.get(t);
1156:       if (action != null)
1157:         action.start(t, a);      
1158:     }
1159:     
1160:     /**
1161:      * This method called by parser to handle a comment block.
1162:      * 
1163:      * @param data the comment
1164:      * @param pos the position at which the comment was encountered
1165:      */
1166:     public void handleComment(char[] data, int pos)
1167:     {
1168:       // Don't call the Action if we've already seen </html>.
1169:       if (endHTMLEncountered)
1170:         return;
1171:       
1172:       TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
1173:       if (action != null)
1174:         {
1175:           action.start(HTML.Tag.COMMENT, new SimpleAttributeSet());
1176:           action.end (HTML.Tag.COMMENT);
1177:         }
1178:     }
1179:     
1180:     /**
1181:      * This method is called by the parser and should route the call to 
1182:      * the proper handler for the tag.
1183:      * 
1184:      * @param t the HTML.Tag
1185:      * @param pos the position at which the tag was encountered
1186:      */
1187:     public void handleEndTag(HTML.Tag t, int pos)
1188:     {
1189:       // Don't call the Action if we've already seen </html>.
1190:       if (endHTMLEncountered)
1191:         return;
1192:       
1193:       // If this is the </html> tag we need to stop calling the Actions
1194:       if (t == HTML.Tag.HTML)
1195:         endHTMLEncountered = true;
1196:       
1197:       TagAction action = (TagAction) tagToAction.get(t);
1198:       if (action != null)
1199:         action.end(t);
1200:     }
1201:     
1202:     /**
1203:      * This is a callback from the parser that should be routed to the 
1204:      * appropriate handler for the tag.
1205:      * 
1206:      * @param t the HTML.Tag that was encountered
1207:      * @param a the attribute set
1208:      * @param pos the position at which the tag was encountered
1209:      */
1210:     public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos)
1211:     {
1212:       // Don't call the Action if we've already seen </html>.
1213:       if (endHTMLEncountered)
1214:         return;
1215:       
1216:       TagAction action = (TagAction) tagToAction.get (t);
1217:       if (action != null)
1218:         {
1219:           action.start(t, a);
1220:           action.end(t);
1221:         }
1222:     }
1223:     
1224:     /**
1225:      * This is invoked after the stream has been parsed but before it has been
1226:      * flushed.
1227:      * 
1228:      * @param eol one of \n, \r, or \r\n, whichever was encountered the most in 
1229:      * parsing the stream
1230:      * @since 1.3
1231:      */
1232:     public void handleEndOfLineString(String eol)
1233:       throws NotImplementedException
1234:     {
1235:       // FIXME: Implement.
1236:       print ("HTMLReader.handleEndOfLineString not implemented yet");
1237:     }
1238:     
1239:     /**
1240:      * Adds the given text to the textarea document.  Called only when we are
1241:      * within a textarea.  
1242:      * 
1243:      * @param data the text to add to the textarea
1244:      */
1245:     protected void textAreaContent(char[] data)
1246:       throws NotImplementedException
1247:     {
1248:       // FIXME: Implement.
1249:       print ("HTMLReader.textAreaContent not implemented yet");
1250:     }
1251:     
1252:     /**
1253:      * Adds the given text that was encountered in a <PRE> element.
1254:      * 
1255:      * @param data the text
1256:      */
1257:     protected void preContent(char[] data)
1258:       throws NotImplementedException
1259:     {
1260:       // FIXME: Implement
1261:       print ("HTMLReader.preContent not implemented yet");
1262:     }
1263:     
1264:     /**
1265:      * Instructs the parse buffer to create a block element with the given 
1266:      * attributes.
1267:      * 
1268:      * @param t the tag that requires opening a new block
1269:      * @param attr the attribute set for the new block
1270:      */
1271:     protected void blockOpen(HTML.Tag t, MutableAttributeSet attr)
1272:     {
1273:       printBuffer();
1274:       DefaultStyledDocument.ElementSpec element;
1275: 
1276:       // If the previous tag is content and the parent is p-implied, then
1277:       // we must also close the p-implied.
1278:       if (parseStack.size() > 0 && parseStack.peek() == HTML.Tag.IMPLIED)
1279:         {
1280:           element = new DefaultStyledDocument.ElementSpec(null,
1281:                                     DefaultStyledDocument.ElementSpec.EndTagType);
1282:           parseBuffer.addElement(element);
1283:           parseStack.pop();
1284:         }
1285: 
1286:       parseStack.push(t);
1287:       AbstractDocument.AttributeContext ctx = getAttributeContext();
1288:       AttributeSet copy = attr.copyAttributes();
1289:       copy = ctx.addAttribute(copy, StyleConstants.NameAttribute, t);
1290:       element = new DefaultStyledDocument.ElementSpec(copy,
1291:                                DefaultStyledDocument.ElementSpec.StartTagType);
1292:       parseBuffer.addElement(element);
1293:       printBuffer();
1294:     }
1295: 
1296:     /**
1297:      * Instructs the parse buffer to close the block element associated with 
1298:      * the given HTML.Tag
1299:      * 
1300:      * @param t the HTML.Tag that is closing its block
1301:      */
1302:     protected void blockClose(HTML.Tag t)
1303:     {
1304:       printBuffer();
1305:       DefaultStyledDocument.ElementSpec element;
1306: 
1307:       // If the previous tag is a start tag then we insert a synthetic
1308:       // content tag.
1309:       DefaultStyledDocument.ElementSpec prev;
1310:       prev = (DefaultStyledDocument.ElementSpec)
1311:           parseBuffer.get(parseBuffer.size() - 1);
1312:       if (prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType)
1313:         {
1314:           AbstractDocument.AttributeContext ctx = getAttributeContext();
1315:           AttributeSet attributes = ctx.getEmptySet();
1316:           attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute,
1317:                                         HTML.Tag.CONTENT);
1318:           element = new DefaultStyledDocument.ElementSpec(attributes,
1319:               DefaultStyledDocument.ElementSpec.ContentType,
1320:                                     new char[0], 0, 0);
1321:           parseBuffer.add(element);
1322:         }
1323:       // If the previous tag is content and the parent is p-implied, then
1324:       // we must also close the p-implied.
1325:       else if (parseStack.peek() == HTML.Tag.IMPLIED)
1326:         {
1327:           element = new DefaultStyledDocument.ElementSpec(null,
1328:                                  DefaultStyledDocument.ElementSpec.EndTagType);
1329:           parseBuffer.addElement(element);
1330:           if (parseStack.size() > 0)
1331:             parseStack.pop();
1332:         }
1333: 
1334:       element = new DefaultStyledDocument.ElementSpec(null,
1335:                 DefaultStyledDocument.ElementSpec.EndTagType);
1336:       parseBuffer.addElement(element);
1337:       printBuffer();
1338:       if (parseStack.size() > 0)
1339:         parseStack.pop();
1340:     }
1341:     
1342:     /**
1343:      * Adds text to the appropriate context using the current character
1344:      * attribute set.
1345:      * 
1346:      * @param data the text to add
1347:      * @param offs the offset at which to add it
1348:      * @param length the length of the text to add
1349:      */
1350:     protected void addContent(char[] data, int offs, int length)
1351:     {
1352:       addContent(data, offs, length, true);
1353:     }
1354:     
1355:     /**
1356:      * Adds text to the appropriate context using the current character
1357:      * attribute set, and possibly generating an IMPLIED Tag if necessary.
1358:      * 
1359:      * @param data the text to add
1360:      * @param offs the offset at which to add it
1361:      * @param length the length of the text to add
1362:      * @param generateImpliedPIfNecessary whether or not we should generate
1363:      * an HTML.Tag.IMPLIED tag if necessary
1364:      */
1365:     protected void addContent(char[] data, int offs, int length,
1366:                               boolean generateImpliedPIfNecessary)
1367:     {
1368:       AbstractDocument.AttributeContext ctx = getAttributeContext();
1369:       DefaultStyledDocument.ElementSpec element;
1370:       AttributeSet attributes = null;
1371: 
1372:       // Content must always be embedded inside a paragraph element,
1373:       // so we create this if the previous element is not one of
1374:       // <p>, <h1> .. <h6>.
1375:       boolean createImpliedParagraph = false;
1376:       HTML.Tag parent = (HTML.Tag) parseStack.peek();
1377:       if (parent != HTML.Tag.P && parent != HTML.Tag.H1
1378:           && parent != HTML.Tag.H2
1379:           && parent != HTML.Tag.H3 && parent != HTML.Tag.H4
1380:           && parent != HTML.Tag.H5 && parent != HTML.Tag.H6
1381:           && parent != HTML.Tag.TD)
1382:         {
1383:           attributes = ctx.getEmptySet();
1384:           attributes = ctx.addAttribute(attributes,
1385:                                         StyleConstants.NameAttribute,
1386:                                         HTML.Tag.IMPLIED);
1387:           element = new DefaultStyledDocument.ElementSpec(attributes,
1388:                        DefaultStyledDocument.ElementSpec.StartTagType);
1389:           parseBuffer.add(element);
1390:           parseStack.push(HTML.Tag.IMPLIED);
1391:         }
1392: 
1393:       // Copy the attribute set, don't use the same object because 
1394:       // it may change
1395:       if (charAttr != null)
1396:         attributes = charAttr.copyAttributes();
1397:       else
1398:         attributes = ctx.getEmptySet();
1399:       attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute,
1400:                                     HTML.Tag.CONTENT);
1401:       element = new DefaultStyledDocument.ElementSpec(attributes,
1402:                                 DefaultStyledDocument.ElementSpec.ContentType,
1403:                                 data, offs, length);
1404:       
1405:       printBuffer();
1406:       // Add the element to the buffer
1407:       parseBuffer.addElement(element);
1408:       printBuffer();
1409: 
1410:       if (parseBuffer.size() > HTMLDocument.this.getTokenThreshold())
1411:         {
1412:           try
1413:             {
1414:               flush();
1415:             }
1416:           catch (BadLocationException ble)
1417:             {
1418:               // TODO: what to do here?
1419:             }
1420:         }
1421:     }
1422:     
1423:     /**
1424:      * Adds content that is specified in the attribute set.
1425:      * 
1426:      * @param t the HTML.Tag
1427:      * @param a the attribute set specifying the special content
1428:      */
1429:     protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a)
1430:     {
1431:       a.addAttribute(StyleConstants.NameAttribute, t);
1432:       
1433:       // Migrate from the rather htmlAttributeSet to the faster, lighter and 
1434:       // unchangeable alternative implementation.
1435:       AttributeSet copy = a.copyAttributes();
1436:       
1437:       // TODO: Figure out why we must always insert this single character
1438:       // (otherwise the element does not appear). Either fix or add explaining
1439:       // comment or at least report a normal bug.
1440:       DefaultStyledDocument.ElementSpec spec;
1441:       spec = new DefaultStyledDocument.ElementSpec(copy,
1442:     DefaultStyledDocument.ElementSpec.ContentType, 
1443:         new char[] {' '}, 0, 1 );
1444:       parseBuffer.add(spec);
1445:     }
1446:     
1447:     void printBuffer()
1448:     {      
1449:       print ("\n*********BUFFER**********");
1450:       for (int i = 0; i < parseBuffer.size(); i ++)
1451:         print ("  "+parseBuffer.get(i));
1452:       print ("***************************");
1453:     }
1454:   }
1455:   
1456:   /**
1457:    * Gets the reader for the parser to use when loading the document with HTML. 
1458:    * 
1459:    * @param pos - the starting position
1460:    * @return - the reader
1461:    */
1462:   public HTMLEditorKit.ParserCallback getReader(int pos)
1463:   {
1464:     return new HTMLReader(pos);
1465:   }  
1466:   
1467:   /**
1468:    * Gets the reader for the parser to use when loading the document with HTML. 
1469:    * 
1470:    * @param pos - the starting position
1471:    * @param popDepth - the number of EndTagTypes to generate before inserting
1472:    * @param pushDepth - the number of StartTagTypes with a direction 
1473:    * of JoinNextDirection that should be generated before inserting, 
1474:    * but after the end tags have been generated.
1475:    * @param insertTag - the first tag to start inserting into document
1476:    * @return - the reader
1477:    */
1478:   public HTMLEditorKit.ParserCallback getReader(int pos,
1479:                                                 int popDepth,
1480:                                                 int pushDepth,
1481:                                                 HTML.Tag insertTag)
1482:   {
1483:     return new HTMLReader(pos, popDepth, pushDepth, insertTag);
1484:   }  
1485:   
1486:   /**
1487:    * Gets the child element that contains the attribute with the value or null.
1488:    * Not thread-safe.
1489:    * 
1490:    * @param e - the element to begin search at
1491:    * @param attribute - the desired attribute
1492:    * @param value - the desired value
1493:    * @return the element found with the attribute and value specified or null
1494:    * if it is not found.
1495:    */
1496:   public Element getElement(Element e, Object attribute, Object value)
1497:   {
1498:     if (e != null)
1499:       {
1500:         if (e.getAttributes().containsAttribute(attribute, value))
1501:           return e;
1502:         
1503:         int count = e.getElementCount();
1504:         for (int j = 0; j < count; j++)
1505:           {
1506:             Element child = e.getElement(j);
1507:             if (child.getAttributes().containsAttribute(attribute, value))
1508:               return child;
1509:             
1510:             Element grandChild = getElement(child, attribute, value);
1511:             if (grandChild != null)
1512:               return grandChild;
1513:           }
1514:       }
1515:     return null;
1516:   }
1517:   
1518:   /**
1519:    * Returns the element that has the given id Attribute. If it is not found, 
1520:    * null is returned. This method works on an Attribute, not a character tag.
1521:    * This is not thread-safe.
1522:    * 
1523:    * @param attrId - the Attribute id to look for
1524:    * @return the element that has the given id.
1525:    */
1526:   public Element getElement(String attrId)
1527:   {
1528:     return getElement(getDefaultRootElement(), HTML.getAttributeKey(attrId),
1529:                       attrId);
1530:   }
1531:   
1532:   /**
1533:    * Replaces the children of the given element with the contents of
1534:    * the string. The document must have an HTMLEditorKit.Parser set.
1535:    * This will be seen as at least two events, n inserts followed by a remove.
1536:    * 
1537:    * @param elem - the brance element whose children will be replaced
1538:    * @param htmlText - the string to be parsed and assigned to element.
1539:    * @throws BadLocationException
1540:    * @throws IOException
1541:    * @throws IllegalArgumentException - if elem is a leaf 
1542:    * @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set
1543:    */
1544:   public void setInnerHTML(Element elem, String htmlText) 
1545:     throws BadLocationException, IOException, NotImplementedException
1546:   {
1547:     if (elem.isLeaf())
1548:       throw new IllegalArgumentException("Element is a leaf");
1549:     if (parser == null)
1550:       throw new IllegalStateException("Parser has not been set");
1551:     // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
1552:     System.out.println("setInnerHTML not implemented");
1553:   }
1554:   
1555:   /**
1556:    * Replaces the given element in the parent with the string. When replacing
1557:    * a leaf, this will attempt to make sure there is a newline present if one is
1558:    * needed. This may result in an additional element being inserted.
1559:    * This will be seen as at least two events, n inserts followed by a remove.
1560:    * The HTMLEditorKit.Parser must be set.
1561:    * 
1562:    * @param elem - the branch element whose parent will be replaced
1563:    * @param htmlText - the string to be parsed and assigned to elem
1564:    * @throws BadLocationException
1565:    * @throws IOException
1566:    * @throws IllegalStateException - if parser is not set
1567:    */
1568:   public void setOuterHTML(Element elem, String htmlText) 
1569:     throws BadLocationException, IOException, NotImplementedException
1570:     {
1571:       if (parser == null)
1572:         throw new IllegalStateException("Parser has not been set");
1573:       // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
1574:       System.out.println("setOuterHTML not implemented");
1575:     }
1576:   
1577:   /**
1578:    * Inserts the string before the start of the given element.
1579:    * The parser must be set.
1580:    * 
1581:    * @param elem - the element to be the root for the new text.
1582:    * @param htmlText - the string to be parsed and assigned to elem
1583:    * @throws BadLocationException
1584:    * @throws IOException
1585:    * @throws IllegalStateException - if parser has not been set
1586:    */
1587:   public void insertBeforeStart(Element elem, String htmlText)
1588:       throws BadLocationException, IOException, NotImplementedException
1589:   {
1590:     if (parser == null)
1591:       throw new IllegalStateException("Parser has not been set");
1592:     //  FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
1593:     System.out.println("insertBeforeStart not implemented");
1594:   }
1595:   
1596:   /**
1597:    * Inserts the string at the end of the element. If elem's children
1598:    * are leaves, and the character at elem.getEndOffset() - 1 is a newline, 
1599:    * then it will be inserted before the newline. The parser must be set.
1600:    * 
1601:    * @param elem - the element to be the root for the new text
1602:    * @param htmlText - the text to insert
1603:    * @throws BadLocationException
1604:    * @throws IOException
1605:    * @throws IllegalStateException - if parser is not set
1606:    */
1607:   public void insertBeforeEnd(Element elem, String htmlText)
1608:       throws BadLocationException, IOException, NotImplementedException
1609:   {
1610:     if (parser == null)
1611:       throw new IllegalStateException("Parser has not been set");
1612:     //  FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
1613:     System.out.println("insertBeforeEnd not implemented");
1614:   }
1615:   
1616:   /**
1617:    * Inserts the string after the end of the given element.
1618:    * The parser must be set.
1619:    * 
1620:    * @param elem - the element to be the root for the new text
1621:    * @param htmlText - the text to insert
1622:    * @throws BadLocationException
1623:    * @throws IOException
1624:    * @throws IllegalStateException - if parser is not set
1625:    */
1626:   public void insertAfterEnd(Element elem, String htmlText)
1627:       throws BadLocationException, IOException, NotImplementedException
1628:   {
1629:     if (parser == null)
1630:       throw new IllegalStateException("Parser has not been set");
1631:     //  FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
1632:     System.out.println("insertAfterEnd not implemented");
1633:   }
1634:   
1635:   /**
1636:    * Inserts the string at the start of the element.
1637:    * The parser must be set.
1638:    * 
1639:    * @param elem - the element to be the root for the new text
1640:    * @param htmlText - the text to insert
1641:    * @throws BadLocationException
1642:    * @throws IOException
1643:    * @throws IllegalStateException - if parser is not set
1644:    */
1645:   public void insertAfterStart(Element elem, String htmlText)
1646:       throws BadLocationException, IOException, NotImplementedException
1647:   {
1648:     if (parser == null)
1649:       throw new IllegalStateException("Parser has not been set");
1650:     //  FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
1651:     System.out.println("insertAfterStart not implemented");
1652:   }
1653: }