OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [text/] [html/] [HTMLDocument.java] - Blame information for rev 775

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* 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.io.StringReader;
45
import java.net.MalformedURLException;
46
import java.net.URL;
47
import java.util.ArrayList;
48
import java.util.HashMap;
49
import java.util.Stack;
50
import java.util.Vector;
51
 
52
import javax.swing.ButtonGroup;
53
import javax.swing.DefaultButtonModel;
54
import javax.swing.JEditorPane;
55
import javax.swing.ListSelectionModel;
56
import javax.swing.event.DocumentEvent;
57
import javax.swing.event.UndoableEditEvent;
58
import javax.swing.text.AbstractDocument;
59
import javax.swing.text.AttributeSet;
60
import javax.swing.text.BadLocationException;
61
import javax.swing.text.DefaultStyledDocument;
62
import javax.swing.text.Element;
63
import javax.swing.text.ElementIterator;
64
import javax.swing.text.GapContent;
65
import javax.swing.text.MutableAttributeSet;
66
import javax.swing.text.PlainDocument;
67
import javax.swing.text.SimpleAttributeSet;
68
import javax.swing.text.StyleConstants;
69
import javax.swing.text.html.HTML.Tag;
70
 
71
/**
72
 * Represents the HTML document that is constructed by defining the text and
73
 * other components (images, buttons, etc) in HTML language. This class can
74
 * becomes the default document for {@link JEditorPane} after setting its
75
 * content type to "text/html". HTML document also serves as an intermediate
76
 * data structure when it is needed to parse HTML and then obtain the content of
77
 * the certain types of tags. This class also has methods for modifying the HTML
78
 * content.
79
 *
80
 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
81
 * @author Anthony Balkissoon (abalkiss@redhat.com)
82
 * @author Lillian Angel (langel@redhat.com)
83
 */
84
public class HTMLDocument extends DefaultStyledDocument
85
{
86
  /** A key for document properies.  The value for the key is
87
   * a Vector of Strings of comments not found in the body.
88
   */
89
  public static final String AdditionalComments = "AdditionalComments";
90
  URL baseURL = null;
91
  boolean preservesUnknownTags = true;
92
  int tokenThreshold = Integer.MAX_VALUE;
93
  HTMLEditorKit.Parser parser;
94
 
95
  /**
96
   * Indicates whether this document is inside a frame or not.
97
   */
98
  private boolean frameDocument;
99
 
100
  /**
101
   * Package private to avoid accessor methods.
102
   */
103
  String baseTarget;
104
 
105
  /**
106
   * Constructs an HTML document using the default buffer size and a default
107
   * StyleSheet.
108
   */
109
  public HTMLDocument()
110
  {
111
    this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleSheet());
112
  }
113
 
114
  /**
115
   * Constructs an HTML document with the default content storage
116
   * implementation and the specified style/attribute storage mechanism.
117
   *
118
   * @param styles - the style sheet
119
   */
120
  public HTMLDocument(StyleSheet styles)
121
  {
122
   this(new GapContent(BUFFER_SIZE_DEFAULT), styles);
123
  }
124
 
125
  /**
126
   * Constructs an HTML document with the given content storage implementation
127
   * and the given style/attribute storage mechanism.
128
   *
129
   * @param c - the document's content
130
   * @param styles - the style sheet
131
   */
132
  public HTMLDocument(AbstractDocument.Content c, StyleSheet styles)
133
  {
134
    super(c, styles);
135
  }
136
 
137
  /**
138
   * Gets the style sheet with the document display rules (CSS) that were specified
139
   * in the HTML document.
140
   *
141
   * @return - the style sheet
142
   */
143
  public StyleSheet getStyleSheet()
144
  {
145
    return (StyleSheet) getAttributeContext();
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
    return new RunElement(parent, a, p0, p1);
200
  }
201
 
202
  /**
203
   * This method returns an HTMLDocument.BlockElement object representing the
204
   * attribute set a and attached to parent.
205
   *
206
   * @param parent - the parent element
207
   * @param a - the attributes for the element
208
   *
209
   * @return the new element
210
   */
211
  protected Element createBranchElement(Element parent, AttributeSet a)
212
  {
213
    return new BlockElement(parent, a);
214
  }
215
 
216
  /**
217
   * Returns the parser used by this HTMLDocument to insert HTML.
218
   *
219
   * @return the parser used by this HTMLDocument to insert HTML.
220
   */
221
  public HTMLEditorKit.Parser getParser()
222
  {
223
    return parser;
224
  }
225
 
226
  /**
227
   * Sets the parser used by this HTMLDocument to insert HTML.
228
   *
229
   * @param p the parser to use
230
   */
231
  public void setParser (HTMLEditorKit.Parser p)
232
  {
233
    parser = p;
234
  }
235
  /**
236
   * Sets the number of tokens to buffer before trying to display the
237
   * Document.
238
   *
239
   * @param n the number of tokens to buffer
240
   */
241
  public void setTokenThreshold (int n)
242
  {
243
    tokenThreshold = n;
244
  }
245
 
246
  /**
247
   * Returns the number of tokens that are buffered before the document
248
   * is rendered.
249
   *
250
   * @return the number of tokens buffered
251
   */
252
  public int getTokenThreshold ()
253
  {
254
    return tokenThreshold;
255
  }
256
 
257
  /**
258
   * Returns the location against which to resolve relative URLs.
259
   * This is the document's URL if the document was loaded from a URL.
260
   * If a <code>base</code> tag is found, it will be used.
261
   * @return the base URL
262
   */
263
  public URL getBase()
264
  {
265
    return baseURL;
266
  }
267
 
268
  /**
269
   * Sets the location against which to resolve relative URLs.
270
   * @param u the new base URL
271
   */
272
  public void setBase(URL u)
273
  {
274
    baseURL = u;
275
    getStyleSheet().setBase(u);
276
  }
277
 
278
  /**
279
   * Returns whether or not the parser preserves unknown HTML tags.
280
   * @return true if the parser preserves unknown tags
281
   */
282
  public boolean getPreservesUnknownTags()
283
  {
284
    return preservesUnknownTags;
285
  }
286
 
287
  /**
288
   * Sets the behaviour of the parser when it encounters unknown HTML tags.
289
   * @param preservesTags true if the parser should preserve unknown tags.
290
   */
291
  public void setPreservesUnknownTags(boolean preservesTags)
292
  {
293
    preservesUnknownTags = preservesTags;
294
  }
295
 
296
  /**
297
   * An iterator to iterate through LeafElements in the document.
298
   */
299
  class LeafIterator extends Iterator
300
  {
301
    HTML.Tag tag;
302
    HTMLDocument doc;
303
    ElementIterator it;
304
 
305
    public LeafIterator (HTML.Tag t, HTMLDocument d)
306
    {
307
      doc = d;
308
      tag = t;
309
      it = new ElementIterator(doc);
310
    }
311
 
312
    /**
313
     * Return the attributes for the tag associated with this iteartor
314
     * @return the AttributeSet
315
     */
316
    public AttributeSet getAttributes()
317
    {
318
      if (it.current() != null)
319
        return it.current().getAttributes();
320
      return null;
321
    }
322
 
323
    /**
324
     * Get the end of the range for the current occurrence of the tag
325
     * being defined and having the same attributes.
326
     * @return the end of the range
327
     */
328
    public int getEndOffset()
329
    {
330
      if (it.current() != null)
331
        return it.current().getEndOffset();
332
      return -1;
333
    }
334
 
335
    /**
336
     * Get the start of the range for the current occurrence of the tag
337
     * being defined and having the same attributes.
338
     * @return the start of the range (-1 if it can't be found).
339
     */
340
 
341
    public int getStartOffset()
342
    {
343
      if (it.current() != null)
344
        return it.current().getStartOffset();
345
      return -1;
346
    }
347
 
348
    /**
349
     * Advance the iterator to the next LeafElement .
350
     */
351
    public void next()
352
    {
353
      it.next();
354
      while (it.current()!= null && !it.current().isLeaf())
355
        it.next();
356
    }
357
 
358
    /**
359
     * Indicates whether or not the iterator currently represents an occurrence
360
     * of the tag.
361
     * @return true if the iterator currently represents an occurrence of the
362
     * tag.
363
     */
364
    public boolean isValid()
365
    {
366
      return it.current() != null;
367
    }
368
 
369
    /**
370
     * Type of tag for this iterator.
371
     */
372
    public Tag getTag()
373
    {
374
      return tag;
375
    }
376
 
377
  }
378
 
379
  public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event)
380
  {
381
    String target = event.getTarget();
382
    Element el = event.getSourceElement();
383
    URL url = event.getURL();
384
    if (target.equals("_self"))
385
      {
386
        updateFrame(el, url);
387
      }
388
    else if (target.equals("_parent"))
389
      {
390
        updateFrameSet(el.getParentElement(), url);
391
      }
392
    else
393
      {
394
        Element targetFrame = findFrame(target);
395
        if (targetFrame != null)
396
          updateFrame(targetFrame, url);
397
      }
398
  }
399
 
400
  /**
401
   * Finds the named frame inside this document.
402
   *
403
   * @param target the name to look for
404
   *
405
   * @return the frame if there is a matching frame, <code>null</code>
406
   *         otherwise
407
   */
408
  private Element findFrame(String target)
409
  {
410
    ElementIterator i = new ElementIterator(this);
411
    Element next = null;
412
    while ((next = i.next()) != null)
413
      {
414
        AttributeSet atts = next.getAttributes();
415
        if (atts.getAttribute(StyleConstants.NameAttribute) == HTML.Tag.FRAME)
416
          {
417
            String name = (String) atts.getAttribute(HTML.Attribute.NAME);
418
            if (name != null && name.equals(target))
419
              break;
420
          }
421
      }
422
    return next;
423
  }
424
 
425
  /**
426
   * Updates the frame that is represented by the specified element to
427
   * refer to the specified URL.
428
   *
429
   * @param el the element
430
   * @param url the new url
431
   */
432
  private void updateFrame(Element el, URL url)
433
  {
434
    try
435
      {
436
        writeLock();
437
        DefaultDocumentEvent ev =
438
          new DefaultDocumentEvent(el.getStartOffset(), 1,
439
                                   DocumentEvent.EventType.CHANGE);
440
        AttributeSet elAtts = el.getAttributes();
441
        AttributeSet copy = elAtts.copyAttributes();
442
        MutableAttributeSet matts = (MutableAttributeSet) elAtts;
443
        ev.addEdit(new AttributeUndoableEdit(el, copy, false));
444
        matts.removeAttribute(HTML.Attribute.SRC);
445
        matts.addAttribute(HTML.Attribute.SRC, url.toString());
446
        ev.end();
447
        fireChangedUpdate(ev);
448
        fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
449
      }
450
    finally
451
      {
452
        writeUnlock();
453
      }
454
  }
455
 
456
  /**
457
   * Updates the frameset that is represented by the specified element
458
   * to create a frame that refers to the specified URL.
459
   *
460
   * @param el the element
461
   * @param url the url
462
   */
463
  private void updateFrameSet(Element el, URL url)
464
  {
465
    int start = el.getStartOffset();
466
    int end = el.getEndOffset();
467
 
468
    StringBuilder html = new StringBuilder();
469
    html.append("<frame");
470
    if (url != null)
471
      {
472
        html.append(" src=\"");
473
        html.append(url.toString());
474
        html.append("\"");
475
      }
476
    html.append('>');
477
    if (getParser() == null)
478
      setParser(new HTMLEditorKit().getParser());
479
    try
480
      {
481
        setOuterHTML(el, html.toString());
482
      }
483
    catch (BadLocationException ex)
484
      {
485
        ex.printStackTrace();
486
      }
487
    catch (IOException ex)
488
      {
489
        ex.printStackTrace();
490
      }
491
  }
492
 
493
  /**
494
   * Gets an iterator for the given HTML.Tag.
495
   * @param t the requested HTML.Tag
496
   * @return the Iterator
497
   */
498
  public HTMLDocument.Iterator getIterator (HTML.Tag t)
499
  {
500
    return new HTMLDocument.LeafIterator(t, this);
501
  }
502
 
503
  /**
504
   * An iterator over a particular type of tag.
505
   */
506
  public abstract static class Iterator
507
  {
508
    /**
509
     * Return the attribute set for this tag.
510
     * @return the <code>AttributeSet</code> (null if none found).
511
     */
512
    public abstract AttributeSet getAttributes();
513
 
514
    /**
515
     * Get the end of the range for the current occurrence of the tag
516
     * being defined and having the same attributes.
517
     * @return the end of the range
518
     */
519
    public abstract int getEndOffset();
520
 
521
    /**
522
     * Get the start of the range for the current occurrence of the tag
523
     * being defined and having the same attributes.
524
     * @return the start of the range (-1 if it can't be found).
525
     */
526
    public abstract int getStartOffset();
527
 
528
    /**
529
     * Move the iterator forward.
530
     */
531
    public abstract void next();
532
 
533
    /**
534
     * Indicates whether or not the iterator currently represents an occurrence
535
     * of the tag.
536
     * @return true if the iterator currently represents an occurrence of the
537
     * tag.
538
     */
539
    public abstract boolean isValid();
540
 
541
    /**
542
     * Type of tag this iterator represents.
543
     * @return the tag.
544
     */
545
    public abstract HTML.Tag getTag();
546
  }
547
 
548
  public class BlockElement extends AbstractDocument.BranchElement
549
  {
550
    public BlockElement (Element parent, AttributeSet a)
551
    {
552
      super(parent, a);
553
    }
554
 
555
    /**
556
     * Gets the resolving parent.  Since HTML attributes are not
557
     * inherited at the model level, this returns null.
558
     */
559
    public AttributeSet getResolveParent()
560
    {
561
      return null;
562
    }
563
 
564
    /**
565
     * Gets the name of the element.
566
     *
567
     * @return the name of the element if it exists, null otherwise.
568
     */
569
    public String getName()
570
    {
571
      Object tag = getAttribute(StyleConstants.NameAttribute);
572
      String name = null;
573
      if (tag != null)
574
        name = tag.toString();
575
      if (name == null)
576
        name = super.getName();
577
      return name;
578
    }
579
  }
580
 
581
  /**
582
   * RunElement represents a section of text that has a set of
583
   * HTML character level attributes assigned to it.
584
   */
585
  public class RunElement extends AbstractDocument.LeafElement
586
  {
587
 
588
    /**
589
     * Constructs an element that has no children. It represents content
590
     * within the document.
591
     *
592
     * @param parent - parent of this
593
     * @param a - elements attributes
594
     * @param start - the start offset >= 0
595
     * @param end - the end offset
596
     */
597
    public RunElement(Element parent, AttributeSet a, int start, int end)
598
    {
599
      super(parent, a, start, end);
600
    }
601
 
602
    /**
603
     * Gets the name of the element.
604
     *
605
     * @return the name of the element if it exists, null otherwise.
606
     */
607
    public String getName()
608
    {
609
      Object tag = getAttribute(StyleConstants.NameAttribute);
610
      String name = null;
611
      if (tag != null)
612
        name = tag.toString();
613
      if (name == null)
614
        name = super.getName();
615
      return name;
616
    }
617
 
618
    /**
619
     * Gets the resolving parent. HTML attributes do not inherit at the
620
     * model level, so this method returns null.
621
     *
622
     * @return null
623
     */
624
    public AttributeSet getResolveParent()
625
    {
626
      return null;
627
    }
628
  }
629
 
630
  /**
631
   * A reader to load an HTMLDocument with HTML structure.
632
   *
633
   * @author Anthony Balkissoon abalkiss at redhat dot com
634
   */
635
  public class HTMLReader extends HTMLEditorKit.ParserCallback
636
  {
637
    /**
638
     * The maximum token threshold. We don't grow it larger than this.
639
     */
640
    private static final int MAX_THRESHOLD = 10000;
641
 
642
    /**
643
     * The threshold growth factor.
644
     */
645
    private static final int GROW_THRESHOLD = 5;
646
 
647
    /**
648
     * Holds the current character attribute set *
649
     */
650
    protected MutableAttributeSet charAttr = new SimpleAttributeSet();
651
 
652
    protected Vector<ElementSpec> parseBuffer = new Vector<ElementSpec>();
653
 
654
    /**
655
     * The parse stack. It holds the current element tree path.
656
     */
657
    private Stack<HTML.Tag> parseStack = new Stack<HTML.Tag>();
658
 
659
    /**
660
     * A stack for character attribute sets *
661
     */
662
    Stack charAttrStack = new Stack();
663
 
664
    /** A mapping between HTML.Tag objects and the actions that handle them **/
665
    HashMap tagToAction;
666
 
667
    /** Tells us whether we've received the '</html>' tag yet **/
668
    boolean endHTMLEncountered = false;
669
 
670
    /**
671
     * Related to the constructor with explicit insertTag
672
     */
673
    int popDepth;
674
 
675
    /**
676
     * Related to the constructor with explicit insertTag
677
     */
678
    int pushDepth;
679
 
680
    /**
681
     * Related to the constructor with explicit insertTag
682
     */
683
    int offset;
684
 
685
    /**
686
     * The tag (inclusve), after that the insertion should start.
687
     */
688
    HTML.Tag insertTag;
689
 
690
    /**
691
     * This variable becomes true after the insert tag has been encountered.
692
     */
693
    boolean insertTagEncountered;
694
 
695
 
696
    /** A temporary variable that helps with the printing out of debug information **/
697
    boolean debug = false;
698
 
699
    /**
700
     * This is true when we are inside a pre tag.
701
     */
702
    boolean inPreTag = false;
703
 
704
    /**
705
     * This is true when we are inside a style tag. This will add text
706
     * content inside this style tag beeing parsed as CSS.
707
     *
708
     * This is package private to avoid accessor methods.
709
     */
710
    boolean inStyleTag = false;
711
 
712
    /**
713
     * This is true when we are inside a &lt;textarea&gt; tag. Any text
714
     * content will then be added to the text area.
715
     *
716
     * This is package private to avoid accessor methods.
717
     */
718
    boolean inTextArea = false;
719
 
720
    /**
721
     * This contains all stylesheets that are somehow read, either
722
     * via embedded style tags, or via linked stylesheets. The
723
     * elements will be String objects containing a stylesheet each.
724
     */
725
    ArrayList styles;
726
 
727
    /**
728
     * The document model for a textarea.
729
     *
730
     * This is package private to avoid accessor methods.
731
     */
732
    ResetablePlainDocument textAreaDocument;
733
 
734
    /**
735
     * The current model of a select tag. Can be a ComboBoxModel or a
736
     * ListModel depending on the type of the select box.
737
     */
738
    Object selectModel;
739
 
740
    /**
741
     * The current option beeing read.
742
     */
743
    Option option;
744
 
745
    /**
746
     * The current number of options in the current select model.
747
     */
748
    int numOptions;
749
 
750
    /**
751
     * The current button groups mappings.
752
     */
753
    HashMap buttonGroups;
754
 
755
    /**
756
     * The token threshold. This gets increased while loading.
757
     */
758
    private int threshold;
759
 
760
    public class TagAction
761
    {
762
      /**
763
       * This method is called when a start tag is seen for one of the types
764
       * of tags associated with this Action.  By default this does nothing.
765
       */
766
      public void start(HTML.Tag t, MutableAttributeSet a)
767
      {
768
        // Nothing to do here.
769
      }
770
 
771
      /**
772
       * Called when an end tag is seen for one of the types of tags associated
773
       * with this Action.  By default does nothing.
774
       */
775
      public void end(HTML.Tag t)
776
      {
777
        // Nothing to do here.
778
      }
779
    }
780
 
781
    public class BlockAction extends TagAction
782
    {
783
      /**
784
       * This method is called when a start tag is seen for one of the types
785
       * of tags associated with this Action.
786
       */
787
      public void start(HTML.Tag t, MutableAttributeSet a)
788
      {
789
        // Tell the parse buffer to open a new block for this tag.
790
        blockOpen(t, a);
791
      }
792
 
793
      /**
794
       * Called when an end tag is seen for one of the types of tags associated
795
       * with this Action.
796
       */
797
      public void end(HTML.Tag t)
798
      {
799
        // Tell the parse buffer to close this block.
800
        blockClose(t);
801
      }
802
    }
803
 
804
    public class CharacterAction extends TagAction
805
    {
806
      /**
807
       * This method is called when a start tag is seen for one of the types
808
       * of tags associated with this Action.
809
       */
810
      public void start(HTML.Tag t, MutableAttributeSet a)
811
      {
812
        // Put the old attribute set on the stack.
813
        pushCharacterStyle();
814
 
815
        // Initialize with link pseudo class.
816
        if (t == HTML.Tag.A)
817
          a.addAttribute(HTML.Attribute.PSEUDO_CLASS, "link");
818
 
819
        // Just add the attributes in <code>a</code>.
820
        charAttr.addAttribute(t, a.copyAttributes());
821
      }
822
 
823
      /**
824
       * Called when an end tag is seen for one of the types of tags associated
825
       * with this Action.
826
       */
827
      public void end(HTML.Tag t)
828
      {
829
        popCharacterStyle();
830
      }
831
    }
832
 
833
    /**
834
     * Processes elements that make up forms: &lt;input&gt;, &lt;textarea&gt;,
835
     * &lt;select&gt; and &lt;option&gt;.
836
     */
837
    public class FormAction extends SpecialAction
838
    {
839
      /**
840
       * This method is called when a start tag is seen for one of the types
841
       * of tags associated with this Action.
842
       */
843
      public void start(HTML.Tag t, MutableAttributeSet a)
844
      {
845
        if (t == HTML.Tag.INPUT)
846
          {
847
            String type = (String) a.getAttribute(HTML.Attribute.TYPE);
848
            if (type == null)
849
              {
850
                type = "text"; // Default to 'text' when nothing was specified.
851
                a.addAttribute(HTML.Attribute.TYPE, type);
852
              }
853
            setModel(type, a);
854
          }
855
        else if (t == HTML.Tag.TEXTAREA)
856
          {
857
            inTextArea = true;
858
            textAreaDocument = new ResetablePlainDocument();
859
            a.addAttribute(StyleConstants.ModelAttribute, textAreaDocument);
860
          }
861
        else if (t == HTML.Tag.SELECT)
862
          {
863
            int size = HTML.getIntegerAttributeValue(a, HTML.Attribute.SIZE,
864
                                                     1);
865
            boolean multi = a.getAttribute(HTML.Attribute.MULTIPLE) != null;
866
            if (size > 1 || multi)
867
              {
868
                SelectListModel m = new SelectListModel();
869
                if (multi)
870
                  m.getSelectionModel().setSelectionMode(ListSelectionModel
871
                                                 .MULTIPLE_INTERVAL_SELECTION);
872
                selectModel = m;
873
              }
874
            else
875
              {
876
                selectModel = new SelectComboBoxModel();
877
              }
878
            a.addAttribute(StyleConstants.ModelAttribute, selectModel);
879
          }
880
        if (t == HTML.Tag.OPTION)
881
          {
882
            option = new Option(a);
883
            if (selectModel instanceof SelectListModel)
884
              {
885
                SelectListModel m = (SelectListModel) selectModel;
886
                m.addElement(option);
887
                if (option.isSelected())
888
                  {
889
                    m.getSelectionModel().addSelectionInterval(numOptions,
890
                                                               numOptions);
891
                    m.addInitialSelection(numOptions);
892
                  }
893
              }
894
            else if (selectModel instanceof SelectComboBoxModel)
895
              {
896
                SelectComboBoxModel m = (SelectComboBoxModel) selectModel;
897
                m.addElement(option);
898
                if (option.isSelected())
899
                  {
900
                    m.setSelectedItem(option);
901
                    m.setInitialSelection(option);
902
                  }
903
              }
904
            numOptions++;
905
          }
906
        else
907
          {
908
            // Build the element.
909
            super.start(t, a);
910
          }
911
      }
912
 
913
      /**
914
       * Called when an end tag is seen for one of the types of tags associated
915
       * with this Action.
916
       */
917
      public void end(HTML.Tag t)
918
      {
919
        if (t == HTML.Tag.OPTION)
920
          {
921
            option = null;
922
          }
923
        else
924
          {
925
            if (t == HTML.Tag.TEXTAREA)
926
              {
927
                inTextArea = false;
928
              }
929
            else if (t == HTML.Tag.SELECT)
930
              {
931
                selectModel = null;
932
                numOptions = 0;
933
              }
934
            // Finish the element.
935
            super.end(t);
936
          }
937
      }
938
 
939
      private void setModel(String type, MutableAttributeSet attrs)
940
      {
941
        if (type.equals("submit") || type.equals("reset")
942
            || type.equals("image"))
943
          {
944
            // Create button.
945
            attrs.addAttribute(StyleConstants.ModelAttribute,
946
                               new DefaultButtonModel());
947
          }
948
        else if (type.equals("text") || type.equals("password"))
949
          {
950
            String text = (String) attrs.getAttribute(HTML.Attribute.VALUE);
951
            ResetablePlainDocument doc = new ResetablePlainDocument();
952
            if (text != null)
953
              {
954
                doc.setInitialText(text);
955
                try
956
                  {
957
                    doc.insertString(0, text, null);
958
                  }
959
                catch (BadLocationException ex)
960
                  {
961
                    // Shouldn't happen.
962
                    assert false;
963
                  }
964
              }
965
            attrs.addAttribute(StyleConstants.ModelAttribute, doc);
966
          }
967
        else if (type.equals("file"))
968
          {
969
            attrs.addAttribute(StyleConstants.ModelAttribute,
970
                               new PlainDocument());
971
          }
972
        else if (type.equals("checkbox") || type.equals("radio"))
973
          {
974
            ResetableToggleButtonModel model =
975
              new ResetableToggleButtonModel();
976
            if (attrs.getAttribute(HTML.Attribute.SELECTED) != null)
977
              {
978
                model.setSelected(true);
979
                model.setInitial(true);
980
              }
981
            if (type.equals("radio"))
982
              {
983
                String name = (String) attrs.getAttribute(HTML.Attribute.NAME);
984
                if (name != null)
985
                  {
986
                    if (buttonGroups == null)
987
                      buttonGroups = new HashMap();
988
                    ButtonGroup group = (ButtonGroup) buttonGroups.get(name);
989
                    if (group == null)
990
                      {
991
                        group = new ButtonGroup();
992
                        buttonGroups.put(name, group);
993
                      }
994
                    model.setGroup(group);
995
                  }
996
              }
997
            attrs.addAttribute(StyleConstants.ModelAttribute, model);
998
          }
999
      }
1000
    }
1001
 
1002
    /**
1003
     * Called for form tags.
1004
     */
1005
    class FormTagAction
1006
      extends BlockAction
1007
    {
1008
      /**
1009
       * Clears the button group mapping.
1010
       */
1011
      public void end(HTML.Tag t)
1012
      {
1013
        super.end(t);
1014
        buttonGroups = null;
1015
      }
1016
    }
1017
 
1018
    /**
1019
     * This action indicates that the content between starting and closing HTML
1020
     * elements (like script - /script) should not be visible. The content is
1021
     * still inserted and can be accessed when iterating the HTML document. The
1022
     * parser will only fire
1023
     * {@link javax.swing.text.html.HTMLEditorKit.ParserCallback#handleText} for
1024
     * the hidden tags, regardless from that html tags the hidden section may
1025
     * contain.
1026
     */
1027
    public class HiddenAction
1028
        extends TagAction
1029
    {
1030
      /**
1031
       * This method is called when a start tag is seen for one of the types
1032
       * of tags associated with this Action.
1033
       */
1034
      public void start(HTML.Tag t, MutableAttributeSet a)
1035
      {
1036
        blockOpen(t, a);
1037
      }
1038
 
1039
      /**
1040
       * Called when an end tag is seen for one of the types of tags associated
1041
       * with this Action.
1042
       */
1043
      public void end(HTML.Tag t)
1044
      {
1045
        blockClose(t);
1046
      }
1047
    }
1048
 
1049
    /**
1050
     * Handles &lt;isindex&gt; tags.
1051
     */
1052
    public class IsindexAction extends TagAction
1053
    {
1054
      /**
1055
       * This method is called when a start tag is seen for one of the types
1056
       * of tags associated with this Action.
1057
       */
1058
      public void start(HTML.Tag t, MutableAttributeSet a)
1059
      {
1060
        blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
1061
        addSpecialElement(t, a);
1062
        blockClose(HTML.Tag.IMPLIED);
1063
      }
1064
    }
1065
 
1066
    public class ParagraphAction extends BlockAction
1067
    {
1068
      /**
1069
       * This method is called when a start tag is seen for one of the types
1070
       * of tags associated with this Action.
1071
       */
1072
      public void start(HTML.Tag t, MutableAttributeSet a)
1073
      {
1074
        super.start(t, a);
1075
      }
1076
 
1077
      /**
1078
       * Called when an end tag is seen for one of the types of tags associated
1079
       * with this Action.
1080
       */
1081
      public void end(HTML.Tag t)
1082
      {
1083
        super.end(t);
1084
      }
1085
    }
1086
 
1087
    /**
1088
     * This action is performed when a &lt;pre&gt; tag is parsed.
1089
     */
1090
    public class PreAction extends BlockAction
1091
    {
1092
      /**
1093
       * This method is called when a start tag is seen for one of the types
1094
       * of tags associated with this Action.
1095
       */
1096
      public void start(HTML.Tag t, MutableAttributeSet a)
1097
      {
1098
        inPreTag = true;
1099
        blockOpen(t, a);
1100
        a.addAttribute(CSS.Attribute.WHITE_SPACE, "pre");
1101
        blockOpen(HTML.Tag.IMPLIED, a);
1102
      }
1103
 
1104
      /**
1105
       * Called when an end tag is seen for one of the types of tags associated
1106
       * with this Action.
1107
       */
1108
      public void end(HTML.Tag t)
1109
      {
1110
        blockClose(HTML.Tag.IMPLIED);
1111
        inPreTag = false;
1112
        blockClose(t);
1113
      }
1114
    }
1115
 
1116
    /**
1117
     * Inserts the elements that are represented by ths single tag with
1118
     * attributes (only). The closing tag, even if present, mut follow
1119
     * immediately after the starting tag without providing any additional
1120
     * information. Hence the {@link TagAction#end} method need not be
1121
     * overridden and still does nothing.
1122
     */
1123
    public class SpecialAction extends TagAction
1124
    {
1125
      /**
1126
       * The functionality is delegated to {@link HTMLReader#addSpecialElement}
1127
       */
1128
      public void start(HTML.Tag t, MutableAttributeSet a)
1129
      {
1130
        addSpecialElement(t, a);
1131
      }
1132
    }
1133
 
1134
    class AreaAction extends TagAction
1135
    {
1136
      /**
1137
       * This method is called when a start tag is seen for one of the types
1138
       * of tags associated with this Action.
1139
       */
1140
      public void start(HTML.Tag t, MutableAttributeSet a)
1141
        throws NotImplementedException
1142
      {
1143
        // FIXME: Implement.
1144
      }
1145
 
1146
      /**
1147
       * Called when an end tag is seen for one of the types of tags associated
1148
       * with this Action.
1149
       */
1150
      public void end(HTML.Tag t)
1151
        throws NotImplementedException
1152
      {
1153
        // FIXME: Implement.
1154
      }
1155
    }
1156
 
1157
    /**
1158
     * Converts HTML tags to CSS attributes.
1159
     */
1160
    class ConvertAction
1161
      extends TagAction
1162
    {
1163
 
1164
      public void start(HTML.Tag tag, MutableAttributeSet atts)
1165
      {
1166
        pushCharacterStyle();
1167
        charAttr.addAttribute(tag, atts.copyAttributes());
1168
        StyleSheet styleSheet = getStyleSheet();
1169
        // TODO: Add other tags here.
1170
        if (tag == HTML.Tag.FONT)
1171
          {
1172
            String color = (String) atts.getAttribute(HTML.Attribute.COLOR);
1173
            if (color != null)
1174
              styleSheet.addCSSAttribute(charAttr, CSS.Attribute.COLOR, color);
1175
            String face = (String) atts.getAttribute(HTML.Attribute.FACE);
1176
            if (face != null)
1177
              styleSheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_FAMILY,
1178
                                         face);
1179
            String size = (String) atts.getAttribute(HTML.Attribute.SIZE);
1180
            if (size != null)
1181
              styleSheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_SIZE,
1182
                                         size);
1183
          }
1184
      }
1185
 
1186
      public void end(HTML.Tag tag)
1187
      {
1188
        popCharacterStyle();
1189
      }
1190
    }
1191
 
1192
    class BaseAction extends TagAction
1193
    {
1194
      /**
1195
       * This method is called when a start tag is seen for one of the types
1196
       * of tags associated with this Action.
1197
       */
1198
      public void start(HTML.Tag t, MutableAttributeSet a)
1199
      {
1200
        baseTarget = (String) a.getAttribute(HTML.Attribute.TARGET);
1201
      }
1202
    }
1203
 
1204
    class HeadAction extends BlockAction
1205
    {
1206
      /**
1207
       * This method is called when a start tag is seen for one of the types
1208
       * of tags associated with this Action.
1209
       */
1210
      public void start(HTML.Tag t, MutableAttributeSet a)
1211
        throws NotImplementedException
1212
      {
1213
        // FIXME: Implement.
1214
        super.start(t, a);
1215
      }
1216
 
1217
      /**
1218
       * Called when an end tag is seen for one of the types of tags associated
1219
       * with this Action.
1220
       */
1221
      public void end(HTML.Tag t)
1222
      {
1223
        // We read in all the stylesheets that are embedded or referenced
1224
        // inside the header.
1225
        if (styles != null)
1226
          {
1227
            int numStyles = styles.size();
1228
            for (int i = 0; i < numStyles; i++)
1229
              {
1230
                String style = (String) styles.get(i);
1231
                getStyleSheet().addRule(style);
1232
              }
1233
          }
1234
        super.end(t);
1235
      }
1236
    }
1237
 
1238
    class LinkAction extends HiddenAction
1239
    {
1240
      /**
1241
       * This method is called when a start tag is seen for one of the types
1242
       * of tags associated with this Action.
1243
       */
1244
      public void start(HTML.Tag t, MutableAttributeSet a)
1245
      {
1246
        super.start(t, a);
1247
        String type = (String) a.getAttribute(HTML.Attribute.TYPE);
1248
        if (type == null)
1249
          type = "text/css";
1250
        if (type.equals("text/css"))
1251
          {
1252
            String rel = (String) a.getAttribute(HTML.Attribute.REL);
1253
            String media = (String) a.getAttribute(HTML.Attribute.MEDIA);
1254
            String title = (String) a.getAttribute(HTML.Attribute.TITLE);
1255
            if (media == null)
1256
              media = "all";
1257
            else
1258
              media = media.toLowerCase();
1259
            if (rel != null)
1260
              {
1261
                rel = rel.toLowerCase();
1262
                if ((media.indexOf("all") != -1
1263
                     || media.indexOf("screen") != -1)
1264
                    && (rel.equals("stylesheet")))
1265
                  {
1266
                    String href = (String) a.getAttribute(HTML.Attribute.HREF);
1267
                    URL url = null;
1268
                    try
1269
                      {
1270
                        url = new URL(baseURL, href);
1271
                      }
1272
                    catch (MalformedURLException ex)
1273
                      {
1274
                        try
1275
                          {
1276
                            url = new URL(href);
1277
                          }
1278
                        catch (MalformedURLException ex2)
1279
                          {
1280
                            url = null;
1281
                          }
1282
                      }
1283
                    if (url != null)
1284
                      {
1285
                        try
1286
                          {
1287
                            getStyleSheet().importStyleSheet(url);
1288
                          }
1289
                        catch (Exception ex)
1290
                          {
1291
                            // Don't let exceptions and runtime exceptions
1292
                            // in CSS parsing disprupt the HTML parsing
1293
                            // process. But inform the user/developer
1294
                            // on the console about it.
1295
                            ex.printStackTrace();
1296
                          }
1297
                      }
1298
                  }
1299
              }
1300
          }
1301
      }
1302
 
1303
    }
1304
 
1305
    class MapAction extends TagAction
1306
    {
1307
      /**
1308
       * This method is called when a start tag is seen for one of the types
1309
       * of tags associated with this Action.
1310
       */
1311
      public void start(HTML.Tag t, MutableAttributeSet a)
1312
        throws NotImplementedException
1313
      {
1314
        // FIXME: Implement.
1315
      }
1316
 
1317
      /**
1318
       * Called when an end tag is seen for one of the types of tags associated
1319
       * with this Action.
1320
       */
1321
      public void end(HTML.Tag t)
1322
        throws NotImplementedException
1323
      {
1324
        // FIXME: Implement.
1325
      }
1326
    }
1327
 
1328
    class MetaAction extends TagAction
1329
    {
1330
      /**
1331
       * This method is called when a start tag is seen for one of the types
1332
       * of tags associated with this Action.
1333
       */
1334
      public void start(HTML.Tag t, MutableAttributeSet a)
1335
        throws NotImplementedException
1336
      {
1337
        // FIXME: Implement.
1338
      }
1339
 
1340
      /**
1341
       * Called when an end tag is seen for one of the types of tags associated
1342
       * with this Action.
1343
       */
1344
      public void end(HTML.Tag t)
1345
        throws NotImplementedException
1346
      {
1347
        // FIXME: Implement.
1348
      }
1349
    }
1350
 
1351
    class StyleAction extends TagAction
1352
    {
1353
      /**
1354
       * This method is called when a start tag is seen for one of the types
1355
       * of tags associated with this Action.
1356
       */
1357
      public void start(HTML.Tag t, MutableAttributeSet a)
1358
      {
1359
        inStyleTag = true;
1360
      }
1361
 
1362
      /**
1363
       * Called when an end tag is seen for one of the types of tags associated
1364
       * with this Action.
1365
       */
1366
      public void end(HTML.Tag t)
1367
      {
1368
        inStyleTag = false;
1369
      }
1370
    }
1371
 
1372
    class TitleAction extends TagAction
1373
    {
1374
      /**
1375
       * This method is called when a start tag is seen for one of the types
1376
       * of tags associated with this Action.
1377
       */
1378
      public void start(HTML.Tag t, MutableAttributeSet a)
1379
        throws NotImplementedException
1380
      {
1381
        // FIXME: Implement.
1382
      }
1383
 
1384
      /**
1385
       * Called when an end tag is seen for one of the types of tags associated
1386
       * with this Action.
1387
       */
1388
      public void end(HTML.Tag t)
1389
        throws NotImplementedException
1390
      {
1391
        // FIXME: Implement.
1392
      }
1393
    }
1394
 
1395
    public HTMLReader(int offset)
1396
    {
1397
      this (offset, 0, 0, null);
1398
    }
1399
 
1400
    public HTMLReader(int offset, int popDepth, int pushDepth,
1401
                      HTML.Tag insertTag)
1402
    {
1403
      this.insertTag = insertTag;
1404
      this.offset = offset;
1405
      this.popDepth = popDepth;
1406
      this.pushDepth = pushDepth;
1407
      threshold = getTokenThreshold();
1408
      initTags();
1409
    }
1410
 
1411
    void initTags()
1412
    {
1413
      tagToAction = new HashMap(72);
1414
      CharacterAction characterAction = new CharacterAction();
1415
      HiddenAction hiddenAction = new HiddenAction();
1416
      AreaAction areaAction = new AreaAction();
1417
      BaseAction baseAction = new BaseAction();
1418
      BlockAction blockAction = new BlockAction();
1419
      SpecialAction specialAction = new SpecialAction();
1420
      ParagraphAction paragraphAction = new ParagraphAction();
1421
      HeadAction headAction = new HeadAction();
1422
      FormAction formAction = new FormAction();
1423
      IsindexAction isindexAction = new IsindexAction();
1424
      LinkAction linkAction = new LinkAction();
1425
      MapAction mapAction = new MapAction();
1426
      PreAction preAction = new PreAction();
1427
      MetaAction metaAction = new MetaAction();
1428
      StyleAction styleAction = new StyleAction();
1429
      TitleAction titleAction = new TitleAction();
1430
 
1431
      ConvertAction convertAction = new ConvertAction();
1432
      tagToAction.put(HTML.Tag.A, characterAction);
1433
      tagToAction.put(HTML.Tag.ADDRESS, characterAction);
1434
      tagToAction.put(HTML.Tag.APPLET, hiddenAction);
1435
      tagToAction.put(HTML.Tag.AREA, areaAction);
1436
      tagToAction.put(HTML.Tag.B, characterAction);
1437
      tagToAction.put(HTML.Tag.BASE, baseAction);
1438
      tagToAction.put(HTML.Tag.BASEFONT, characterAction);
1439
      tagToAction.put(HTML.Tag.BIG, characterAction);
1440
      tagToAction.put(HTML.Tag.BLOCKQUOTE, blockAction);
1441
      tagToAction.put(HTML.Tag.BODY, blockAction);
1442
      tagToAction.put(HTML.Tag.BR, specialAction);
1443
      tagToAction.put(HTML.Tag.CAPTION, blockAction);
1444
      tagToAction.put(HTML.Tag.CENTER, blockAction);
1445
      tagToAction.put(HTML.Tag.CITE, characterAction);
1446
      tagToAction.put(HTML.Tag.CODE, characterAction);
1447
      tagToAction.put(HTML.Tag.DD, blockAction);
1448
      tagToAction.put(HTML.Tag.DFN, characterAction);
1449
      tagToAction.put(HTML.Tag.DIR, blockAction);
1450
      tagToAction.put(HTML.Tag.DIV, blockAction);
1451
      tagToAction.put(HTML.Tag.DL, blockAction);
1452
      tagToAction.put(HTML.Tag.DT, paragraphAction);
1453
      tagToAction.put(HTML.Tag.EM, characterAction);
1454
      tagToAction.put(HTML.Tag.FONT, convertAction);
1455
      tagToAction.put(HTML.Tag.FORM, new FormTagAction());
1456
      tagToAction.put(HTML.Tag.FRAME, specialAction);
1457
      tagToAction.put(HTML.Tag.FRAMESET, blockAction);
1458
      tagToAction.put(HTML.Tag.H1, paragraphAction);
1459
      tagToAction.put(HTML.Tag.H2, paragraphAction);
1460
      tagToAction.put(HTML.Tag.H3, paragraphAction);
1461
      tagToAction.put(HTML.Tag.H4, paragraphAction);
1462
      tagToAction.put(HTML.Tag.H5, paragraphAction);
1463
      tagToAction.put(HTML.Tag.H6, paragraphAction);
1464
      tagToAction.put(HTML.Tag.HEAD, headAction);
1465
      tagToAction.put(HTML.Tag.HR, specialAction);
1466
      tagToAction.put(HTML.Tag.HTML, blockAction);
1467
      tagToAction.put(HTML.Tag.I, characterAction);
1468
      tagToAction.put(HTML.Tag.IMG, specialAction);
1469
      tagToAction.put(HTML.Tag.INPUT, formAction);
1470
      tagToAction.put(HTML.Tag.ISINDEX, isindexAction);
1471
      tagToAction.put(HTML.Tag.KBD, characterAction);
1472
      tagToAction.put(HTML.Tag.LI, blockAction);
1473
      tagToAction.put(HTML.Tag.LINK, linkAction);
1474
      tagToAction.put(HTML.Tag.MAP, mapAction);
1475
      tagToAction.put(HTML.Tag.MENU, blockAction);
1476
      tagToAction.put(HTML.Tag.META, metaAction);
1477
      tagToAction.put(HTML.Tag.NOFRAMES, blockAction);
1478
      tagToAction.put(HTML.Tag.OBJECT, specialAction);
1479
      tagToAction.put(HTML.Tag.OL, blockAction);
1480
      tagToAction.put(HTML.Tag.OPTION, formAction);
1481
      tagToAction.put(HTML.Tag.P, paragraphAction);
1482
      tagToAction.put(HTML.Tag.PARAM, hiddenAction);
1483
      tagToAction.put(HTML.Tag.PRE, preAction);
1484
      tagToAction.put(HTML.Tag.SAMP, characterAction);
1485
      tagToAction.put(HTML.Tag.SCRIPT, hiddenAction);
1486
      tagToAction.put(HTML.Tag.SELECT, formAction);
1487
      tagToAction.put(HTML.Tag.SMALL, characterAction);
1488
      tagToAction.put(HTML.Tag.STRIKE, characterAction);
1489
      tagToAction.put(HTML.Tag.S, characterAction);
1490
      tagToAction.put(HTML.Tag.STRONG, characterAction);
1491
      tagToAction.put(HTML.Tag.STYLE, styleAction);
1492
      tagToAction.put(HTML.Tag.SUB, characterAction);
1493
      tagToAction.put(HTML.Tag.SUP, characterAction);
1494
      tagToAction.put(HTML.Tag.TABLE, blockAction);
1495
      tagToAction.put(HTML.Tag.TD, blockAction);
1496
      tagToAction.put(HTML.Tag.TEXTAREA, formAction);
1497
      tagToAction.put(HTML.Tag.TH, blockAction);
1498
      tagToAction.put(HTML.Tag.TITLE, titleAction);
1499
      tagToAction.put(HTML.Tag.TR, blockAction);
1500
      tagToAction.put(HTML.Tag.TT, characterAction);
1501
      tagToAction.put(HTML.Tag.U, characterAction);
1502
      tagToAction.put(HTML.Tag.UL, blockAction);
1503
      tagToAction.put(HTML.Tag.VAR, characterAction);
1504
    }
1505
 
1506
    /**
1507
     * Pushes the current character style onto the stack.
1508
     *
1509
     */
1510
    protected void pushCharacterStyle()
1511
    {
1512
      charAttrStack.push(charAttr.copyAttributes());
1513
    }
1514
 
1515
    /**
1516
     * Pops a character style off of the stack and uses it as the
1517
     * current character style.
1518
     *
1519
     */
1520
    protected void popCharacterStyle()
1521
    {
1522
      if (!charAttrStack.isEmpty())
1523
        charAttr = (MutableAttributeSet) charAttrStack.pop();
1524
    }
1525
 
1526
    /**
1527
     * Registers a given tag with a given Action.  All of the well-known tags
1528
     * are registered by default, but this method can change their behaviour
1529
     * or add support for custom or currently unsupported tags.
1530
     *
1531
     * @param t the Tag to register
1532
     * @param a the Action for the Tag
1533
     */
1534
    protected void registerTag(HTML.Tag t, HTMLDocument.HTMLReader.TagAction a)
1535
    {
1536
      tagToAction.put (t, a);
1537
    }
1538
 
1539
    /**
1540
     * This is the last method called on the HTMLReader, allowing any pending
1541
     * changes to be flushed to the HTMLDocument.
1542
     */
1543
    public void flush() throws BadLocationException
1544
    {
1545
      flushImpl();
1546
    }
1547
 
1548
    /**
1549
     * Flushes the buffer and handle partial inserts.
1550
     *
1551
     */
1552
    private void flushImpl()
1553
      throws BadLocationException
1554
    {
1555
      int oldLen = getLength();
1556
      int size = parseBuffer.size();
1557
      ElementSpec[] elems = new ElementSpec[size];
1558
      parseBuffer.copyInto(elems);
1559
      if (oldLen == 0)
1560
        create(elems);
1561
      else
1562
        insert(offset, elems);
1563
      parseBuffer.removeAllElements();
1564
      offset += getLength() - oldLen;
1565
    }
1566
 
1567
    /**
1568
     * This method is called by the parser to indicate a block of
1569
     * text was encountered.  Should insert the text appropriately.
1570
     *
1571
     * @param data the text that was inserted
1572
     * @param pos the position at which the text was inserted
1573
     */
1574
    public void handleText(char[] data, int pos)
1575
    {
1576
      if (shouldInsert() && data != null && data.length > 0)
1577
        {
1578
          if (inTextArea)
1579
            textAreaContent(data);
1580
          else if (inPreTag)
1581
            preContent(data);
1582
          else if (option != null)
1583
            option.setLabel(new String(data));
1584
          else if (inStyleTag)
1585
            {
1586
              if (styles == null)
1587
                styles = new ArrayList();
1588
              styles.add(new String(data));
1589
            }
1590
          else
1591
            addContent(data, 0, data.length);
1592
 
1593
        }
1594
    }
1595
 
1596
    /**
1597
     * Checks if the HTML tag should be inserted. The tags before insert tag (if
1598
     * specified) are not inserted. Also, the tags after the end of the html are
1599
     * not inserted.
1600
     *
1601
     * @return true if the tag should be inserted, false otherwise.
1602
     */
1603
    private boolean shouldInsert()
1604
    {
1605
      return ! endHTMLEncountered
1606
             && (insertTagEncountered || insertTag == null);
1607
    }
1608
 
1609
    /**
1610
     * This method is called by the parser and should route the call to the
1611
     * proper handler for the tag.
1612
     *
1613
     * @param t the HTML.Tag
1614
     * @param a the attribute set
1615
     * @param pos the position at which the tag was encountered
1616
     */
1617
    public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
1618
    {
1619
      if (t == insertTag)
1620
        insertTagEncountered = true;
1621
 
1622
      if (shouldInsert())
1623
        {
1624
          TagAction action = (TagAction) tagToAction.get(t);
1625
          if (action != null)
1626
            action.start(t, a);
1627
        }
1628
    }
1629
 
1630
    /**
1631
     * This method called by parser to handle a comment block.
1632
     *
1633
     * @param data the comment
1634
     * @param pos the position at which the comment was encountered
1635
     */
1636
    public void handleComment(char[] data, int pos)
1637
    {
1638
      if (shouldInsert())
1639
        {
1640
          TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
1641
          if (action != null)
1642
            {
1643
              action.start(HTML.Tag.COMMENT, new SimpleAttributeSet());
1644
              action.end(HTML.Tag.COMMENT);
1645
            }
1646
        }
1647
    }
1648
 
1649
    /**
1650
     * This method is called by the parser and should route the call to the
1651
     * proper handler for the tag.
1652
     *
1653
     * @param t the HTML.Tag
1654
     * @param pos the position at which the tag was encountered
1655
     */
1656
    public void handleEndTag(HTML.Tag t, int pos)
1657
    {
1658
      if (shouldInsert())
1659
        {
1660
          // If this is the </html> tag we need to stop calling the Actions
1661
          if (t == HTML.Tag.HTML)
1662
            endHTMLEncountered = true;
1663
 
1664
          TagAction action = (TagAction) tagToAction.get(t);
1665
          if (action != null)
1666
            action.end(t);
1667
        }
1668
    }
1669
 
1670
    /**
1671
     * This is a callback from the parser that should be routed to the
1672
     * appropriate handler for the tag.
1673
     *
1674
     * @param t the HTML.Tag that was encountered
1675
     * @param a the attribute set
1676
     * @param pos the position at which the tag was encountered
1677
     */
1678
    public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos)
1679
    {
1680
      if (t == insertTag)
1681
        insertTagEncountered = true;
1682
 
1683
      if (shouldInsert())
1684
        {
1685
          TagAction action = (TagAction) tagToAction.get(t);
1686
          if (action != null)
1687
            {
1688
              action.start(t, a);
1689
              action.end(t);
1690
            }
1691
        }
1692
    }
1693
 
1694
    /**
1695
     * This is invoked after the stream has been parsed but before it has been
1696
     * flushed.
1697
     *
1698
     * @param eol one of \n, \r, or \r\n, whichever was encountered the most in
1699
     * parsing the stream
1700
     * @since 1.3
1701
     */
1702
    public void handleEndOfLineString(String eol)
1703
    {
1704
      // FIXME: Implement.
1705
    }
1706
 
1707
    /**
1708
     * Adds the given text to the textarea document.  Called only when we are
1709
     * within a textarea.
1710
     *
1711
     * @param data the text to add to the textarea
1712
     */
1713
    protected void textAreaContent(char[] data)
1714
    {
1715
      try
1716
        {
1717
          int offset = textAreaDocument.getLength();
1718
          String text = new String(data);
1719
          textAreaDocument.setInitialText(text);
1720
          textAreaDocument.insertString(offset, text, null);
1721
        }
1722
      catch (BadLocationException ex)
1723
        {
1724
          // Must not happen as we insert at a model location that we
1725
          // got from the document itself.
1726
          assert false;
1727
        }
1728
    }
1729
 
1730
    /**
1731
     * Adds the given text that was encountered in a <PRE> element.
1732
     * This adds synthesized lines to hold the text runs.
1733
     *
1734
     * @param data the text
1735
     */
1736
    protected void preContent(char[] data)
1737
    {
1738
      int start = 0;
1739
      for (int i = 0; i < data.length; i++)
1740
        {
1741
          if (data[i] == '\n')
1742
            {
1743
              addContent(data, start, i - start + 1);
1744
              blockClose(HTML.Tag.IMPLIED);
1745
              MutableAttributeSet atts = new SimpleAttributeSet();
1746
              atts.addAttribute(CSS.Attribute.WHITE_SPACE, "pre");
1747
              blockOpen(HTML.Tag.IMPLIED, atts);
1748
              start = i + 1;
1749
            }
1750
        }
1751
      if (start < data.length)
1752
        {
1753
          // Add remaining last line.
1754
          addContent(data, start, data.length - start);
1755
        }
1756
    }
1757
 
1758
    /**
1759
     * Instructs the parse buffer to create a block element with the given
1760
     * attributes.
1761
     *
1762
     * @param t the tag that requires opening a new block
1763
     * @param attr the attribute set for the new block
1764
     */
1765
    protected void blockOpen(HTML.Tag t, MutableAttributeSet attr)
1766
    {
1767
      if (inImpliedParagraph())
1768
        blockClose(HTML.Tag.IMPLIED);
1769
 
1770
      // Push the new tag on top of the stack.
1771
      parseStack.push(t);
1772
 
1773
      DefaultStyledDocument.ElementSpec element;
1774
 
1775
      AbstractDocument.AttributeContext ctx = getAttributeContext();
1776
      AttributeSet copy = attr.copyAttributes();
1777
      copy = ctx.addAttribute(copy, StyleConstants.NameAttribute, t);
1778
      element = new DefaultStyledDocument.ElementSpec(copy,
1779
                               DefaultStyledDocument.ElementSpec.StartTagType);
1780
      parseBuffer.addElement(element);
1781
    }
1782
 
1783
    /**
1784
     * Returns true when we are currently inside a paragraph, either
1785
     * a real one or an implied, false otherwise.
1786
     *
1787
     * @return
1788
     */
1789
    private boolean inParagraph()
1790
    {
1791
      boolean inParagraph = false;
1792
      if (! parseStack.isEmpty())
1793
        {
1794
          HTML.Tag top = parseStack.peek();
1795
          inParagraph = top == HTML.Tag.P || top == HTML.Tag.IMPLIED;
1796
        }
1797
      return inParagraph;
1798
    }
1799
 
1800
    private boolean inImpliedParagraph()
1801
    {
1802
      boolean inParagraph = false;
1803
      if (! parseStack.isEmpty())
1804
        {
1805
          HTML.Tag top = parseStack.peek();
1806
          inParagraph = top == HTML.Tag.IMPLIED;
1807
        }
1808
      return inParagraph;
1809
    }
1810
 
1811
    /**
1812
     * Instructs the parse buffer to close the block element associated with
1813
     * the given HTML.Tag
1814
     *
1815
     * @param t the HTML.Tag that is closing its block
1816
     */
1817
    protected void blockClose(HTML.Tag t)
1818
    {
1819
      DefaultStyledDocument.ElementSpec element;
1820
 
1821
      if (inImpliedParagraph() && t != HTML.Tag.IMPLIED)
1822
        blockClose(HTML.Tag.IMPLIED);
1823
 
1824
      // Pull the token from the stack.
1825
      if (! parseStack.isEmpty()) // Just to be sure.
1826
        parseStack.pop();
1827
 
1828
      // If the previous tag is a start tag then we insert a synthetic
1829
      // content tag.
1830
      DefaultStyledDocument.ElementSpec prev;
1831
      prev = parseBuffer.size() > 0 ? (DefaultStyledDocument.ElementSpec)
1832
                                parseBuffer.get(parseBuffer.size() - 1) : null;
1833
      if (prev != null &&
1834
          prev.getType() == DefaultStyledDocument.ElementSpec.StartTagType)
1835
        {
1836
          addContent(new char[]{' '}, 0, 1);
1837
        }
1838
 
1839
      element = new DefaultStyledDocument.ElementSpec(null,
1840
                                DefaultStyledDocument.ElementSpec.EndTagType);
1841
      parseBuffer.addElement(element);
1842
    }
1843
 
1844
    /**
1845
     * Adds text to the appropriate context using the current character
1846
     * attribute set.
1847
     *
1848
     * @param data the text to add
1849
     * @param offs the offset at which to add it
1850
     * @param length the length of the text to add
1851
     */
1852
    protected void addContent(char[] data, int offs, int length)
1853
    {
1854
      addContent(data, offs, length, true);
1855
    }
1856
 
1857
    /**
1858
     * Adds text to the appropriate context using the current character
1859
     * attribute set, and possibly generating an IMPLIED Tag if necessary.
1860
     *
1861
     * @param data the text to add
1862
     * @param offs the offset at which to add it
1863
     * @param length the length of the text to add
1864
     * @param generateImpliedPIfNecessary whether or not we should generate
1865
     * an HTML.Tag.IMPLIED tag if necessary
1866
     */
1867
    protected void addContent(char[] data, int offs, int length,
1868
                              boolean generateImpliedPIfNecessary)
1869
    {
1870
      if (generateImpliedPIfNecessary && ! inParagraph())
1871
        {
1872
          blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
1873
        }
1874
 
1875
      AbstractDocument.AttributeContext ctx = getAttributeContext();
1876
      DefaultStyledDocument.ElementSpec element;
1877
      AttributeSet attributes = null;
1878
 
1879
      // Copy the attribute set, don't use the same object because
1880
      // it may change
1881
      if (charAttr != null)
1882
        attributes = charAttr.copyAttributes();
1883
      else
1884
        attributes = ctx.getEmptySet();
1885
      attributes = ctx.addAttribute(attributes, StyleConstants.NameAttribute,
1886
                                    HTML.Tag.CONTENT);
1887
      element = new DefaultStyledDocument.ElementSpec(attributes,
1888
                                DefaultStyledDocument.ElementSpec.ContentType,
1889
                                data, offs, length);
1890
 
1891
      // Add the element to the buffer
1892
      parseBuffer.addElement(element);
1893
 
1894
      if (parseBuffer.size() > threshold)
1895
        {
1896
          if (threshold <= MAX_THRESHOLD)
1897
            threshold *= GROW_THRESHOLD;
1898
          try
1899
            {
1900
              flushImpl();
1901
            }
1902
          catch (BadLocationException ble)
1903
            {
1904
              // TODO: what to do here?
1905
            }
1906
        }
1907
    }
1908
 
1909
    /**
1910
     * Adds content that is specified in the attribute set.
1911
     *
1912
     * @param t the HTML.Tag
1913
     * @param a the attribute set specifying the special content
1914
     */
1915
    protected void addSpecialElement(HTML.Tag t, MutableAttributeSet a)
1916
    {
1917
      if (t != HTML.Tag.FRAME && ! inParagraph())
1918
        {
1919
          blockOpen(HTML.Tag.IMPLIED, new SimpleAttributeSet());
1920
        }
1921
 
1922
      a.addAttribute(StyleConstants.NameAttribute, t);
1923
 
1924
      // The two spaces are required because some special elements like HR
1925
      // must be broken. At least two characters are needed to break into the
1926
      // two parts.
1927
      DefaultStyledDocument.ElementSpec spec =
1928
        new DefaultStyledDocument.ElementSpec(a.copyAttributes(),
1929
          DefaultStyledDocument.ElementSpec.ContentType,
1930
          new char[] {' '}, 0, 1 );
1931
      parseBuffer.add(spec);
1932
    }
1933
 
1934
  }
1935
 
1936
  /**
1937
   * Gets the reader for the parser to use when loading the document with HTML.
1938
   *
1939
   * @param pos - the starting position
1940
   * @return - the reader
1941
   */
1942
  public HTMLEditorKit.ParserCallback getReader(int pos)
1943
  {
1944
    return new HTMLReader(pos);
1945
  }
1946
 
1947
  /**
1948
   * Gets the reader for the parser to use when loading the document with HTML.
1949
   *
1950
   * @param pos - the starting position
1951
   * @param popDepth - the number of EndTagTypes to generate before inserting
1952
   * @param pushDepth - the number of StartTagTypes with a direction
1953
   * of JoinNextDirection that should be generated before inserting,
1954
   * but after the end tags have been generated.
1955
   * @param insertTag - the first tag to start inserting into document
1956
   * @return - the reader
1957
   */
1958
  public HTMLEditorKit.ParserCallback getReader(int pos,
1959
                                                int popDepth,
1960
                                                int pushDepth,
1961
                                                HTML.Tag insertTag)
1962
  {
1963
    return new HTMLReader(pos, popDepth, pushDepth, insertTag);
1964
  }
1965
 
1966
  /**
1967
   * Gets the reader for the parser to use when inserting the HTML fragment into
1968
   * the document. Checks if the parser is present, sets the parent in the
1969
   * element stack and removes any actions for BODY (it can be only one body in
1970
   * a HTMLDocument).
1971
   *
1972
   * @param pos - the starting position
1973
   * @param popDepth - the number of EndTagTypes to generate before inserting
1974
   * @param pushDepth - the number of StartTagTypes with a direction of
1975
   *          JoinNextDirection that should be generated before inserting, but
1976
   *          after the end tags have been generated.
1977
   * @param insertTag - the first tag to start inserting into document
1978
   * @param parent the element that will be the parent in the document. HTML
1979
   *          parsing includes checks for the parent, so it must be available.
1980
   * @return - the reader
1981
   * @throws IllegalStateException if the parsert is not set.
1982
   */
1983
  public HTMLEditorKit.ParserCallback getInsertingReader(int pos, int popDepth,
1984
                                                         int pushDepth,
1985
                                                         HTML.Tag insertTag,
1986
                                                         final Element parent)
1987
      throws IllegalStateException
1988
  {
1989
    if (parser == null)
1990
      throw new IllegalStateException("Parser has not been set");
1991
 
1992
    HTMLReader reader = new HTMLReader(pos, popDepth, pushDepth, insertTag)
1993
    {
1994
      /**
1995
       * Ignore BODY.
1996
       */
1997
      public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
1998
      {
1999
        if (t != HTML.Tag.BODY)
2000
          super.handleStartTag(t, a, pos);
2001
      }
2002
 
2003
      /**
2004
       * Ignore BODY.
2005
       */
2006
      public void handleEndTag(HTML.Tag t, int pos)
2007
      {
2008
        if (t != HTML.Tag.BODY)
2009
          super.handleEndTag(t, pos);
2010
      }
2011
    };
2012
 
2013
    return reader;
2014
  }
2015
 
2016
  /**
2017
   * Gets the child element that contains the attribute with the value or null.
2018
   * Not thread-safe.
2019
   *
2020
   * @param e - the element to begin search at
2021
   * @param attribute - the desired attribute
2022
   * @param value - the desired value
2023
   * @return the element found with the attribute and value specified or null if
2024
   *         it is not found.
2025
   */
2026
  public Element getElement(Element e, Object attribute, Object value)
2027
  {
2028
    if (e != null)
2029
      {
2030
        if (e.getAttributes().containsAttribute(attribute, value))
2031
          return e;
2032
 
2033
        int count = e.getElementCount();
2034
        for (int j = 0; j < count; j++)
2035
          {
2036
            Element child = e.getElement(j);
2037
            if (child.getAttributes().containsAttribute(attribute, value))
2038
              return child;
2039
 
2040
            Element grandChild = getElement(child, attribute, value);
2041
            if (grandChild != null)
2042
              return grandChild;
2043
          }
2044
      }
2045
    return null;
2046
  }
2047
 
2048
  /**
2049
   * Returns the element that has the given id Attribute (for instance, &lt;p id
2050
   * ='my paragraph &gt;'). If it is not found, null is returned. The HTML tag,
2051
   * having this attribute, is not checked by this method and can be any. The
2052
   * method is not thread-safe.
2053
   *
2054
   * @param attrId - the value of the attribute id to look for
2055
   * @return the element that has the given id.
2056
   */
2057
  public Element getElement(String attrId)
2058
  {
2059
    return getElement(getDefaultRootElement(), HTML.Attribute.ID,
2060
                      attrId);
2061
  }
2062
 
2063
  /**
2064
   * Replaces the children of the given element with the contents of
2065
   * the string. The document must have an HTMLEditorKit.Parser set.
2066
   * This will be seen as at least two events, n inserts followed by a remove.
2067
   *
2068
   * @param elem - the brance element whose children will be replaced
2069
   * @param htmlText - the string to be parsed and assigned to element.
2070
   * @throws BadLocationException
2071
   * @throws IOException
2072
   * @throws IllegalArgumentException - if elem is a leaf
2073
   * @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set
2074
   */
2075
  public void setInnerHTML(Element elem, String htmlText)
2076
    throws BadLocationException, IOException
2077
  {
2078
    if (elem.isLeaf())
2079
      throw new IllegalArgumentException("Element is a leaf");
2080
 
2081
    int start = elem.getStartOffset();
2082
    int end = elem.getEndOffset();
2083
 
2084
    HTMLEditorKit.ParserCallback reader = getInsertingReader(
2085
      end, 0, 0, HTML.Tag.BODY, elem);
2086
 
2087
    // TODO charset
2088
    getParser().parse(new StringReader(htmlText), reader, true);
2089
 
2090
    // Remove the previous content
2091
    remove(start, end - start);
2092
  }
2093
 
2094
  /**
2095
   * Replaces the given element in the parent with the string. When replacing a
2096
   * leaf, this will attempt to make sure there is a newline present if one is
2097
   * needed. This may result in an additional element being inserted. This will
2098
   * be seen as at least two events, n inserts followed by a remove. The
2099
   * HTMLEditorKit.Parser must be set.
2100
   *
2101
   * @param elem - the branch element whose parent will be replaced
2102
   * @param htmlText - the string to be parsed and assigned to elem
2103
   * @throws BadLocationException
2104
   * @throws IOException
2105
   * @throws IllegalStateException - if parser is not set
2106
   */
2107
public void setOuterHTML(Element elem, String htmlText)
2108
      throws BadLocationException, IOException
2109
  {
2110
    // Remove the current element:
2111
    int start = elem.getStartOffset();
2112
    int end = elem.getEndOffset();
2113
 
2114
    remove(start, end-start);
2115
 
2116
    HTMLEditorKit.ParserCallback reader = getInsertingReader(
2117
      start, 0, 0, HTML.Tag.BODY, elem);
2118
 
2119
    // TODO charset
2120
    getParser().parse(new StringReader(htmlText), reader, true);
2121
  }
2122
 
2123
  /**
2124
   * Inserts the string before the start of the given element. The parser must
2125
   * be set.
2126
   *
2127
   * @param elem - the element to be the root for the new text.
2128
   * @param htmlText - the string to be parsed and assigned to elem
2129
   * @throws BadLocationException
2130
   * @throws IOException
2131
   * @throws IllegalStateException - if parser has not been set
2132
   */
2133
  public void insertBeforeStart(Element elem, String htmlText)
2134
      throws BadLocationException, IOException
2135
  {
2136
    HTMLEditorKit.ParserCallback reader = getInsertingReader(
2137
      elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem);
2138
 
2139
    // TODO charset
2140
    getParser().parse(new StringReader(htmlText), reader, true);
2141
  }
2142
 
2143
  /**
2144
   * Inserts the string at the end of the element. If elem's children are
2145
   * leaves, and the character at elem.getEndOffset() - 1 is a newline, then it
2146
   * will be inserted before the newline. The parser must be set.
2147
   *
2148
   * @param elem - the element to be the root for the new text
2149
   * @param htmlText - the text to insert
2150
   * @throws BadLocationException
2151
   * @throws IOException
2152
   * @throws IllegalStateException - if parser is not set
2153
   */
2154
  public void insertBeforeEnd(Element elem, String htmlText)
2155
      throws BadLocationException, IOException
2156
  {
2157
    HTMLEditorKit.ParserCallback reader = getInsertingReader(
2158
      elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
2159
 
2160
    // TODO charset
2161
    getParser().parse(new StringReader(htmlText), reader, true);
2162
 
2163
  }
2164
 
2165
  /**
2166
   * Inserts the string after the end of the given element.
2167
   * The parser must be set.
2168
   *
2169
   * @param elem - the element to be the root for the new text
2170
   * @param htmlText - the text to insert
2171
   * @throws BadLocationException
2172
   * @throws IOException
2173
   * @throws IllegalStateException - if parser is not set
2174
   */
2175
  public void insertAfterEnd(Element elem, String htmlText)
2176
      throws BadLocationException, IOException
2177
  {
2178
    HTMLEditorKit.ParserCallback reader = getInsertingReader(
2179
      elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
2180
 
2181
    // TODO charset
2182
    getParser().parse(new StringReader(htmlText), reader, true);
2183
  }
2184
 
2185
  /**
2186
   * Inserts the string at the start of the element.
2187
   * The parser must be set.
2188
   *
2189
   * @param elem - the element to be the root for the new text
2190
   * @param htmlText - the text to insert
2191
   * @throws BadLocationException
2192
   * @throws IOException
2193
   * @throws IllegalStateException - if parser is not set
2194
   */
2195
  public void insertAfterStart(Element elem, String htmlText)
2196
      throws BadLocationException, IOException
2197
  {
2198
    HTMLEditorKit.ParserCallback reader = getInsertingReader(
2199
      elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem);
2200
 
2201
    // TODO charset
2202
    getParser().parse(new StringReader(htmlText), reader, true);
2203
  }
2204
 
2205
  /**
2206
   * Overridden to tag content with the synthetic HTML.Tag.CONTENT
2207
   * tag.
2208
   */
2209
  protected void insertUpdate(DefaultDocumentEvent evt, AttributeSet att)
2210
  {
2211
    if (att == null)
2212
      {
2213
        SimpleAttributeSet sas = new SimpleAttributeSet();
2214
        sas.addAttribute(StyleConstants.NameAttribute, HTML.Tag.CONTENT);
2215
        att = sas;
2216
      }
2217
    super.insertUpdate(evt, att);
2218
  }
2219
 
2220
  /**
2221
   * Returns <code>true</code> when this document is inside a frame,
2222
   * <code>false</code> otherwise.
2223
   *
2224
   * @return <code>true</code> when this document is inside a frame,
2225
   *         <code>false</code> otherwise
2226
   */
2227
  boolean isFrameDocument()
2228
  {
2229
    return frameDocument;
2230
  }
2231
 
2232
  /**
2233
   * Set <code>true</code> when this document is inside a frame,
2234
   * <code>false</code> otherwise.
2235
   *
2236
   * @param frameDoc <code>true</code> when this document is inside a frame,
2237
   *                 <code>false</code> otherwise
2238
   */
2239
  void setFrameDocument(boolean frameDoc)
2240
  {
2241
    frameDocument = frameDoc;
2242
  }
2243
 
2244
  /**
2245
   * Returns the target that is specified in the base tag, if this is the case.
2246
   *
2247
   * @return the target that is specified in the base tag, if this is the case
2248
   */
2249
  String getBaseTarget()
2250
  {
2251
    return baseTarget;
2252
  }
2253
 
2254
  /**
2255
   * Updates the A tag's pseudo class value in response to a hyperlink
2256
   * action.
2257
   *
2258
   * @param el the corresponding element
2259
   * @param value the new value
2260
   */
2261
  void updateSpecialClass(Element el, HTML.Attribute cl, String value)
2262
  {
2263
    try
2264
    {
2265
      writeLock();
2266
      DefaultDocumentEvent ev =
2267
        new DefaultDocumentEvent(el.getStartOffset(), 1,
2268
                                 DocumentEvent.EventType.CHANGE);
2269
      AttributeSet elAtts = el.getAttributes();
2270
      AttributeSet anchorAtts = (AttributeSet) elAtts.getAttribute(HTML.Tag.A);
2271
      if (anchorAtts != null)
2272
        {
2273
          AttributeSet copy = elAtts.copyAttributes();
2274
          StyleSheet ss = getStyleSheet();
2275
          if (value != null)
2276
            {
2277
              anchorAtts = ss.addAttribute(anchorAtts, cl, value);
2278
            }
2279
          else
2280
            {
2281
              anchorAtts = ss.removeAttribute(anchorAtts, cl);
2282
            }
2283
          MutableAttributeSet matts = (MutableAttributeSet) elAtts;
2284
          ev.addEdit(new AttributeUndoableEdit(el, copy, false));
2285
          matts.removeAttribute(HTML.Tag.A);
2286
          matts.addAttribute(HTML.Tag.A, anchorAtts);
2287
          ev.end();
2288
          fireChangedUpdate(ev);
2289
          fireUndoableEditUpdate(new UndoableEditEvent(this, ev));
2290
        }
2291
    }
2292
  finally
2293
    {
2294
      writeUnlock();
2295
    }
2296
  }
2297
 
2298
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.