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