home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / jfc.bin / HTMLDocument.java < prev    next >
Text File  |  1998-02-26  |  38KB  |  1,472 lines

  1. /*
  2.  * @(#)HTMLDocument.java    1.53 98/02/02
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text.html;
  21.  
  22. import java.awt.Color;
  23. import java.awt.Component;
  24. import java.util.Vector;
  25. import java.util.Stack;
  26. import java.util.Enumeration;
  27. import java.net.URL;
  28. import java.net.MalformedURLException;
  29. import java.io.*;
  30. import com.sun.java.swing.*;
  31. import com.sun.java.swing.text.*;
  32. import com.sun.java.swing.Icon;
  33. import com.sun.java.swing.ImageIcon;
  34.  
  35. /**
  36.  * A document that maintains an html element structure.
  37.  * 
  38.  * @author  Timothy Prinzing
  39.  * @author  Sara Swanson
  40.  * @author  Makarand Gokhale
  41.  * @version 1.53 02/02/98
  42.  */
  43. class HTMLDocument extends DefaultStyledDocument implements HTMLDefs {
  44.  
  45.    /**
  46.      * The property name for the actual html tag name used
  47.      * as an attribute for the writer.
  48.      */
  49.     public static final String HTMLTagAttribute = "htmltag";
  50.  
  51.    /**
  52.      * The property name for the base href which is used to
  53.      * define the absolute URL against relatives URLs in the document.
  54.      */
  55.     public static final String BaseHrefProperty = "basehref";
  56.  
  57.    /**
  58.      * The property name for the BGCOLOR which is used to
  59.      * define the Background Color for a HTML Document
  60.      */
  61.     public static final String BGCOLOR = "BGCOLOR";
  62.  
  63.    /**
  64.      * The property name for the BACKGROUND (Image) which is used to
  65.      * define the Background Image for a HTML Document
  66.      */
  67.     public static final String BACKGROUND = "BACKGROUND";
  68.  
  69.    /**
  70.      * The property name for the Keywords  which is used to
  71.      * define the keywords for a HTML Document
  72.      */
  73.     public static final String KEYWORDS = "Keywords";
  74.  
  75.    /**
  76.      * The property name for the TEXT  which is used to
  77.      * define the text color for a HTML Document
  78.      */
  79.     public static final String TEXT = "TEXT";
  80.  
  81.    /**
  82.      * The property name for the LINK  which is used to
  83.      * define the  hyperlink color which is NOT Visited or NOT active
  84.      */
  85.     public static final String LINK = "LINK";
  86.  
  87.    /**
  88.      * The property name for the VLINK  which is used to
  89.      * define the visited hyperlink color for a HTML Document
  90.      */
  91.     public static final String VLINK = "VLINK";
  92.  
  93.    /**
  94.      * The property name for the ALINK  which is used to
  95.      * define the  active hyperlink color for a HTML Document
  96.      */
  97.     public static final String ALINK = "ALINK";
  98.  
  99.    /**
  100.      * The attribute name used to identify INPUT tag elements.
  101.      */
  102.     public static final String HTMLInputComponent = "input-component";
  103.  
  104.  
  105.     /**
  106.      * Constructs an html document.
  107.      */
  108.     public HTMLDocument() {
  109.     super();
  110.     }
  111.  
  112.     /**
  113.      * Constructs an html document with the default content
  114.      * storage implementation and a shared set of styles.
  115.      *
  116.      * @param styles the styles
  117.      */
  118.     public HTMLDocument(StyleContext styles) {
  119.         super(new StringContent(BUFFER_SIZE_DEFAULT), styles);
  120.     }
  121.  
  122.     public void setRootElementAttributes(MutableAttributeSet attr) {
  123.     Element section = getDefaultRootElement();
  124.     try {
  125.         writeLock();
  126.             MutableAttributeSet mattr = (MutableAttributeSet) section.getAttributes();
  127.         mattr.addAttributes(attr);
  128.     }
  129.     finally {
  130.         writeUnlock();
  131.     }
  132.     }
  133.  
  134.     public void read(Reader in, int pos) throws IOException {
  135.     Object desc = getProperty(Document.StreamDescriptionProperty);
  136.     if (desc instanceof URL) { 
  137.         reference = (URL) desc;
  138.     }
  139.     HTMLReader reader = new HTMLReader();
  140.     reader.read(pos, in);
  141.     }
  142.  
  143.     /**
  144.      * Inserts new elements in bulk.
  145.      *
  146.      * @param offset the starting offset
  147.      * @data the element data
  148.      * @exception BadLocationException for an invalid starting offset
  149.      * @see StyledDocument#insert
  150.      * @exception BadLocationException  if the given position does not 
  151.      *   represent a valid location in the associated document.
  152.      */
  153.     protected void insert(int offset, ElementSpec[] data) throws BadLocationException {
  154.     super.insert(offset, data);
  155.     }
  156.  
  157.     StyleContext getStyleContext() {
  158.     return (StyleContext) getAttributeContext();
  159.     }
  160.  
  161.     /**
  162.      * Return a vector containing any components on the page that were
  163.      * derived from the contents of a FORM tag.
  164.      */
  165.     public void getComponents(Vector compList) {
  166.     AbstractElement section = (AbstractElement)getDefaultRootElement();
  167.     findComponents(section, compList);
  168.     }
  169.  
  170.     /**
  171.      * A recursive function that searches the model for components and
  172.      * determines if they are FORM components.
  173.      */
  174.     private void findComponents(AbstractElement elem, Vector compList) {
  175.         if (elem.isLeaf()) {
  176.         AttributeSet a = elem.getAttributes();
  177.         String str = new String(HTMLInputComponent);
  178.         if (a.getAttribute(str) != null) {
  179.             compList.addElement((Component)a.getAttribute(
  180.             StyleConstants.ComponentAttribute));
  181.         }
  182.         } else {
  183.             int n = elem.getElementCount();
  184.             for (int i = 0; i < n; i++) {
  185.                 AbstractElement e = (AbstractElement) elem.getElement(i);
  186.                 findComponents(e, compList);
  187.             }
  188.         }
  189.     }
  190.  
  191.     /**
  192.      * The location to resolve relative url's against.  By
  193.      * default this will be the documents url if the document
  194.      * was loaded from a url.  If a base tag is found and
  195.      * can be parsed, it will be used as the reference location.
  196.      */
  197.     URL reference;
  198.  
  199. /**
  200.  * An HTML reader to load a styled document with an HTML
  201.  * element structure. 
  202.  */ 
  203. class HTMLReader extends HTMLParserCallbackDefault {
  204.  
  205.     /**
  206.      * Loads the given input stream (which is expected to 
  207.      * contain valid html) into the given StyledDocument.
  208.      *
  209.      * @param doc the document to read into
  210.      * @param offset the starting offset in the document
  211.      * @param in the input stream
  212.      */
  213.     public void read(int offset, Reader in) throws IOException {
  214.     parser = new html32(in);
  215.     StyleContext context = getStyleContext();
  216.     charAttr = context.addStyle(null, null);
  217.     attr = context.addStyle(null, null);
  218.  
  219.          resolver = getStyle(StyleReader.DEFAULT_STYLE_HIERARCHY);
  220.     String hack = " ";
  221.     ElementSpec es = new ElementSpec(
  222.         null, ElementSpec.ContentType, hack.toCharArray(), 0, 1);
  223.     parseBuffer.addElement(es);
  224.     es = new ElementSpec(null, ElementSpec.EndTagType);
  225.     parseBuffer.addElement(es);
  226.  
  227.     parser.setCallback(this);
  228.     try {
  229.         parser.html();
  230.     } catch (Exception e) {
  231.         e.printStackTrace();
  232.         throw new IOException(e.toString());
  233.     }
  234.  
  235.     ElementSpec[] spec = new ElementSpec[parseBuffer.size()];
  236.     parseBuffer.copyInto(spec);
  237.     try {
  238.         insert(offset, spec);
  239.     } catch (BadLocationException bl) {
  240.         throw new IOException("BadLocationException: " + bl.getMessage());
  241.     }
  242.     }
  243.  
  244.     /**
  245.      * Fetches the CHILD_STYLE from a named style previously added.
  246.      *
  247.      * @param nm  the name of the style
  248.      * @return the style
  249.      */
  250.     public Style getChildStyle(String nm) {
  251.         Style shStyle = getStyle("SH" + nm);
  252.     return (Style)shStyle.getAttribute(StyleReader.CHILD_STYLE);
  253.     }
  254.  
  255.     /**
  256.      * Adds an attribute for the current tag being
  257.      * scanned.
  258.      *
  259.      * @param name the attribute name
  260.      * @param value the attribute value
  261.      */
  262.     public void attributeAction(String name, String value) {
  263.     if (value == null) {
  264.         value = HTMLDefs.NULL_ATTRIBUTE;
  265.     }
  266.     attr.addAttribute(name.toLowerCase(), value);
  267.     }
  268.  
  269.     private void setAlignment(MutableAttributeSet a) {
  270.     String align = (String) a.getAttribute(ALIGN);
  271.     if (align != null) {
  272.         align = align.toLowerCase();
  273.         if (align.equals("left")) {
  274.         StyleConstants.setAlignment(a, StyleConstants.ALIGN_LEFT);
  275.         } else if (align.equals("center")) {
  276.         StyleConstants.setAlignment(a, StyleConstants.ALIGN_CENTER);
  277.         } else if (align.equals("right")) {
  278.         StyleConstants.setAlignment(a, StyleConstants.ALIGN_RIGHT);
  279.         }
  280.     }
  281.     }
  282.  
  283.     public void blockOpenAction(String tag) {
  284.     setAlignment(attr);
  285.     blockOpen(tag, false);
  286.     }
  287.  
  288.     public void blockCloseAction(String tag) {
  289.     blockClose();
  290.     }
  291.  
  292.     public void incrementPCData() {
  293.     if (!dataCountStack.empty()) {
  294.         DataCounter dc = (DataCounter)dataCountStack.pop();
  295.         dc.incCounter();
  296.         dataCountStack.push(dc);
  297.     }
  298.     }
  299.  
  300.     /**
  301.      * Implements the pcdata action to create an ElementSpec
  302.      * record for content with the current character attributes
  303.      * defined.  This is added to the parse buffer
  304.      */
  305.     public void pcdataAction(String data) {
  306.     // Keep track of the pcdata's seen in each nested block
  307.     incrementPCData();
  308.  
  309.     // Translate special characters like ", <, and &034
  310.     String xstr = xlateSpecialChars(data);
  311.     if (xstr != null) {
  312.         data = xstr;
  313.     }
  314.  
  315.     if (inPre) {
  316.         preContent(data);
  317.     } else if (inTitle) {
  318.         titleContent(data);
  319.     } else if (inOption) {
  320.         data = cleanString(data);
  321.         combobox.addItem(data);
  322.     } else if (inBlock > 0) {
  323.         data = cleanString(data);
  324.         if (data.length() >= 1) {
  325.         AttributeSet a = charAttr.copyAttributes();
  326.         ElementSpec es = new ElementSpec(a, ElementSpec.ContentType,
  327.             data.toCharArray(), 0, data.length());
  328.         parseBuffer.addElement(es);
  329.         }
  330.     }
  331.     attr.removeAttributes(attr);
  332.     }
  333.  
  334.     /**
  335.      * cleanEndTag removes any whitespace immediately preceding an
  336.      * end tag.  It also appends an newline character to the text
  337.      * before the end tag so that the insertion caret is positioned
  338.      * properly when editing.
  339.      */
  340.     protected void cleanEndTag(boolean endParagraphSeen) {
  341.     // Fetch the last character data added to the parseBuffer
  342.     ElementSpec lastes = (ElementSpec) parseBuffer.lastElement();
  343.     if (lastes == null)
  344.         return;
  345.     char [] lastchars = lastes.getArray();
  346.     if (lastchars == null)
  347.         return;
  348.     String clean = new String (lastchars);
  349.     if (clean.length() == 0)
  350.         return;
  351.  
  352.     // Eat last whitespace - there's exactly one trailing whitespace
  353.     // because the string was trimmed in cleanString & one space was
  354.     // appended.
  355.     if (isWhiteSpace(clean.charAt(clean.length() - 1))) {
  356.         clean = clean.substring(0, clean.length() - 1);
  357.     }
  358.  
  359.     // For proper cursor positioning during editing,there must be a
  360.     // newline at the end of each paragraph.
  361.     if (endParagraphSeen) {
  362.         clean = clean + "\n";
  363.     }
  364.  
  365.     // Replace the last character data with the modified string
  366.     // in the parseBuffer
  367.     ElementSpec es = new ElementSpec(lastes.getAttributes(),
  368.         ElementSpec.ContentType, clean.toCharArray(),
  369.         0, clean.length());
  370.     parseBuffer.removeElementAt(parseBuffer.size() - 1);
  371.     parseBuffer.addElement(es);
  372.     }
  373.  
  374.     /**
  375.      * isWhiteSpace returns true if a character is whitespace and
  376.      * otherwise returns false.
  377.      */
  378.     protected boolean isWhiteSpace(char c) {
  379.     if ((c == ' ')
  380.      || (c == 10)
  381.      || (c == 13)
  382.      || (c == '\t')) { 
  383.         return true;
  384.     } else {
  385.         return false;
  386.     }
  387.     }
  388.  
  389.     /**
  390.      * cleanString replaces any sequence of blanks, tabs, & newlines 
  391.      *     with a single blank where a newline equals CR LF, CR only,
  392.      *     or LF only.
  393.      * A newline immediately following a start tag is trimmed.
  394.      */
  395.     protected String cleanString(String s) {
  396.     if (s.length() < 1)
  397.         return s;
  398.  
  399.     // Remove all preceding & trailing whitespace & replace with a
  400.     // single space.  If there is no whitespace to begin with, don't
  401.     // add any.
  402.     String endSpace = "";
  403.     String begSpace = "";
  404.     if ((s.length() > 1) 
  405.         && isWhiteSpace(s.charAt(s.length()-1)))
  406.         endSpace = new String (" ");
  407.     if (isWhiteSpace(s.charAt(0)))
  408.         begSpace = new String (" ");
  409.     String clean = begSpace + s.trim() + endSpace; 
  410.  
  411.     // Remove all preceding white space if the pcdata immediately
  412.     // follows an open tag.
  413.     if (openTagSeen && begSpace.equals(" ")) {
  414.         clean = clean.substring(1, clean.length());
  415.     }
  416.     openTagSeen = false;
  417.  
  418.     // Search the entire string for whitespace & replace any sequence
  419.     // of blanks, tabs, & newlines with a single space.
  420.         int index = 0;
  421.         while (index < clean.length()) {
  422.         int endindex = index;
  423.         // Eat whitespace
  424.         if (isWhiteSpace(clean.charAt(endindex))) {
  425.         while ((endindex < clean.length())
  426.             && (isWhiteSpace(clean.charAt(endindex)))) {
  427.             endindex++;
  428.         }
  429.         clean = clean.substring(0, index) + " "
  430.             + clean.substring(endindex, clean.length());
  431.         index = endindex;
  432.         } else {
  433.             index++;
  434.         }
  435.     }
  436.  
  437.     return clean;
  438.     }
  439.  
  440.         
  441.     public void fontOpenAction() {
  442.     openTagSeen = true;
  443.     pushCharacterStyle();
  444.     Color fg = getColor(attr);
  445.     if (fg != null) {
  446.         StyleConstants.setForeground(charAttr, fg);
  447.     }
  448.     String face = (String) attr.getAttribute(FACE);
  449.     if (face != null) {
  450.         StyleConstants.setFontFamily(charAttr, face);
  451.     }
  452.     String size = (String) attr.getAttribute(SIZE);
  453.     StyleSheet ss = StyleReader.getStyleSheet();
  454.     if (size != null) {
  455.         StyleConstants.setFontSize(charAttr, ss.getPtSize(size));
  456.     }
  457.     }
  458.  
  459.     public void fontCloseAction() {
  460.     popCharacterStyle();
  461.     }
  462.  
  463.     public void htmlOpenAction() {
  464.     ;
  465.     }
  466.  
  467.     public void htmlCloseAction() {
  468.     ;
  469.     }
  470.  
  471.     public void headOpenAction() {
  472.     ;
  473.     }
  474.  
  475.     public void headCloseAction() {
  476.     ;
  477.     }
  478.  
  479.     public void bodyOpenAction() {
  480.     setRootElementAttributes(attr);
  481.     }
  482.  
  483.     public void bodyCloseAction() {
  484.     }
  485.  
  486.     public void whitespaceAction(String data) {
  487.     ;
  488.     addContent(data);
  489.     }
  490.  
  491.     public void titleOpenAction() {
  492.     ;
  493.     inTitle = true;
  494.     }
  495.  
  496.     public void titleCloseAction() {
  497.     ;
  498.     inTitle = false;
  499.     }
  500.  
  501.     public void preOpenAction() {
  502.     inPre = true;
  503.     blockOpen(PRE, true);
  504.     blockOpen(PRELINE, true);
  505.     }
  506.  
  507.     public void preCloseAction() {
  508.     inPre = false;
  509.     blockClose();
  510.     blockClose();
  511.     }
  512.  
  513.     /**
  514.      * Set the title as a property on the doc.
  515.      */
  516.     void titleContent(String s) {
  517.     putProperty(Document.TitleProperty, s);
  518.     }
  519.  
  520.     void preContent(String s) {
  521.     int last = 0;
  522.     for (int index = s.indexOf('\n'); index >= 0; index = s.indexOf('\n', last)) {
  523.         String chunk = s.substring(last, index);
  524.         addContent(chunk);
  525.         blockClose();
  526.         blockOpen(PRELINE, true);
  527.         last = index + 1;
  528.     }
  529.     if (last < s.length()) {
  530.         addContent(s.substring(last, s.length()));
  531.     }
  532.     }
  533.  
  534.     public void ttOpenAction() {
  535.     pushCharacterStyle();
  536.     attr.addAttribute(TT, "true");
  537.     AttributeSet look = getChildStyle(TT);
  538.     if (look != null) {
  539.         charAttr.addAttributes(look);
  540.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  541.     }
  542.     else 
  543.         StyleConstants.setFontFamily(charAttr, "Monospaced");
  544.        
  545.     charAttr.addAttributes(attr);
  546.     }
  547.  
  548.     public void ttCloseAction() {
  549.     popCharacterStyle();
  550.     }
  551.  
  552.     public void dfnOpenAction() {
  553.     pushCharacterStyle();
  554.     AttributeSet look = getChildStyle(DFN);
  555.     if (look != null) {
  556.         charAttr.addAttributes(look);
  557.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  558.     }
  559.     else 
  560.         StyleConstants.setItalic(charAttr, true);
  561.        
  562.     charAttr.addAttributes(attr);
  563.     }
  564.  
  565.     public void dfnCloseAction() {
  566.     popCharacterStyle();
  567.     }
  568.  
  569.     public void citeOpenAction() {
  570.     pushCharacterStyle();
  571.     AttributeSet look = getChildStyle(CITE);
  572.     if (look != null) {
  573.         charAttr.addAttributes(look);
  574.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  575.     }
  576.     else 
  577.         StyleConstants.setItalic(charAttr, true);
  578.        
  579.     charAttr.addAttributes(attr);
  580.     }
  581.  
  582.     public void citeCloseAction() {
  583.     popCharacterStyle();
  584.     }
  585.  
  586.     public void bigOpenAction() {
  587.     pushCharacterStyle();
  588.     AttributeSet look = getChildStyle(BIG);
  589.     if (look != null) {
  590.         charAttr.addAttributes(look);
  591.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  592.     }
  593.     else {
  594.         String fontval = StyleXlater.convertFontSizeString("x-large");
  595.         StyleSheet ss = StyleReader.getStyleSheet();
  596.         int size = ss.getPtSize(fontval);
  597.         StyleConstants.setFontSize(charAttr, size);
  598.     }
  599.        
  600.     }
  601.  
  602.     public void bigCloseAction() {
  603.     popCharacterStyle();
  604.     }
  605.  
  606.     public void smallOpenAction() {
  607.     pushCharacterStyle();
  608.     AttributeSet look = getChildStyle(SMALL);
  609.     if (look != null) {
  610.         charAttr.addAttributes(look);
  611.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  612.     }
  613.     else {
  614.         String fontval = StyleXlater.convertFontSizeString("x-small");
  615.         StyleSheet ss = StyleReader.getStyleSheet();
  616.         int size = ss.getPtSize(fontval);
  617.         StyleConstants.setFontSize(charAttr, size);
  618.     }
  619.        
  620.     }
  621.  
  622.     public void smallCloseAction() {
  623.     popCharacterStyle();
  624.     }
  625.  
  626.     public void sampOpenAction() {
  627.     pushCharacterStyle();
  628.     AttributeSet look = getChildStyle(SAMP);
  629.     if (look != null) {
  630.         charAttr.addAttributes(look);
  631.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  632.     }
  633.     else {
  634.         String fontval = StyleXlater.convertFontSizeString("small");
  635.         StyleSheet ss = StyleReader.getStyleSheet();
  636.         int size = ss.getPtSize(fontval);
  637.         StyleConstants.setFontSize(charAttr, size);
  638.         StyleConstants.setFontFamily(charAttr, "Monospaced");
  639.     }
  640.        
  641.     }
  642.  
  643.     public void sampCloseAction() {
  644.     popCharacterStyle();
  645.     }
  646.  
  647.     public void codeOpenAction() {
  648.     pushCharacterStyle();
  649.     AttributeSet look = getChildStyle(CODE);
  650.     if (look != null) {
  651.         charAttr.addAttributes(look);
  652.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  653.     }
  654.     else {
  655.         String fontval = StyleXlater.convertFontSizeString("small");
  656.         StyleSheet ss = StyleReader.getStyleSheet();
  657.         int size = ss.getPtSize(fontval);
  658.         StyleConstants.setFontSize(charAttr, size);
  659.         StyleConstants.setFontFamily(charAttr, "Monospaced");
  660.     }
  661.        
  662.     }
  663.  
  664.     public void codeCloseAction() {
  665.     popCharacterStyle();
  666.     }
  667.  
  668.     public void strikeOpenAction() {
  669.     pushCharacterStyle();
  670.     AttributeSet look = getChildStyle(STRIKE);
  671.     if (look != null) {
  672.         charAttr.addAttributes(look);
  673.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  674.     }
  675.     else {
  676.        ; // Add code here to do strikethrough when implemented in text.
  677.     }
  678.        
  679.     }
  680.  
  681.     public void strikeCloseAction() {
  682.     popCharacterStyle();
  683.     }
  684.  
  685.     public void blockquoteOpenAction() {
  686.     blockOpen(BLOCKQUOTE, false);
  687.     }
  688.  
  689.     public void blockquoteCloseAction() {
  690.     blockClose();
  691.     }
  692.  
  693.     public void emOpenAction() {
  694.     pushCharacterStyle();
  695.     AttributeSet look = getChildStyle(EM);
  696.     if (look != null) {
  697.         charAttr.addAttributes(look);
  698.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  699.     }
  700.     else
  701.       StyleConstants.setItalic(charAttr, true);
  702.       
  703.     charAttr.addAttributes(attr);
  704.     }
  705.  
  706.     public void emCloseAction() {
  707.     popCharacterStyle();
  708.     }
  709.  
  710.     public void addressOpenAction() {
  711.     pushCharacterStyle();
  712.     AttributeSet look = getChildStyle(ADDRESS);
  713.     if (look != null) {
  714.         charAttr.addAttributes(look);
  715.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  716.     }
  717.     else
  718.       StyleConstants.setItalic(charAttr, true);
  719.       
  720.     charAttr.addAttributes(attr);
  721.     }
  722.  
  723.     public void addressCloseAction() {
  724.     popCharacterStyle();
  725.     }
  726.  
  727.     public void strongOpenAction() {
  728.     pushCharacterStyle();
  729.     AttributeSet look = getChildStyle(STRONG);
  730.     if (look != null) {
  731.         charAttr.addAttributes(look);
  732.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  733.     }
  734.     else
  735.         StyleConstants.setBold(charAttr, true);
  736.  
  737.     charAttr.addAttributes(attr);
  738.     }
  739.  
  740.     public void strongCloseAction() {
  741.     popCharacterStyle();
  742.     }
  743.  
  744.     public void varOpenAction() {
  745.     pushCharacterStyle();
  746.     AttributeSet look = getChildStyle(VAR);
  747.     if (look != null) {
  748.         charAttr.addAttributes(look);
  749.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  750.     }
  751.     else {
  752.       StyleConstants.setBold(charAttr, true);
  753.       StyleConstants.setItalic(charAttr, true);
  754.     }
  755.     charAttr.addAttributes(attr);
  756.     }
  757.  
  758.     public void varCloseAction() {
  759.     popCharacterStyle();
  760.     }
  761.  
  762.     public void basefontAction() {
  763.  
  764. /** This is wrong.
  765.   It sets all Paragraphs to be that basefont size
  766.   even if the basefont tag was in the middle of the doc
  767.  
  768.   If we set the size on the charAttr, then it only
  769.   takes effect for those within this character style run.
  770.  
  771.     String size = (String) attr.getAttribute(SIZE);
  772.     if (size != null) {
  773.         StyleSheet ss = StyleReader.getStyleSheet();
  774.         ss.setBaseFontSize(size);
  775.         //Style defStyle = getStyle(StyleContext.DEFAULT_STYLE);
  776.         Style style = getChildStyle(P);
  777.         // This currently only changes text in a P block.
  778.         StyleConstants.setFontSize(style, ss.getPtSize(size));
  779.     }
  780. */
  781.  
  782.     //
  783.     // Save this attribute on the element for writing.
  784.     //
  785.     attr.addAttribute(HTMLTagAttribute, BASEFONT);
  786.     addSpecialElement(attr);
  787.  
  788.     }
  789.  
  790.     public void brAction() {
  791. /*
  792.     blockOpen(BR, false);
  793.     AttributeSet a = charAttr.copyAttributes();
  794.     ElementSpec es = new ElementSpec(a, ElementSpec.ContentType,
  795.         null, 0, 0);
  796.     parseBuffer.addElement(es);
  797.     blockClose();
  798. */
  799.     ;
  800.     }
  801.  
  802.     public void aOpenAction() {
  803.     pushCharacterStyle();
  804.     AttributeSet look = getChildStyle(A);
  805.     if (look != null) {
  806.         charAttr.addAttributes(look);
  807.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  808.     }
  809.     charAttr.addAttributes(attr);
  810.     }
  811.  
  812.     private void checkPCData() {
  813.     // If no pcdata was found, add an empty content anyway
  814.     if (!dataCountStack.empty()) {
  815.         DataCounter dc = (DataCounter)dataCountStack.peek();
  816.         if (dc.noPCData()) {
  817.         AttributeSet a = charAttr.copyAttributes();
  818.         String empty = new String("");
  819.         ElementSpec es = new ElementSpec(a, ElementSpec.ContentType,
  820.             empty.toCharArray(), 0, empty.length());
  821.         parseBuffer.addElement(es);
  822.         }    
  823.     }
  824.     }
  825.  
  826.     public void aCloseAction() {
  827.     checkPCData();
  828.     popCharacterStyle();
  829.     }
  830.  
  831.     public void hrAction() {
  832.     // Get the margins off the body & set them on the hr
  833.     /*
  834.     Style candidate = (Style)getChildStyle(BODY);
  835.     if (candidate != null) {
  836.         float margin_left = StyleConstants.getLeftIndent(candidate);
  837.         float margin_right = StyleConstants.getRightIndent(candidate);
  838.         StyleConstants.setLeftIndent(attr, margin_left);
  839.         StyleConstants.setRightIndent(attr, margin_right);
  840.     }
  841.     */
  842.  
  843.     setAlignment(attr);
  844.     attr.addAttribute(AbstractDocument.ElementNameAttribute, HR);
  845.     addSpecialElement(attr);
  846.     }
  847.  
  848.     public void imgAction() {
  849.     attr.addAttribute(AbstractDocument.ElementNameAttribute, IMG);
  850.     attr.addAttributes(charAttr);    // so ImageView will know char color
  851.     ImageView.addImageDataAttribute(attr);  // add side data for ImageView
  852.     addSpecialElement(attr);
  853.     }
  854.  
  855.     public void iOpenAction() {
  856.     pushCharacterStyle();
  857.     AttributeSet look = getChildStyle(I);
  858.     if (look != null) {
  859.         charAttr.addAttributes(look);
  860.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  861.     }
  862.     else
  863.       StyleConstants.setItalic(charAttr, true);
  864.       
  865.     charAttr.addAttributes(attr);
  866.     }
  867.     public void iCloseAction() {
  868.     popCharacterStyle();
  869.     }
  870.  
  871.     public void bOpenAction() {
  872.     pushCharacterStyle();
  873.     AttributeSet look = getChildStyle(B);
  874.     if (look != null) {
  875.         charAttr.addAttributes(look);
  876.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  877.     }
  878.     else
  879.       StyleConstants.setBold(charAttr, true);
  880.  
  881.     charAttr.addAttributes(attr);
  882.     }
  883.     public void bCloseAction() {
  884.     popCharacterStyle();
  885.     }
  886.  
  887.     public void uOpenAction() {
  888.     pushCharacterStyle();
  889.     AttributeSet look = getChildStyle(U);
  890.     if (look != null) {
  891.         charAttr.addAttributes(look);
  892.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  893.     }
  894.     else
  895.         StyleConstants.setUnderline(charAttr, true);
  896.     }
  897.     public void uCloseAction() {
  898.     popCharacterStyle();
  899.     }
  900.  
  901.     public void kbdOpenAction() {
  902.     pushCharacterStyle();
  903.     AttributeSet look = getChildStyle(KBD);
  904.     if (look != null) {
  905.         charAttr.addAttributes(look);
  906.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  907.     }
  908.     else {
  909.         StyleConstants.setFontFamily(charAttr, "Monospaced");
  910.         String fontval = StyleXlater.convertFontSizeString("small");
  911.         StyleSheet ss = StyleReader.getStyleSheet();
  912.         int size = ss.getPtSize(fontval);
  913.         StyleConstants.setFontSize(charAttr, size);
  914.     }
  915.  
  916.     charAttr.addAttributes(attr);
  917.     }
  918.  
  919.     public void kbdCloseAction() {
  920.     popCharacterStyle();
  921.     }
  922.  
  923.     public void baseAction() {
  924.     String href = (String) attr.getAttribute(HREF);
  925.     if (href != null) {
  926.         putProperty(BaseHrefProperty, href);
  927.         try {
  928.         reference = new URL(href);
  929.         } catch (MalformedURLException ex) {
  930.         }
  931.     }
  932.     }
  933.  
  934.     public void subOpenAction() {
  935.     openTagSeen = true;
  936.     pushCharacterStyle();
  937.     AttributeSet look = getChildStyle(SUB);
  938.     if (look != null) {
  939.         charAttr.addAttributes(look);
  940.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  941.     }
  942.     //else
  943.         // set subscripting
  944.         //StyleConstants.set*
  945.     charAttr.addAttributes(attr);
  946.     }
  947.     public void subCloseAction() {
  948.     cleanEndTag(false);
  949.     popCharacterStyle();
  950.     }
  951.  
  952.     public void supOpenAction() {
  953.     openTagSeen = true;
  954.     attr.addAttribute(SUP, "true");
  955.     pushCharacterStyle();
  956.     AttributeSet look = getChildStyle(SUP);
  957.     if (look != null) {
  958.         charAttr.addAttributes(look);
  959.         charAttr.removeAttribute(StyleConstants.ResolveAttribute);
  960.     }
  961.     //else
  962.         // set superscripting
  963.         //StyleConstants.set*(charAttr, true);
  964.  
  965.     charAttr.addAttributes(attr);
  966.     }
  967.     public void supCloseAction() {
  968.     cleanEndTag(false);
  969.     popCharacterStyle();
  970.     }
  971.  
  972.  
  973.     // --- list actions ---------------------------
  974.  
  975.     public void liOpenAction() {
  976.     blockOpen(LI, true);
  977.     }
  978.     public void liCloseAction() {
  979.     blockClose();
  980.     }
  981.     public void ulOpenAction() {
  982.     blockOpen(UL, true);
  983.     }
  984.     public void ulCloseAction() {
  985.     blockClose();
  986.     }
  987.     public void olOpenAction() {
  988.     blockOpen(OL, true);
  989.     }
  990.     public void olCloseAction() {
  991.     blockClose();
  992.     }
  993.     public void dlOpenAction() {
  994.     blockOpen(DL, true);
  995.     }
  996.     public void dlCloseAction() {
  997.     blockClose();
  998.     }
  999.     public void ddOpenAction() {
  1000.     blockOpen(DD, true);
  1001.     }
  1002.     public void ddCloseAction() {
  1003.     blockClose();
  1004.     }
  1005.     public void dtOpenAction() {
  1006.     blockOpen(DT, true);
  1007.     }
  1008.     public void dtCloseAction() {
  1009.     blockClose();
  1010.     }
  1011.     public void dirOpenAction() {
  1012.     blockOpen(DIR, true);
  1013.     }
  1014.     public void dirCloseAction() {
  1015.     blockClose();
  1016.     }
  1017.     public void menuOpenAction() {
  1018.     blockOpen(MENU, true);
  1019.     }
  1020.     public void menuCloseAction() {
  1021.     blockClose();
  1022.     }
  1023.  
  1024.     // --- form actions ---------------------------
  1025.  
  1026.     public void formOpenAction(){
  1027. //    blockOpen(FORM, true);
  1028.     }
  1029.  
  1030.     public void formCloseAction(){
  1031. //    blockClose();
  1032.     }
  1033.  
  1034.     public void inputAction(){
  1035.     String type = (String) attr.getAttribute(TYPE);
  1036.     if (type == null)
  1037.         type = new String("text");
  1038.  
  1039.     if (type.equalsIgnoreCase("hidden")) {
  1040.         addSpecialElement(attr);
  1041.         return;
  1042.     }
  1043.  
  1044.     Component c;
  1045.     if (type.equalsIgnoreCase("submit")
  1046.         || type.equalsIgnoreCase("reset")) {
  1047.         String value = (String) attr.getAttribute(VALUE);
  1048.         c = (Component) new JButton(value);
  1049.     } else if (type.equalsIgnoreCase("image")) {
  1050.         String src = (String) attr.getAttribute(SRC);
  1051.         c = (Component) new JButton(src);
  1052.     } else if (type.equalsIgnoreCase("checkbox")) {
  1053.         c = (Component) new JCheckBox();
  1054.     } else if (type.equalsIgnoreCase("radio")) {
  1055.         String value = (String) attr.getAttribute(VALUE);
  1056.  
  1057.         c = (Component) new JRadioButton(value);
  1058.     } else if (type.equalsIgnoreCase("text")
  1059.         || type.equalsIgnoreCase("password")) {
  1060.         int size;
  1061.         String sizestr = (String) attr.getAttribute(SIZE);
  1062.         if (sizestr != null) {
  1063.                 try {
  1064.             size = Integer.valueOf(sizestr).intValue();
  1065.                 } catch (NumberFormatException e) {
  1066.             size = 40;
  1067.                 }
  1068.         } else {
  1069.         size = 40;
  1070.         }
  1071.  
  1072.         String value = (String) attr.getAttribute(VALUE);
  1073.  
  1074.         c = (Component) new JTextField(value, size);
  1075.     } else {
  1076.         c = (Component) new JButton();
  1077.     }
  1078.     attr.addAttribute(HTMLInputComponent, HTMLInputComponent);
  1079.     StyleConstants.setComponent(attr, c);
  1080.     addSpecialElement(attr);
  1081.     }
  1082.  
  1083.     public void selectOpenAction(){
  1084.     Component c;
  1085.  
  1086.     int rows;
  1087.     String rowsstr = (String) attr.getAttribute(ROWS);
  1088.     if (rowsstr != null) {
  1089.             try {
  1090.             rows = Integer.valueOf(rowsstr).intValue();
  1091.             } catch (NumberFormatException e) {
  1092.             rows = 10;
  1093.             }
  1094.     } else {
  1095.         rows = 10;
  1096.     }
  1097.  
  1098.     int cols;
  1099.     String colsstr = (String) attr.getAttribute(COLS);
  1100.     if (colsstr != null) {
  1101.             try {
  1102.             cols = Integer.valueOf(colsstr).intValue();
  1103.             } catch (NumberFormatException e) {
  1104.             cols = 40;
  1105.             }
  1106.     } else {
  1107.         cols = 40;
  1108.     }
  1109.  
  1110.     String value = (String) attr.getAttribute(VALUE);
  1111.  
  1112.         combobox = new JComboBox();
  1113.         combobox.setEditable(false);
  1114.  
  1115.     c = (Component) combobox; 
  1116.     attr.addAttribute(HTMLInputComponent, HTMLInputComponent);
  1117.     StyleConstants.setComponent(attr, c);
  1118.     addSpecialElement(attr);
  1119.     }
  1120.  
  1121.     public void selectCloseAction(){
  1122.     }
  1123.  
  1124.     public void optionOpenAction(){
  1125.     inOption = true;
  1126.     }
  1127.  
  1128.     public void optionCloseAction(){
  1129.     inOption = false;
  1130.     }
  1131.  
  1132.     public void textareaOpenAction(){
  1133.     Component c;
  1134.  
  1135.     int rows;
  1136.     String rowsstr = (String) attr.getAttribute(ROWS);
  1137.     if (rowsstr != null) {
  1138.             try {
  1139.             rows = Integer.valueOf(rowsstr).intValue();
  1140.             } catch (NumberFormatException e) {
  1141.             rows = 10;
  1142.             }
  1143.     } else {
  1144.         rows = 10;
  1145.     }
  1146.  
  1147.     int cols;
  1148.     String colsstr = (String) attr.getAttribute(COLS);
  1149.     if (colsstr != null) {
  1150.             try {
  1151.             cols = Integer.valueOf(colsstr).intValue();
  1152.             } catch (NumberFormatException e) {
  1153.             cols = 40;
  1154.             }
  1155.     } else {
  1156.         cols = 40;
  1157.     }
  1158.  
  1159.     String value = (String) attr.getAttribute(VALUE);
  1160.  
  1161.         JTextArea ta = new JTextArea(value, rows, cols);
  1162.         ta.setEditable(true);
  1163.  
  1164.         JScrollPane scroller = new JScrollPane(
  1165.         JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
  1166.         JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
  1167.         scroller.getViewport().add(ta);
  1168.  
  1169.     c = (Component) scroller; 
  1170.     attr.addAttribute(HTMLInputComponent, HTMLInputComponent);
  1171.     StyleConstants.setComponent(attr, c);
  1172.     addSpecialElement(attr);
  1173.     }
  1174.  
  1175.     public void textareaCloseAction(){
  1176.     }
  1177.  
  1178.     // --- table actions -------------------
  1179. /*
  1180.     public void tableOpenAction() {
  1181.     blockOpen(TABLE, true);
  1182.     }
  1183.     public void tableCloseAction() {
  1184.     blockClose();
  1185.     }
  1186.  
  1187.     public void trOpenAction() {
  1188.     blockOpen(TR, true);
  1189.     }
  1190.     public void trCloseAction() {
  1191.     blockClose();
  1192.     }
  1193.  
  1194.     public void thOpenAction() {
  1195.     blockOpen(TH, true);
  1196.     }
  1197.     public void thCloseAction() {
  1198.     blockClose();
  1199.     }
  1200.  
  1201.     public void tdOpenAction() {
  1202.     blockOpen(TD, true);
  1203.     }
  1204.     public void tdCloseAction() {
  1205.     blockClose();
  1206.     }
  1207.  
  1208.     public void captionOpenAction() {
  1209.     blockOpen(CAPTION, true);
  1210.     }
  1211.     public void captionCloseAction() {
  1212.     blockClose();
  1213.     }
  1214. */
  1215.     // --- utility methods used by the reader ------------------
  1216.  
  1217.     /**
  1218.      * Try to turn an html color spec into a Color object.
  1219.      */
  1220.     Color getColor(AttributeSet a) {
  1221.     String name = (String) attr.getAttribute(COLOR);
  1222.     if (name != null) {
  1223.         try {
  1224.             Color c = HTMLUtils.stringToColor(name);
  1225.         return c;
  1226.         }
  1227.         catch (HTMLException e) {
  1228.         return null;
  1229.         }
  1230.     }
  1231.     return null;
  1232.     }
  1233.  
  1234.     /**
  1235.      * Push the current character style on a stack in preparation
  1236.      * for forming a new nested character style.
  1237.      */
  1238.     void pushCharacterStyle() {
  1239.     charAttrStack.push(charAttr.copyAttributes());
  1240.     }
  1241.  
  1242.     /**
  1243.      * Pop a previously pushed character style off the stack
  1244.      * to return to a previous style.
  1245.      */
  1246.     void popCharacterStyle() {
  1247.     charAttr = (MutableAttributeSet) charAttrStack.peek();
  1248.     charAttrStack.pop();
  1249.     }
  1250.  
  1251.     /**
  1252.      * Push the current logical style on the style stack and
  1253.      * set the current logical style to new named style (as
  1254.      * it resolves from the old style.
  1255.      */
  1256.     void pushStyle(String name) {
  1257.     styleStack.push(resolver);
  1258.     
  1259.     // FIXME - should create a local def if it doesn't
  1260.     // exist, so that styles can later be dynamically
  1261.     // updated and the element will be pointing to the
  1262.     // correct style if one is added!!
  1263.     String str = "SH" + name;
  1264.     Style candidate = (Style) resolver.getAttribute(str);
  1265.     if ((candidate == null) && name.equalsIgnoreCase(HTMLDefs.IMPLIEDP)) {
  1266.         str = new String("SHp");
  1267.         candidate = (Style) resolver.getAttribute(str);
  1268.     }
  1269.  
  1270.     if (candidate != null) {
  1271.         resolver = candidate;
  1272.     }
  1273.     }
  1274.  
  1275.     /**
  1276.      * Restores a previously pushed style back as the current
  1277.      * style.
  1278.      */
  1279.     void popStyle() {
  1280.     resolver = (Style) styleStack.peek();
  1281.     styleStack.pop();
  1282.     }
  1283.  
  1284.     /**
  1285.      * Add a specification to create a new branch element,
  1286.      * optionally with the given tag name.
  1287.      */
  1288.     void blockOpen(String tag, boolean setName) {
  1289.     // Increment the parent data count to include this block
  1290.     incrementPCData();
  1291.     // Keep track of the pcdata's seen in each nested block
  1292.     dataCountStack.push(new DataCounter());
  1293.  
  1294.     openTagSeen = true;
  1295.     inBlock++;
  1296.     pushStyle(tag);
  1297.     //Style s = getStyle(tag);
  1298.     if (resolver != null) {
  1299.         // resolve to the tag-named style if it exists
  1300.         Style tmpResolver 
  1301.         = (Style) resolver.getAttribute(StyleReader.CHILD_STYLE);
  1302.         if (tmpResolver != null) {
  1303.             attr.addAttribute(StyleConstants.ResolveAttribute, tmpResolver);
  1304.         }
  1305.     }
  1306.     if (setName) {
  1307.         attr.addAttribute(AbstractDocument.ElementNameAttribute, tag);
  1308.     }
  1309.     if (tag.equalsIgnoreCase(HTMLDefs.IMPLIEDP)) {
  1310.         attr.addAttribute(HTMLDefs.IMPLIEDP, HTMLDefs.IMPLIEDP);
  1311.     }
  1312.     ElementSpec es = new ElementSpec(
  1313.         attr.copyAttributes(), ElementSpec.StartTagType);
  1314.     parseBuffer.addElement(es);
  1315.     attr.removeAttributes(attr);
  1316.     }
  1317.  
  1318.     /**
  1319.      * Close out an element.
  1320.      */
  1321.     void blockClose() {
  1322.     // Keep track of the pcdata's seen in each nested block
  1323.     checkPCData();
  1324.     dataCountStack.pop();
  1325.  
  1326.     cleanEndTag(true);
  1327.     inBlock --;
  1328.     popStyle();
  1329.  
  1330.     // an open/close with no content will be removed, so we
  1331.     // add a space of content to keep the element being formed.
  1332.     ElementSpec prev = (ElementSpec) parseBuffer.lastElement();
  1333.     if (prev != null && prev.getType() == ElementSpec.StartTagType) {
  1334.         addContent(" ");
  1335.     }
  1336.  
  1337.     ElementSpec es = new ElementSpec(
  1338.         null, ElementSpec.EndTagType);
  1339.     parseBuffer.addElement(es);
  1340.     }
  1341.  
  1342.     /**
  1343.      * Add some text with the current character attributes
  1344.      */
  1345.     void addContent(String data) {
  1346.     AttributeSet a = charAttr.copyAttributes();
  1347.     ElementSpec es = new ElementSpec(
  1348.         a, ElementSpec.ContentType, data.toCharArray(), 0, data.length());
  1349.     parseBuffer.addElement(es);
  1350.     }
  1351.  
  1352.     /**
  1353.      * Add content that is basically specified entirely
  1354.      * in the attribute set.
  1355.      */
  1356.     void addSpecialElement(AttributeSet a) {
  1357.     char[] one = new char[1];
  1358.     one[0] = ' ';
  1359.     a = a.copyAttributes();
  1360.     ElementSpec es = new ElementSpec(
  1361.         a.copyAttributes(), ElementSpec.ContentType, one, 0, 1);
  1362.     parseBuffer.addElement(es);
  1363.  
  1364.     attr.removeAttributes(attr);
  1365.     }
  1366.  
  1367.     /**
  1368.      * Replace the substring in str indicated by the start and end
  1369.      * indices with the character.
  1370.      */
  1371.     private String replaceSpecialChar(String str, int startindex,
  1372.     int endindex, char ch) {
  1373.  
  1374.     String newstr = null;
  1375.     newstr = str.substring(0, startindex) + ch
  1376.             + str.substring(endindex+1, str.length());
  1377.     return(newstr);
  1378.     }
  1379.  
  1380.     /**
  1381.      * Translate embedded character entities into their respective
  1382.      * characters.
  1383.      */
  1384.     private String xlateSpecialChars(String str) {
  1385.     String result = null;
  1386.     int index = 0;
  1387.  
  1388.     // Look for the '&' character which designates special html chars.
  1389.     index = str.indexOf('&');
  1390.     while ((index < str.length()) && (index > 0)) {
  1391.         // The special character description ends with ';' so find the
  1392.         // beginning and ending indexes of the special character.
  1393.         int jindex = 0;
  1394.         jindex = str.indexOf(';', index);
  1395.         if (jindex < 0) {
  1396.         return(null);
  1397.         }
  1398.  
  1399.         // If a '#' character follows '&' then the special character is
  1400.         // being represented by an ascii numeric code.  Replace the
  1401.         // code with the special character itself and return the string.
  1402.         if (str.charAt(index+1) == '#') {
  1403.         String sstr = str.substring(index+2, jindex); 
  1404.         int num = Integer.valueOf(sstr).intValue();
  1405.         result = replaceSpecialChar(str, index, jindex, (char)num);
  1406.         }
  1407.         // Otherwise, look up the character name (e.g. ") in the
  1408.         // SpecialCharTable.  Replace the code with the special
  1409.         // character itself and return the string.
  1410.         else {
  1411.         String sstr = str.substring(index+1, jindex); 
  1412.         char lookup = ' ';
  1413.         boolean found = false;
  1414.         try {
  1415.             lookup = specTable.getSymbol(sstr);
  1416.             found = true;
  1417.         } catch (HTMLException e) {
  1418.             ;
  1419.         }
  1420.         if (found) {
  1421.             result = replaceSpecialChar(str, index, jindex, lookup);
  1422.         }
  1423.         }
  1424.         
  1425.         index = str.indexOf('&', index + 1);
  1426.     }
  1427.  
  1428.     return(result);
  1429.     }
  1430.  
  1431.     boolean openTagSeen = false;
  1432.     boolean inPre = false;
  1433.     boolean inTitle = false;
  1434.     boolean inOption = false;
  1435.     Stack dataCountStack = new Stack();
  1436.     JComboBox combobox = null;
  1437.     Vector parseBuffer = new Vector();    // Vector<ElementSpec>
  1438.     MutableAttributeSet charAttr = new SimpleAttributeSet();
  1439.     Stack charAttrStack = new Stack();
  1440.     Style resolver;
  1441.     Stack styleStack = new Stack();
  1442.     MutableAttributeSet attr = new SimpleAttributeSet();
  1443.     int inBlock = 0;
  1444.     html32 parser;
  1445.     SpecialCharTable specTable = new SpecialCharTable();
  1446.  
  1447.     class DataCounter {
  1448.     int dc = 0;
  1449.  
  1450.     public DataCounter() {
  1451.         ;
  1452.     }
  1453.  
  1454.     public void incCounter() {
  1455.         dc++;
  1456.     }
  1457.  
  1458.     public void decCounter() {
  1459.         dc--;
  1460.     }
  1461.  
  1462.     public boolean noPCData() {
  1463.         if (dc > 0)
  1464.         return false;
  1465.         else
  1466.         return true;
  1467.     }
  1468.     }
  1469. }
  1470.  
  1471. }
  1472.