| /* HTMLWriter.java -- |
| Copyright (C) 2006 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package javax.swing.text.html; |
| |
| import java.io.IOException; |
| import java.io.Writer; |
| |
| import java.util.Enumeration; |
| import java.util.HashSet; |
| |
| import javax.swing.ComboBoxModel; |
| |
| import javax.swing.text.AbstractWriter; |
| import javax.swing.text.AttributeSet; |
| import javax.swing.text.BadLocationException; |
| import javax.swing.text.Document; |
| import javax.swing.text.Element; |
| import javax.swing.text.StyleConstants; |
| |
| import javax.swing.text.html.HTML; |
| import javax.swing.text.html.HTMLDocument; |
| import javax.swing.text.html.Option; |
| |
| /** |
| * HTMLWriter, |
| * A Writer for HTMLDocuments. |
| * |
| * @author David Fu (fchoong at netbeans.jp) |
| */ |
| |
| public class HTMLWriter |
| extends AbstractWriter |
| { |
| /** |
| * We keep a reference of the writer passed by the construct. |
| */ |
| private Writer outWriter = null; |
| |
| /** |
| * We keep a reference of the HTMLDocument passed by the construct. |
| */ |
| private HTMLDocument htmlDoc = null; |
| |
| /** |
| * Used to keep track of which embeded has been written out. |
| */ |
| private HashSet openEmbededTagHashSet = null; |
| |
| private String new_line_str = "" + NEWLINE; |
| |
| private char[] html_entity_char_arr = {'<', '>', '&', '"'}; |
| |
| private String[] html_entity_escape_str_arr = {"<", ">", "&", |
| """}; |
| |
| // variables used to output Html Fragment |
| private int doc_pos = -1; |
| private int doc_len = -1; |
| private int doc_offset_remaining = -1; |
| private int doc_len_remaining = -1; |
| private HashSet htmlFragmentParentHashSet = null; |
| private Element startElem = null; |
| private Element endElem = null; |
| private boolean fg_pass_start_elem = false; |
| private boolean fg_pass_end_elem = false; |
| |
| /** |
| * Constructs a HTMLWriter. |
| * |
| * @param writer writer to write output to |
| * @param doc the HTMLDocument to output |
| */ |
| public HTMLWriter(Writer writer, HTMLDocument doc) |
| { |
| super(writer, doc); |
| outWriter = writer; |
| htmlDoc = doc; |
| openEmbededTagHashSet = new HashSet(); |
| } // public HTMLWriter(Writer writer, HTMLDocument doc) |
| |
| /** |
| * Constructs a HTMLWriter which outputs a Html Fragment. |
| * |
| * @param writer <code>Writer</code> to write output to |
| * @param doc the <code>javax.swing.text.html.HTMLDocument</code> |
| * to output |
| * @param pos position to start outputing the document |
| * @param len amount to output the document |
| */ |
| public HTMLWriter(Writer writer, HTMLDocument doc, int pos, int len) |
| { |
| super(writer, doc, pos, len); |
| outWriter = writer; |
| htmlDoc = doc; |
| openEmbededTagHashSet = new HashSet(); |
| |
| doc_pos = pos; |
| doc_offset_remaining = pos; |
| doc_len = len; |
| doc_len_remaining = len; |
| htmlFragmentParentHashSet = new HashSet(); |
| } // public HTMLWriter(Writer writer, HTMLDocument doc, int pos, int len) |
| |
| /** |
| * Call this method to start outputing HTML. |
| * |
| * @throws IOException on any I/O exceptions |
| * @throws BadLocationException if a pos is not a valid position in the |
| * html doc element |
| */ |
| public void write() |
| throws IOException, BadLocationException |
| { |
| Element rootElem = htmlDoc.getDefaultRootElement(); |
| |
| if (doc_pos == -1 && doc_len == -1) |
| { |
| // Normal traversal. |
| traverse(rootElem); |
| } // if(doc_pos == -1 && doc_len == -1) |
| else |
| { |
| // Html fragment traversal. |
| if (doc_pos == -1 || doc_len == -1) |
| throw new BadLocationException("Bad Location(" |
| + doc_pos + ", " + doc_len + ")", doc_pos); |
| |
| startElem = htmlDoc.getCharacterElement(doc_pos); |
| |
| int start_offset = startElem.getStartOffset(); |
| |
| // Positions before start_offset will not be traversed, and thus |
| // will not be counted. |
| if (start_offset > 0) |
| doc_offset_remaining = doc_offset_remaining - start_offset; |
| |
| Element tempParentElem = startElem; |
| |
| while ((tempParentElem = tempParentElem.getParentElement()) != null) |
| { |
| if (!htmlFragmentParentHashSet.contains(tempParentElem)) |
| htmlFragmentParentHashSet.add(tempParentElem); |
| } // while((tempParentElem = tempParentElem.getParentElement()) |
| // != null) |
| |
| // NOTE: 20061030 - fchoong - the last index should not be included. |
| endElem = htmlDoc.getCharacterElement(doc_pos + doc_len - 1); |
| |
| tempParentElem = endElem; |
| |
| while ((tempParentElem = tempParentElem.getParentElement()) != null) |
| { |
| if (!htmlFragmentParentHashSet.contains(tempParentElem)) |
| htmlFragmentParentHashSet.add(tempParentElem); |
| } // while((tempParentElem = tempParentElem.getParentElement()) |
| // != null) |
| |
| traverseHtmlFragment(rootElem); |
| |
| } // else |
| |
| // NOTE: close out remaining open embeded tags. |
| Object[] tag_arr = openEmbededTagHashSet.toArray(); |
| |
| for (int i = 0; i < tag_arr.length; i++) |
| { |
| writeRaw("</" + tag_arr[i].toString() + ">"); |
| } // for(int i = 0; i < tag_arr.length; i++) |
| |
| } // public void write() throws IOException, BadLocationException |
| |
| /** |
| * Writes all the attributes in the attrSet, except for attrbutes with |
| * keys of <code>javax.swing.text.html.HTML.Tag</code>, |
| * <code>javax.swing.text.StyleConstants</code> or |
| * <code>javax.swing.text.html.HTML.Attribute.ENDTAG</code>. |
| * |
| * @param attrSet attrSet to write out |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| protected void writeAttributes(AttributeSet attrSet) |
| throws IOException |
| { |
| Enumeration attrNameEnum = attrSet.getAttributeNames(); |
| |
| while (attrNameEnum.hasMoreElements()) |
| { |
| Object key = attrNameEnum.nextElement(); |
| Object value = attrSet.getAttribute(key); |
| |
| // HTML.Attribute.ENDTAG is an instance, not a class. |
| if (!((key instanceof HTML.Tag) || (key instanceof StyleConstants) |
| || (key == HTML.Attribute.ENDTAG))) |
| { |
| if (key == HTML.Attribute.SELECTED) |
| writeRaw(" selected"); |
| else if (key == HTML.Attribute.CHECKED) |
| writeRaw(" checked"); |
| else |
| writeRaw(" " + key + "=\"" + value + "\""); |
| } // if(!((key instanceof HTML.Tag) || (key instanceof |
| // StyleConstants) || (key == HTML.Attribute.ENDTAG))) |
| } // while(attrNameEnum.hasMoreElements()) |
| |
| } // protected void writeAttributes(AttributeSet attrSet) throws IOException |
| |
| /** |
| * Writes out an empty tag. i.e. a tag without any child elements. |
| * |
| * @param paramElem the element to output as an empty tag |
| * |
| * @throws IOException on any I/O exceptions |
| * @throws BadLocationException if a pos is not a valid position in the |
| * html doc element |
| */ |
| protected void emptyTag(Element paramElem) |
| throws IOException, BadLocationException |
| { |
| String elem_name = paramElem.getName(); |
| AttributeSet attrSet = paramElem.getAttributes(); |
| |
| writeRaw("<" + elem_name); |
| writeAttributes(attrSet); |
| writeRaw(">"); |
| |
| if (isBlockTag(attrSet)) |
| { |
| writeRaw("</" + elem_name + ">"); |
| } // if(isBlockTag(attrSet)) |
| |
| } // protected void emptyTag(Element paramElem) |
| // throws IOException, BadLocationException |
| |
| /** |
| * Determines if it is a block tag or not. |
| * |
| * @param attrSet the attrSet of the element |
| * |
| * @return <code>true</code> if it is a block tag |
| * <code>false</code> if it is a not block tag |
| */ |
| protected boolean isBlockTag(AttributeSet attrSet) |
| { |
| return ((HTML.Tag) |
| attrSet.getAttribute(StyleConstants.NameAttribute)).isBlock(); |
| } // protected boolean isBlockTag(AttributeSet attrSet) |
| |
| /** |
| * Writes out a start tag. Synthesized elements are skipped. |
| * |
| * @param paramElem the element to output as a start tag |
| * @throws IOException on any I/O exceptions |
| * @throws BadLocationException if a pos is not a valid position in the |
| * html doc element |
| */ |
| protected void startTag(Element paramElem) |
| throws IOException, BadLocationException |
| { |
| // NOTE: Sysnthesized elements do no call this method at all. |
| String elem_name = paramElem.getName(); |
| AttributeSet attrSet = paramElem.getAttributes(); |
| |
| indent(); |
| writeRaw("<" + elem_name); |
| writeAttributes(attrSet); |
| writeRaw(">"); |
| writeLineSeparator(); // Extra formatting to look more like the RI. |
| incrIndent(); |
| |
| } // protected void startTag(Element paramElem) |
| // throws IOException, BadLocationException |
| |
| /** |
| * Writes out the contents of a textarea. |
| * |
| * @param attrSet the attrSet of the element to output as a text area |
| * @throws IOException on any I/O exceptions |
| * @throws BadLocationException if a pos is not a valid position in the |
| * html doc element |
| */ |
| protected void textAreaContent(AttributeSet attrSet) |
| throws IOException, BadLocationException |
| { |
| writeLineSeparator(); // Extra formatting to look more like the RI. |
| indent(); |
| writeRaw("<textarea"); |
| writeAttributes(attrSet); |
| writeRaw(">"); |
| |
| Document tempDocument = |
| (Document) attrSet.getAttribute(StyleConstants.ModelAttribute); |
| |
| writeRaw(tempDocument.getText(0, tempDocument.getLength())); |
| indent(); |
| writeRaw("</textarea>"); |
| |
| } // protected void textAreaContent(AttributeSet attrSet) |
| // throws IOException, BadLocationException |
| |
| /** |
| * Writes out text, within the appropriate range if it is specified. |
| * |
| * @param paramElem the element to output as a text |
| * @throws IOException on any I/O exceptions |
| * @throws BadLocationException if a pos is not a valid position in the |
| * html doc element |
| */ |
| protected void text(Element paramElem) |
| throws IOException, BadLocationException |
| { |
| int offset = paramElem.getStartOffset(); |
| int len = paramElem.getEndOffset() - paramElem.getStartOffset(); |
| String txt_value = htmlDoc.getText(offset, len); |
| |
| writeContent(txt_value); |
| |
| } // protected void text(Element paramElem) |
| // throws IOException, BadLocationException |
| |
| /** |
| * Writes out the contents of a select element. |
| * |
| * @param attrSet the attrSet of the element to output as a select box |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| protected void selectContent(AttributeSet attrSet) |
| throws IOException |
| { |
| writeLineSeparator(); // Extra formatting to look more like the RI. |
| indent(); |
| writeRaw("<select"); |
| writeAttributes(attrSet); |
| writeRaw(">"); |
| incrIndent(); |
| writeLineSeparator(); // extra formatting to look more like the RI. |
| |
| ComboBoxModel comboBoxModel = |
| (ComboBoxModel) attrSet.getAttribute(StyleConstants.ModelAttribute); |
| |
| for (int i = 0; i < comboBoxModel.getSize(); i++) |
| { |
| writeOption((Option) comboBoxModel.getElementAt(i)); |
| } // for(int i = 0; i < comboBoxModel.getSize(); i++) |
| |
| decrIndent(); |
| indent(); |
| writeRaw("</select>"); |
| |
| } // protected void selectContent(AttributeSet attrSet) throws IOException |
| |
| /** |
| * Writes out the contents of an option element. |
| * |
| * @param option the option object to output as a select option |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| protected void writeOption(Option option) |
| throws IOException |
| { |
| indent(); |
| writeRaw("<option"); |
| writeAttributes(option.getAttributes()); |
| writeRaw(">"); |
| |
| writeContent(option.getLabel()); |
| |
| writeRaw("</option>"); |
| writeLineSeparator(); // extra formatting to look more like the RI. |
| |
| } // protected void writeOption(Option option) throws IOException |
| |
| /** |
| * Writes out an end tag. |
| * |
| * @param paramElem the element to output as an end tag |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| protected void endTag(Element paramElem) |
| throws IOException |
| { |
| String elem_name = paramElem.getName(); |
| |
| //writeLineSeparator(); // Extra formatting to look more like the RI. |
| decrIndent(); |
| indent(); |
| writeRaw("</" + elem_name + ">"); |
| writeLineSeparator(); // Extra formatting to look more like the RI. |
| |
| } // protected void endTag(Element paramElem) throws IOException |
| |
| /** |
| * Writes out the comment. |
| * |
| * @param paramElem the element to output as a comment |
| */ |
| protected void comment(Element paramElem) |
| throws IOException, BadLocationException |
| { |
| AttributeSet attrSet = paramElem.getAttributes(); |
| |
| String comment_str = (String) attrSet.getAttribute(HTML.Attribute.COMMENT); |
| |
| writeRaw("<!--" + comment_str + "-->"); |
| |
| } // protected void comment(Element paramElem) |
| // throws IOException, BadLocationException |
| |
| /** |
| * Determines if element is a synthesized |
| * <code>javax.swing.text.Element</code> or not. |
| * |
| * @param element the element to test |
| * |
| * @return <code>true</code> if it is a synthesized element, |
| * <code>false</code> if it is a not synthesized element |
| */ |
| protected boolean synthesizedElement(Element element) |
| { |
| AttributeSet attrSet = element.getAttributes(); |
| Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute); |
| |
| if (tagType == HTML.Tag.CONTENT || tagType == HTML.Tag.COMMENT |
| || tagType == HTML.Tag.IMPLIED) |
| return true; |
| else |
| return false; |
| } // protected boolean synthesizedElement(Element element) |
| |
| /** |
| * Determines if |
| * <code>javax.swing.text.StyleConstants.NameAttribute</code> |
| * matches tag or not. |
| * |
| * @param attrSet the <code>javax.swing.text.AttributeSet</code> of |
| * element to be matched |
| * @param tag the HTML.Tag to match |
| * |
| * @return <code>true</code> if it matches, |
| * <code>false</code> if it does not match |
| */ |
| protected boolean matchNameAttribute(AttributeSet attrSet, HTML.Tag tag) |
| { |
| Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute); |
| |
| if (tagType == tag) |
| return true; |
| else |
| return false; |
| } // protected boolean matchNameAttribute(AttributeSet attrSet, |
| // HTML.Tag tag) |
| |
| /** |
| * Writes out an embedded tag. The tags not already in |
| * openEmbededTagHashSet will written out. |
| * |
| * @param attrSet the <code>javax.swing.text.AttributeSet</code> of |
| * the element to write out |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| protected void writeEmbeddedTags(AttributeSet attrSet) |
| throws IOException |
| { |
| Enumeration attrNameEnum = attrSet.getAttributeNames(); |
| |
| while (attrNameEnum.hasMoreElements()) |
| { |
| Object key = attrNameEnum.nextElement(); |
| Object value = attrSet.getAttribute(key); |
| |
| if (key instanceof HTML.Tag) |
| { |
| if (!openEmbededTagHashSet.contains(key)) |
| { |
| writeRaw("<" + key); |
| writeAttributes((AttributeSet) value); |
| writeRaw(">"); |
| openEmbededTagHashSet.add(key); |
| } // if(!openEmbededTagHashSet.contains(key)) |
| } // if(key instanceof HTML.Tag) |
| } // while(attrNameEnum.hasMoreElements()) |
| |
| } // protected void writeEmbeddedTags(AttributeSet attrSet) |
| // throws IOException |
| |
| /** |
| * Closes out an unwanted embedded tag. The tags from the |
| * openEmbededTagHashSet not found in attrSet will be written out. |
| * |
| * @param attrSet the AttributeSet of the element to write out |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet) |
| throws IOException |
| { |
| Object[] tag_arr = openEmbededTagHashSet.toArray(); |
| |
| for (int i = 0; i < tag_arr.length; i++) |
| { |
| HTML.Tag key = (HTML.Tag) tag_arr[i]; |
| |
| if (!attrSet.isDefined(key)) |
| { |
| writeRaw("</" + key.toString() + ">"); |
| openEmbededTagHashSet.remove(key); |
| } // if(!attrSet.isDefined(key)) |
| } // for(int i = 0; i < tag_arr.length; i++) |
| |
| } // protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet) |
| // throws IOException |
| |
| /** |
| * Writes out a line separator. Overwrites the parent to write out a new |
| * line. |
| * |
| * @throws IOException on any I/O exceptions. |
| */ |
| protected void writeLineSeparator() |
| throws IOException |
| { |
| writeRaw(new_line_str); |
| } // protected void writeLineSeparator() throws IOException |
| |
| /** |
| * Write to the writer. Character entites such as <, > |
| * are escaped appropriately. |
| * |
| * @param chars char array to write out |
| * @param off offset |
| * @param len length |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| protected void output(char[] chars, int off, int len) |
| throws IOException |
| { |
| StringBuffer strBuffer = new StringBuffer(); |
| |
| for (int i = 0; i < chars.length; i++) |
| { |
| if (isCharHtmlEntity(chars[i])) |
| strBuffer.append(escapeCharHtmlEntity(chars[i])); |
| else |
| strBuffer.append(chars[i]); |
| } // for(int i = 0; i < chars.length; i++) |
| |
| writeRaw(strBuffer.toString()); |
| |
| } // protected void output(char[] chars, int off, int len) |
| // throws IOException |
| |
| //------------------------------------------------------------------------- |
| // private methods |
| |
| /** |
| * The main method used to traverse through the elements. |
| * |
| * @param paramElem element to traverse |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| private void traverse(Element paramElem) |
| throws IOException, BadLocationException |
| { |
| Element currElem = paramElem; |
| |
| AttributeSet attrSet = currElem.getAttributes(); |
| |
| closeOutUnwantedEmbeddedTags(attrSet); |
| |
| // handle the tag |
| if (synthesizedElement(paramElem)) |
| { |
| if (matchNameAttribute(attrSet, HTML.Tag.CONTENT)) |
| { |
| writeEmbeddedTags(attrSet); |
| text(currElem); |
| } // if(matchNameAttribute(attrSet, HTML.Tag.CONTENT)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT)) |
| { |
| comment(currElem); |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) |
| { |
| int child_elem_count = currElem.getElementCount(); |
| |
| if (child_elem_count > 0) |
| { |
| for (int i = 0; i < child_elem_count; i++) |
| { |
| Element childElem = paramElem.getElement(i); |
| |
| traverse(childElem); |
| |
| } // for(int i = 0; i < child_elem_count; i++) |
| } // if(child_elem_count > 0) |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) |
| } // if(synthesizedElement(paramElem)) |
| else |
| { |
| // NOTE: 20061030 - fchoong - title is treated specially here. |
| // based on RI behavior. |
| if (matchNameAttribute(attrSet, HTML.Tag.TITLE)) |
| { |
| boolean fg_is_end_tag = false; |
| Enumeration attrNameEnum = attrSet.getAttributeNames(); |
| |
| while (attrNameEnum.hasMoreElements()) |
| { |
| Object key = attrNameEnum.nextElement(); |
| Object value = attrSet.getAttribute(key); |
| |
| if (key == HTML.Attribute.ENDTAG && value.equals("true")) |
| fg_is_end_tag = true; |
| } // while(attrNameEnum.hasMoreElements()) |
| |
| if (fg_is_end_tag) |
| writeRaw("</title>"); |
| else |
| { |
| indent(); |
| writeRaw("<title>"); |
| |
| String title_str = |
| (String) htmlDoc.getProperty(HTMLDocument.TitleProperty); |
| |
| if (title_str != null) |
| writeContent(title_str); |
| |
| } // else |
| } // if(matchNameAttribute(attrSet, HTML.Tag.TITLE)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.PRE)) |
| { |
| // We pursue more stringent formating here. |
| attrSet = paramElem.getAttributes(); |
| |
| indent(); |
| writeRaw("<pre"); |
| writeAttributes(attrSet); |
| writeRaw(">"); |
| |
| int child_elem_count = currElem.getElementCount(); |
| |
| for (int i = 0; i < child_elem_count; i++) |
| { |
| Element childElem = paramElem.getElement(i); |
| |
| traverse(childElem); |
| |
| } // for(int i = 0; i < child_elem_count; i++) |
| |
| writeRaw("</pre>"); |
| |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.PRE)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.SELECT)) |
| { |
| selectContent(attrSet); |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.SELECT)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA)) |
| { |
| textAreaContent(attrSet); |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.TEXTAREA)) |
| else |
| { |
| int child_elem_count = currElem.getElementCount(); |
| |
| if (child_elem_count > 0) |
| { |
| startTag(currElem); |
| |
| for (int i = 0; i < child_elem_count; i++) |
| { |
| Element childElem = paramElem.getElement(i); |
| |
| traverse(childElem); |
| |
| } // for(int i = 0; i < child_elem_count; i++) |
| |
| endTag(currElem); |
| |
| } // if(child_elem_count > 0) |
| else |
| { |
| emptyTag(currElem); |
| } // else |
| } // else |
| } // else |
| |
| } // private void traverse(Element paramElem) |
| // throws IOException, BadLocationException |
| |
| /** |
| * The method used to traverse through a html fragment. |
| * |
| * @param paramElem element to traverse |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| private void traverseHtmlFragment(Element paramElem) |
| throws IOException, BadLocationException |
| { |
| // NOTE: This method is similar to traverse(Element paramElem) |
| Element currElem = paramElem; |
| |
| boolean fg_is_fragment_parent_elem = false; |
| boolean fg_is_start_and_end_elem = false; |
| |
| if (htmlFragmentParentHashSet.contains(paramElem)) |
| fg_is_fragment_parent_elem = true; |
| |
| if (paramElem == startElem) |
| fg_pass_start_elem = true; |
| |
| if (paramElem == startElem && paramElem == endElem) |
| fg_is_start_and_end_elem = true; |
| |
| AttributeSet attrSet = currElem.getAttributes(); |
| |
| closeOutUnwantedEmbeddedTags(attrSet); |
| |
| if (fg_is_fragment_parent_elem || (fg_pass_start_elem |
| && fg_pass_end_elem == false) || fg_is_start_and_end_elem) |
| { |
| // handle the tag |
| if (synthesizedElement(paramElem)) |
| { |
| if (matchNameAttribute(attrSet, HTML.Tag.CONTENT)) |
| { |
| writeEmbeddedTags(attrSet); |
| |
| int content_offset = paramElem.getStartOffset(); |
| int content_length = currElem.getEndOffset() - content_offset; |
| |
| if (doc_offset_remaining > 0) |
| { |
| if (content_length > doc_offset_remaining) |
| { |
| int split_len = content_length; |
| |
| split_len = split_len - doc_offset_remaining; |
| |
| if (split_len > doc_len_remaining) |
| split_len = doc_len_remaining; |
| |
| // we need to split it. |
| String txt_value = htmlDoc.getText(content_offset |
| + doc_offset_remaining, split_len); |
| |
| writeContent(txt_value); |
| |
| doc_offset_remaining = 0; // the offset is used up. |
| doc_len_remaining = doc_len_remaining - split_len; |
| } // if(content_length > doc_offset_remaining) |
| else |
| { |
| // doc_offset_remaining is greater than the entire |
| // length of content |
| doc_offset_remaining = doc_offset_remaining |
| - content_length; |
| } // else |
| } // if(doc_offset_remaining > 0) |
| else if (content_length <= doc_len_remaining) |
| { |
| // we can fit the entire content. |
| text(currElem); |
| doc_len_remaining = doc_len_remaining - content_length; |
| } // else if(content_length <= doc_len_remaining) |
| else |
| { |
| // we need to split it. |
| String txt_value = htmlDoc.getText(content_offset, |
| doc_len_remaining); |
| |
| writeContent(txt_value); |
| |
| doc_len_remaining = 0; |
| } // else |
| |
| } // if(matchNameAttribute(attrSet, HTML.Tag.CONTENT)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT)) |
| { |
| comment(currElem); |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) |
| { |
| int child_elem_count = currElem.getElementCount(); |
| |
| if (child_elem_count > 0) |
| { |
| for (int i = 0; i < child_elem_count; i++) |
| { |
| Element childElem = paramElem.getElement(i); |
| |
| traverseHtmlFragment(childElem); |
| |
| } // for(int i = 0; i < child_elem_count; i++) |
| } // if(child_elem_count > 0) |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) |
| } // if(synthesizedElement(paramElem)) |
| else |
| { |
| // NOTE: 20061030 - fchoong - the isLeaf() condition seems to |
| // generate the closest behavior to the RI. |
| if (paramElem.isLeaf()) |
| { |
| if (doc_offset_remaining > 0) |
| { |
| doc_offset_remaining--; |
| } // if(doc_offset_remaining > 0) |
| else if (doc_len_remaining > 0) |
| { |
| doc_len_remaining--; |
| } // else if(doc_len_remaining > 0) |
| } // if(paramElem.isLeaf()) |
| |
| // NOTE: 20061030 - fchoong - title is treated specially here. |
| // based on RI behavior. |
| if (matchNameAttribute(attrSet, HTML.Tag.TITLE)) |
| { |
| boolean fg_is_end_tag = false; |
| Enumeration attrNameEnum = attrSet.getAttributeNames(); |
| |
| while (attrNameEnum.hasMoreElements()) |
| { |
| Object key = attrNameEnum.nextElement(); |
| Object value = attrSet.getAttribute(key); |
| |
| if (key == HTML.Attribute.ENDTAG && value.equals("true")) |
| fg_is_end_tag = true; |
| } // while(attrNameEnum.hasMoreElements()) |
| |
| if (fg_is_end_tag) |
| writeRaw("</title>"); |
| else |
| { |
| indent(); |
| writeRaw("<title>"); |
| |
| String title_str = |
| (String) htmlDoc.getProperty(HTMLDocument.TitleProperty); |
| |
| if (title_str != null) |
| writeContent(title_str); |
| |
| } // else |
| } // if(matchNameAttribute(attrSet, HTML.Tag.TITLE)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.PRE)) |
| { |
| // We pursue more stringent formating here. |
| attrSet = paramElem.getAttributes(); |
| |
| indent(); |
| writeRaw("<pre"); |
| writeAttributes(attrSet); |
| writeRaw(">"); |
| |
| int child_elem_count = currElem.getElementCount(); |
| |
| for (int i = 0; i < child_elem_count; i++) |
| { |
| Element childElem = paramElem.getElement(i); |
| |
| traverseHtmlFragment(childElem); |
| |
| } // for(int i = 0; i < child_elem_count; i++) |
| |
| writeRaw("</pre>"); |
| |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.PRE)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.SELECT)) |
| { |
| selectContent(attrSet); |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.SELECT)) |
| else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA)) |
| { |
| textAreaContent(attrSet); |
| } // else if(matchNameAttribute(attrSet, HTML.Tag.TEXTAREA)) |
| else |
| { |
| int child_elem_count = currElem.getElementCount(); |
| |
| if (child_elem_count > 0) |
| { |
| startTag(currElem); |
| |
| for (int i = 0; i < child_elem_count; i++) |
| { |
| Element childElem = paramElem.getElement(i); |
| |
| traverseHtmlFragment(childElem); |
| |
| } // for(int i = 0; i < child_elem_count; i++) |
| |
| endTag(currElem); |
| |
| } // if(child_elem_count > 0) |
| else |
| { |
| emptyTag(currElem); |
| } // else |
| } // else |
| } // else |
| |
| } // if(fg_is_fragment_parent_elem || (fg_pass_start_elem |
| // && fg_pass_end_elem == false) || fg_is_start_and_end_elem) |
| |
| if (paramElem == endElem) |
| fg_pass_end_elem = true; |
| |
| } // private void traverseHtmlFragment(Element paramElem) |
| // throws IOException, BadLocationException |
| |
| /** |
| * Write to the writer without any modifications. |
| * |
| * @param param_str the str to write out |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| private void writeRaw(String param_str) |
| throws IOException |
| { |
| super.output(param_str.toCharArray(), 0, param_str.length()); |
| } // private void writeRaw(char[] chars, int off, int len) |
| // throws IOException |
| |
| /** |
| * Write to the writer, escaping HTML character entitie where neccessary. |
| * |
| * @param param_str the str to write out |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| private void writeContent(String param_str) |
| throws IOException |
| { |
| char[] str_char_arr = param_str.toCharArray(); |
| |
| if (hasHtmlEntity(param_str)) |
| output(str_char_arr, 0, str_char_arr.length); |
| else |
| super.output(str_char_arr, 0, str_char_arr.length); |
| |
| } // private void writeContent(String param_str) throws IOException |
| |
| /** |
| * Use this for debugging. Writes out all attributes regardless of type. |
| * |
| * @param attrSet the <code>javax.swing.text.AttributeSet</code> to |
| * write out |
| * |
| * @throws IOException on any I/O exceptions |
| */ |
| private void writeAllAttributes(AttributeSet attrSet) |
| throws IOException |
| { |
| Enumeration attrNameEnum = attrSet.getAttributeNames(); |
| |
| while (attrNameEnum.hasMoreElements()) |
| { |
| Object key = attrNameEnum.nextElement(); |
| Object value = attrSet.getAttribute(key); |
| |
| writeRaw(" " + key + "=\"" + value + "\""); |
| writeRaw(" " + key.getClass().toString() + "=\"" |
| + value.getClass().toString() + "\""); |
| } // while(attrNameEnum.hasMoreElements()) |
| |
| } // private void writeAllAttributes(AttributeSet attrSet) |
| // throws IOException |
| |
| /** |
| * Tests if the str contains any html entities. |
| * |
| * @param param_str the str to test |
| * |
| * @return <code>true</code> if it has a html entity |
| * <code>false</code> if it does not have a html entity |
| */ |
| private boolean hasHtmlEntity(String param_str) |
| { |
| boolean ret_bool = false; |
| |
| for (int i = 0; i < html_entity_char_arr.length; i++) |
| { |
| if (param_str.indexOf(html_entity_char_arr[i]) != -1) |
| { |
| ret_bool = true; |
| break; |
| } // if(param_str.indexOf(html_entity_char_arr[i]) != -1) |
| } // for(int i = 0; i < html_entity_char_arr.length; i++) |
| |
| return ret_bool; |
| } // private boolean hasHtmlEntity(String param_str) |
| |
| /** |
| * Tests if the char is a html entities. |
| * |
| * @param param_char the char to test |
| * |
| * @return <code>true</code> if it is a html entity |
| * <code>false</code> if it is not a html entity. |
| */ |
| private boolean isCharHtmlEntity(char param_char) |
| { |
| boolean ret_bool = false; |
| |
| for (int i = 0; i < html_entity_char_arr.length; i++) |
| { |
| if (param_char == html_entity_char_arr[i]) |
| { |
| ret_bool = true; |
| break; |
| } // if(param_char == html_entity_char_arr[i]) |
| } // for(int i = 0; i < html_entity_char_arr.length; i++) |
| |
| return ret_bool; |
| } // private boolean hasHtmlEntity(String param_str) |
| |
| /** |
| * Escape html entities. |
| * |
| * @param param_char the char to escape |
| * |
| * @return escaped html entity. Original char is returned as a str if is |
| * is not a html entity |
| */ |
| private String escapeCharHtmlEntity(char param_char) |
| { |
| String ret_str = "" + param_char; |
| |
| for (int i = 0; i < html_entity_char_arr.length; i++) |
| { |
| if (param_char == html_entity_char_arr[i]) |
| { |
| ret_str = html_entity_escape_str_arr[i]; |
| break; |
| } // if(param_char == html_entity_char_arr[i]) |
| } // for(int i = 0; i < html_entity_char_arr.length; i++) |
| |
| return ret_str; |
| } // private String escapeCharHtmlEntity(char param_char) |
| |
| } // public class HTMLWriter extends AbstractWriter |