001 /* HTMLWriter.java -- 002 Copyright (C) 2006 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 package javax.swing.text.html; 039 040 import gnu.java.lang.CPStringBuilder; 041 042 import java.io.IOException; 043 import java.io.Writer; 044 045 import java.util.Enumeration; 046 import java.util.HashSet; 047 048 import javax.swing.ComboBoxModel; 049 050 import javax.swing.text.AbstractWriter; 051 import javax.swing.text.AttributeSet; 052 import javax.swing.text.BadLocationException; 053 import javax.swing.text.Document; 054 import javax.swing.text.Element; 055 import javax.swing.text.StyleConstants; 056 057 import javax.swing.text.html.HTML; 058 import javax.swing.text.html.HTMLDocument; 059 import javax.swing.text.html.Option; 060 061 /** 062 * HTMLWriter, 063 * A Writer for HTMLDocuments. 064 * 065 * @author David Fu (fchoong at netbeans.jp) 066 */ 067 068 public class HTMLWriter 069 extends AbstractWriter 070 { 071 /** 072 * We keep a reference of the writer passed by the construct. 073 */ 074 private Writer outWriter = null; 075 076 /** 077 * We keep a reference of the HTMLDocument passed by the construct. 078 */ 079 private HTMLDocument htmlDoc = null; 080 081 /** 082 * Used to keep track of which embedded has been written out. 083 */ 084 private HashSet<HTML.Tag> openEmbeddedTagHashSet = null; 085 086 private String new_line_str = "" + NEWLINE; 087 088 private char[] html_entity_char_arr = {'<', '>', '&', '"'}; 089 090 private String[] html_entity_escape_str_arr = {"<", ">", "&", 091 """}; 092 093 // variables used to output Html Fragment 094 private int doc_pos = -1; 095 private int doc_len = -1; 096 private int doc_offset_remaining = -1; 097 private int doc_len_remaining = -1; 098 private HashSet<Element> htmlFragmentParentHashSet = null; 099 private Element startElem = null; 100 private Element endElem = null; 101 private boolean fg_pass_start_elem = false; 102 private boolean fg_pass_end_elem = false; 103 104 /** 105 * Constructs a HTMLWriter. 106 * 107 * @param writer writer to write output to 108 * @param doc the HTMLDocument to output 109 */ 110 public HTMLWriter(Writer writer, HTMLDocument doc) 111 { 112 super(writer, doc); 113 outWriter = writer; 114 htmlDoc = doc; 115 openEmbeddedTagHashSet = new HashSet<HTML.Tag>(); 116 } // public HTMLWriter(Writer writer, HTMLDocument doc) 117 118 /** 119 * Constructs a HTMLWriter which outputs a Html Fragment. 120 * 121 * @param writer <code>Writer</code> to write output to 122 * @param doc the <code>javax.swing.text.html.HTMLDocument</code> 123 * to output 124 * @param pos position to start outputing the document 125 * @param len amount to output the document 126 */ 127 public HTMLWriter(Writer writer, HTMLDocument doc, int pos, int len) 128 { 129 super(writer, doc, pos, len); 130 outWriter = writer; 131 htmlDoc = doc; 132 openEmbeddedTagHashSet = new HashSet<HTML.Tag>(); 133 134 doc_pos = pos; 135 doc_offset_remaining = pos; 136 doc_len = len; 137 doc_len_remaining = len; 138 htmlFragmentParentHashSet = new HashSet<Element>(); 139 } // public HTMLWriter(Writer writer, HTMLDocument doc, int pos, int len) 140 141 /** 142 * Call this method to start outputing HTML. 143 * 144 * @throws IOException on any I/O exceptions 145 * @throws BadLocationException if a pos is not a valid position in the 146 * html doc element 147 */ 148 public void write() 149 throws IOException, BadLocationException 150 { 151 Element rootElem = htmlDoc.getDefaultRootElement(); 152 153 if (doc_pos == -1 && doc_len == -1) 154 { 155 // Normal traversal. 156 traverse(rootElem); 157 } // if(doc_pos == -1 && doc_len == -1) 158 else 159 { 160 // Html fragment traversal. 161 if (doc_pos == -1 || doc_len == -1) 162 throw new BadLocationException("Bad Location(" 163 + doc_pos + ", " + doc_len + ")", doc_pos); 164 165 startElem = htmlDoc.getCharacterElement(doc_pos); 166 167 int start_offset = startElem.getStartOffset(); 168 169 // Positions before start_offset will not be traversed, and thus 170 // will not be counted. 171 if (start_offset > 0) 172 doc_offset_remaining = doc_offset_remaining - start_offset; 173 174 Element tempParentElem = startElem; 175 176 while ((tempParentElem = tempParentElem.getParentElement()) != null) 177 { 178 if (!htmlFragmentParentHashSet.contains(tempParentElem)) 179 htmlFragmentParentHashSet.add(tempParentElem); 180 } // while((tempParentElem = tempParentElem.getParentElement()) 181 // != null) 182 183 // NOTE: 20061030 - fchoong - the last index should not be included. 184 endElem = htmlDoc.getCharacterElement(doc_pos + doc_len - 1); 185 186 tempParentElem = endElem; 187 188 while ((tempParentElem = tempParentElem.getParentElement()) != null) 189 { 190 if (!htmlFragmentParentHashSet.contains(tempParentElem)) 191 htmlFragmentParentHashSet.add(tempParentElem); 192 } // while((tempParentElem = tempParentElem.getParentElement()) 193 // != null) 194 195 traverseHtmlFragment(rootElem); 196 197 } // else 198 199 // NOTE: close out remaining open embeded tags. 200 HTML.Tag[] tag_arr = 201 openEmbeddedTagHashSet.toArray(new HTML.Tag[openEmbeddedTagHashSet.size()]); 202 203 for (int i = 0; i < tag_arr.length; i++) 204 { 205 writeRaw("</" + tag_arr[i].toString() + ">"); 206 } // for(int i = 0; i < tag_arr.length; i++) 207 208 } // public void write() throws IOException, BadLocationException 209 210 /** 211 * Writes all the attributes in the attrSet, except for attrbutes with 212 * keys of <code>javax.swing.text.html.HTML.Tag</code>, 213 * <code>javax.swing.text.StyleConstants</code> or 214 * <code>javax.swing.text.html.HTML.Attribute.ENDTAG</code>. 215 * 216 * @param attrSet attrSet to write out 217 * 218 * @throws IOException on any I/O exceptions 219 */ 220 protected void writeAttributes(AttributeSet attrSet) 221 throws IOException 222 { 223 Enumeration<?> attrNameEnum = attrSet.getAttributeNames(); 224 225 while (attrNameEnum.hasMoreElements()) 226 { 227 Object key = attrNameEnum.nextElement(); 228 Object value = attrSet.getAttribute(key); 229 230 // HTML.Attribute.ENDTAG is an instance, not a class. 231 if (!((key instanceof HTML.Tag) || (key instanceof StyleConstants) 232 || (key == HTML.Attribute.ENDTAG))) 233 { 234 if (key == HTML.Attribute.SELECTED) 235 writeRaw(" selected"); 236 else if (key == HTML.Attribute.CHECKED) 237 writeRaw(" checked"); 238 else 239 writeRaw(" " + key + "=\"" + value + "\""); 240 } // if(!((key instanceof HTML.Tag) || (key instanceof 241 // StyleConstants) || (key == HTML.Attribute.ENDTAG))) 242 } // while(attrNameEnum.hasMoreElements()) 243 244 } // protected void writeAttributes(AttributeSet attrSet) throws IOException 245 246 /** 247 * Writes out an empty tag. i.e. a tag without any child elements. 248 * 249 * @param paramElem the element to output as an empty tag 250 * 251 * @throws IOException on any I/O exceptions 252 * @throws BadLocationException if a pos is not a valid position in the 253 * html doc element 254 */ 255 protected void emptyTag(Element paramElem) 256 throws IOException, BadLocationException 257 { 258 String elem_name = paramElem.getName(); 259 AttributeSet attrSet = paramElem.getAttributes(); 260 261 writeRaw("<" + elem_name); 262 writeAttributes(attrSet); 263 writeRaw(">"); 264 265 if (isBlockTag(attrSet)) 266 { 267 writeRaw("</" + elem_name + ">"); 268 } // if(isBlockTag(attrSet)) 269 270 } // protected void emptyTag(Element paramElem) 271 // throws IOException, BadLocationException 272 273 /** 274 * Determines if it is a block tag or not. 275 * 276 * @param attrSet the attrSet of the element 277 * 278 * @return <code>true</code> if it is a block tag 279 * <code>false</code> if it is a not block tag 280 */ 281 protected boolean isBlockTag(AttributeSet attrSet) 282 { 283 return ((HTML.Tag) 284 attrSet.getAttribute(StyleConstants.NameAttribute)).isBlock(); 285 } // protected boolean isBlockTag(AttributeSet attrSet) 286 287 /** 288 * Writes out a start tag. Synthesized elements are skipped. 289 * 290 * @param paramElem the element to output as a start tag 291 * @throws IOException on any I/O exceptions 292 * @throws BadLocationException if a pos is not a valid position in the 293 * html doc element 294 */ 295 protected void startTag(Element paramElem) 296 throws IOException, BadLocationException 297 { 298 // NOTE: Sysnthesized elements do no call this method at all. 299 String elem_name = paramElem.getName(); 300 AttributeSet attrSet = paramElem.getAttributes(); 301 302 indent(); 303 writeRaw("<" + elem_name); 304 writeAttributes(attrSet); 305 writeRaw(">"); 306 writeLineSeparator(); // Extra formatting to look more like the RI. 307 incrIndent(); 308 309 } // protected void startTag(Element paramElem) 310 // throws IOException, BadLocationException 311 312 /** 313 * Writes out the contents of a textarea. 314 * 315 * @param attrSet the attrSet of the element to output as a text area 316 * @throws IOException on any I/O exceptions 317 * @throws BadLocationException if a pos is not a valid position in the 318 * html doc element 319 */ 320 protected void textAreaContent(AttributeSet attrSet) 321 throws IOException, BadLocationException 322 { 323 writeLineSeparator(); // Extra formatting to look more like the RI. 324 indent(); 325 writeRaw("<textarea"); 326 writeAttributes(attrSet); 327 writeRaw(">"); 328 329 Document tempDocument = 330 (Document) attrSet.getAttribute(StyleConstants.ModelAttribute); 331 332 writeRaw(tempDocument.getText(0, tempDocument.getLength())); 333 indent(); 334 writeRaw("</textarea>"); 335 336 } // protected void textAreaContent(AttributeSet attrSet) 337 // throws IOException, BadLocationException 338 339 /** 340 * Writes out text, within the appropriate range if it is specified. 341 * 342 * @param paramElem the element to output as a text 343 * @throws IOException on any I/O exceptions 344 * @throws BadLocationException if a pos is not a valid position in the 345 * html doc element 346 */ 347 protected void text(Element paramElem) 348 throws IOException, BadLocationException 349 { 350 int offset = paramElem.getStartOffset(); 351 int len = paramElem.getEndOffset() - paramElem.getStartOffset(); 352 String txt_value = htmlDoc.getText(offset, len); 353 354 writeContent(txt_value); 355 356 } // protected void text(Element paramElem) 357 // throws IOException, BadLocationException 358 359 /** 360 * Writes out the contents of a select element. 361 * 362 * @param attrSet the attrSet of the element to output as a select box 363 * 364 * @throws IOException on any I/O exceptions 365 */ 366 protected void selectContent(AttributeSet attrSet) 367 throws IOException 368 { 369 writeLineSeparator(); // Extra formatting to look more like the RI. 370 indent(); 371 writeRaw("<select"); 372 writeAttributes(attrSet); 373 writeRaw(">"); 374 incrIndent(); 375 writeLineSeparator(); // extra formatting to look more like the RI. 376 377 ComboBoxModel comboBoxModel = 378 (ComboBoxModel) attrSet.getAttribute(StyleConstants.ModelAttribute); 379 380 for (int i = 0; i < comboBoxModel.getSize(); i++) 381 { 382 writeOption((Option) comboBoxModel.getElementAt(i)); 383 } // for(int i = 0; i < comboBoxModel.getSize(); i++) 384 385 decrIndent(); 386 indent(); 387 writeRaw("</select>"); 388 389 } // protected void selectContent(AttributeSet attrSet) throws IOException 390 391 /** 392 * Writes out the contents of an option element. 393 * 394 * @param option the option object to output as a select option 395 * 396 * @throws IOException on any I/O exceptions 397 */ 398 protected void writeOption(Option option) 399 throws IOException 400 { 401 indent(); 402 writeRaw("<option"); 403 writeAttributes(option.getAttributes()); 404 writeRaw(">"); 405 406 writeContent(option.getLabel()); 407 408 writeRaw("</option>"); 409 writeLineSeparator(); // extra formatting to look more like the RI. 410 411 } // protected void writeOption(Option option) throws IOException 412 413 /** 414 * Writes out an end tag. 415 * 416 * @param paramElem the element to output as an end tag 417 * 418 * @throws IOException on any I/O exceptions 419 */ 420 protected void endTag(Element paramElem) 421 throws IOException 422 { 423 String elem_name = paramElem.getName(); 424 425 //writeLineSeparator(); // Extra formatting to look more like the RI. 426 decrIndent(); 427 indent(); 428 writeRaw("</" + elem_name + ">"); 429 writeLineSeparator(); // Extra formatting to look more like the RI. 430 431 } // protected void endTag(Element paramElem) throws IOException 432 433 /** 434 * Writes out the comment. 435 * 436 * @param paramElem the element to output as a comment 437 */ 438 protected void comment(Element paramElem) 439 throws IOException, BadLocationException 440 { 441 AttributeSet attrSet = paramElem.getAttributes(); 442 443 String comment_str = (String) attrSet.getAttribute(HTML.Attribute.COMMENT); 444 445 writeRaw("<!--" + comment_str + "-->"); 446 447 } // protected void comment(Element paramElem) 448 // throws IOException, BadLocationException 449 450 /** 451 * Determines if element is a synthesized 452 * <code>javax.swing.text.Element</code> or not. 453 * 454 * @param element the element to test 455 * 456 * @return <code>true</code> if it is a synthesized element, 457 * <code>false</code> if it is a not synthesized element 458 */ 459 protected boolean synthesizedElement(Element element) 460 { 461 AttributeSet attrSet = element.getAttributes(); 462 Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute); 463 464 if (tagType == HTML.Tag.CONTENT || tagType == HTML.Tag.COMMENT 465 || tagType == HTML.Tag.IMPLIED) 466 return true; 467 else 468 return false; 469 } // protected boolean synthesizedElement(Element element) 470 471 /** 472 * Determines if 473 * <code>javax.swing.text.StyleConstants.NameAttribute</code> 474 * matches tag or not. 475 * 476 * @param attrSet the <code>javax.swing.text.AttributeSet</code> of 477 * element to be matched 478 * @param tag the HTML.Tag to match 479 * 480 * @return <code>true</code> if it matches, 481 * <code>false</code> if it does not match 482 */ 483 protected boolean matchNameAttribute(AttributeSet attrSet, HTML.Tag tag) 484 { 485 Object tagType = attrSet.getAttribute(StyleConstants.NameAttribute); 486 487 if (tagType == tag) 488 return true; 489 else 490 return false; 491 } // protected boolean matchNameAttribute(AttributeSet attrSet, 492 // HTML.Tag tag) 493 494 /** 495 * Writes out an embedded tag. The tags not already in 496 * openEmbededTagHashSet will written out. 497 * 498 * @param attrSet the <code>javax.swing.text.AttributeSet</code> of 499 * the element to write out 500 * 501 * @throws IOException on any I/O exceptions 502 */ 503 protected void writeEmbeddedTags(AttributeSet attrSet) 504 throws IOException 505 { 506 Enumeration<?> attrNameEnum = attrSet.getAttributeNames(); 507 508 while (attrNameEnum.hasMoreElements()) 509 { 510 Object key = attrNameEnum.nextElement(); 511 Object value = attrSet.getAttribute(key); 512 513 if (key instanceof HTML.Tag) 514 { 515 if (!openEmbeddedTagHashSet.contains(key)) 516 { 517 writeRaw("<" + key); 518 writeAttributes((AttributeSet) value); 519 writeRaw(">"); 520 openEmbeddedTagHashSet.add((HTML.Tag) key); 521 } // if(!openEmbededTagHashSet.contains(key)) 522 } // if(key instanceof HTML.Tag) 523 } // while(attrNameEnum.hasMoreElements()) 524 525 } // protected void writeEmbeddedTags(AttributeSet attrSet) 526 // throws IOException 527 528 /** 529 * Closes out an unwanted embedded tag. The tags from the 530 * openEmbededTagHashSet not found in attrSet will be written out. 531 * 532 * @param attrSet the AttributeSet of the element to write out 533 * 534 * @throws IOException on any I/O exceptions 535 */ 536 protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet) 537 throws IOException 538 { 539 HTML.Tag[] tag_arr = 540 openEmbeddedTagHashSet.toArray(new HTML.Tag[openEmbeddedTagHashSet.size()]); 541 542 for (int i = 0; i < tag_arr.length; i++) 543 { 544 HTML.Tag key = tag_arr[i]; 545 546 if (!attrSet.isDefined(key)) 547 { 548 writeRaw("</" + key.toString() + ">"); 549 openEmbeddedTagHashSet.remove(key); 550 } // if(!attrSet.isDefined(key)) 551 } // for(int i = 0; i < tag_arr.length; i++) 552 553 } // protected void closeOutUnwantedEmbeddedTags(AttributeSet attrSet) 554 // throws IOException 555 556 /** 557 * Writes out a line separator. Overwrites the parent to write out a new 558 * line. 559 * 560 * @throws IOException on any I/O exceptions. 561 */ 562 protected void writeLineSeparator() 563 throws IOException 564 { 565 writeRaw(new_line_str); 566 } // protected void writeLineSeparator() throws IOException 567 568 /** 569 * Write to the writer. Character entites such as <, > 570 * are escaped appropriately. 571 * 572 * @param chars char array to write out 573 * @param off offset 574 * @param len length 575 * 576 * @throws IOException on any I/O exceptions 577 */ 578 protected void output(char[] chars, int off, int len) 579 throws IOException 580 { 581 CPStringBuilder strBuffer = new CPStringBuilder(); 582 583 for (int i = 0; i < chars.length; i++) 584 { 585 if (isCharHtmlEntity(chars[i])) 586 strBuffer.append(escapeCharHtmlEntity(chars[i])); 587 else 588 strBuffer.append(chars[i]); 589 } // for(int i = 0; i < chars.length; i++) 590 591 writeRaw(strBuffer.toString()); 592 593 } // protected void output(char[] chars, int off, int len) 594 // throws IOException 595 596 //------------------------------------------------------------------------- 597 // private methods 598 599 /** 600 * The main method used to traverse through the elements. 601 * 602 * @param paramElem element to traverse 603 * 604 * @throws IOException on any I/O exceptions 605 */ 606 private void traverse(Element paramElem) 607 throws IOException, BadLocationException 608 { 609 Element currElem = paramElem; 610 611 AttributeSet attrSet = currElem.getAttributes(); 612 613 closeOutUnwantedEmbeddedTags(attrSet); 614 615 // handle the tag 616 if (synthesizedElement(paramElem)) 617 { 618 if (matchNameAttribute(attrSet, HTML.Tag.CONTENT)) 619 { 620 writeEmbeddedTags(attrSet); 621 text(currElem); 622 } // if(matchNameAttribute(attrSet, HTML.Tag.CONTENT)) 623 else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT)) 624 { 625 comment(currElem); 626 } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT)) 627 else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) 628 { 629 int child_elem_count = currElem.getElementCount(); 630 631 if (child_elem_count > 0) 632 { 633 for (int i = 0; i < child_elem_count; i++) 634 { 635 Element childElem = paramElem.getElement(i); 636 637 traverse(childElem); 638 639 } // for(int i = 0; i < child_elem_count; i++) 640 } // if(child_elem_count > 0) 641 } // else if(matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) 642 } // if(synthesizedElement(paramElem)) 643 else 644 { 645 // NOTE: 20061030 - fchoong - title is treated specially here. 646 // based on RI behavior. 647 if (matchNameAttribute(attrSet, HTML.Tag.TITLE)) 648 { 649 boolean fg_is_end_tag = false; 650 Enumeration<?> attrNameEnum = attrSet.getAttributeNames(); 651 652 while (attrNameEnum.hasMoreElements()) 653 { 654 Object key = attrNameEnum.nextElement(); 655 Object value = attrSet.getAttribute(key); 656 657 if (key == HTML.Attribute.ENDTAG && value.equals("true")) 658 fg_is_end_tag = true; 659 } // while(attrNameEnum.hasMoreElements()) 660 661 if (fg_is_end_tag) 662 writeRaw("</title>"); 663 else 664 { 665 indent(); 666 writeRaw("<title>"); 667 668 String title_str = 669 (String) htmlDoc.getProperty(HTMLDocument.TitleProperty); 670 671 if (title_str != null) 672 writeContent(title_str); 673 674 } // else 675 } // if(matchNameAttribute(attrSet, HTML.Tag.TITLE)) 676 else if (matchNameAttribute(attrSet, HTML.Tag.PRE)) 677 { 678 // We pursue more stringent formating here. 679 attrSet = paramElem.getAttributes(); 680 681 indent(); 682 writeRaw("<pre"); 683 writeAttributes(attrSet); 684 writeRaw(">"); 685 686 int child_elem_count = currElem.getElementCount(); 687 688 for (int i = 0; i < child_elem_count; i++) 689 { 690 Element childElem = paramElem.getElement(i); 691 692 traverse(childElem); 693 694 } // for(int i = 0; i < child_elem_count; i++) 695 696 writeRaw("</pre>"); 697 698 } // else if(matchNameAttribute(attrSet, HTML.Tag.PRE)) 699 else if (matchNameAttribute(attrSet, HTML.Tag.SELECT)) 700 { 701 selectContent(attrSet); 702 } // else if(matchNameAttribute(attrSet, HTML.Tag.SELECT)) 703 else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA)) 704 { 705 textAreaContent(attrSet); 706 } // else if(matchNameAttribute(attrSet, HTML.Tag.TEXTAREA)) 707 else 708 { 709 int child_elem_count = currElem.getElementCount(); 710 711 if (child_elem_count > 0) 712 { 713 startTag(currElem); 714 715 for (int i = 0; i < child_elem_count; i++) 716 { 717 Element childElem = paramElem.getElement(i); 718 719 traverse(childElem); 720 721 } // for(int i = 0; i < child_elem_count; i++) 722 723 endTag(currElem); 724 725 } // if(child_elem_count > 0) 726 else 727 { 728 emptyTag(currElem); 729 } // else 730 } // else 731 } // else 732 733 } // private void traverse(Element paramElem) 734 // throws IOException, BadLocationException 735 736 /** 737 * The method used to traverse through a html fragment. 738 * 739 * @param paramElem element to traverse 740 * 741 * @throws IOException on any I/O exceptions 742 */ 743 private void traverseHtmlFragment(Element paramElem) 744 throws IOException, BadLocationException 745 { 746 // NOTE: This method is similar to traverse(Element paramElem) 747 Element currElem = paramElem; 748 749 boolean fg_is_fragment_parent_elem = false; 750 boolean fg_is_start_and_end_elem = false; 751 752 if (htmlFragmentParentHashSet.contains(paramElem)) 753 fg_is_fragment_parent_elem = true; 754 755 if (paramElem == startElem) 756 fg_pass_start_elem = true; 757 758 if (paramElem == startElem && paramElem == endElem) 759 fg_is_start_and_end_elem = true; 760 761 AttributeSet attrSet = currElem.getAttributes(); 762 763 closeOutUnwantedEmbeddedTags(attrSet); 764 765 if (fg_is_fragment_parent_elem || (fg_pass_start_elem 766 && fg_pass_end_elem == false) || fg_is_start_and_end_elem) 767 { 768 // handle the tag 769 if (synthesizedElement(paramElem)) 770 { 771 if (matchNameAttribute(attrSet, HTML.Tag.CONTENT)) 772 { 773 writeEmbeddedTags(attrSet); 774 775 int content_offset = paramElem.getStartOffset(); 776 int content_length = currElem.getEndOffset() - content_offset; 777 778 if (doc_offset_remaining > 0) 779 { 780 if (content_length > doc_offset_remaining) 781 { 782 int split_len = content_length; 783 784 split_len = split_len - doc_offset_remaining; 785 786 if (split_len > doc_len_remaining) 787 split_len = doc_len_remaining; 788 789 // we need to split it. 790 String txt_value = htmlDoc.getText(content_offset 791 + doc_offset_remaining, split_len); 792 793 writeContent(txt_value); 794 795 doc_offset_remaining = 0; // the offset is used up. 796 doc_len_remaining = doc_len_remaining - split_len; 797 } // if(content_length > doc_offset_remaining) 798 else 799 { 800 // doc_offset_remaining is greater than the entire 801 // length of content 802 doc_offset_remaining = doc_offset_remaining 803 - content_length; 804 } // else 805 } // if(doc_offset_remaining > 0) 806 else if (content_length <= doc_len_remaining) 807 { 808 // we can fit the entire content. 809 text(currElem); 810 doc_len_remaining = doc_len_remaining - content_length; 811 } // else if(content_length <= doc_len_remaining) 812 else 813 { 814 // we need to split it. 815 String txt_value = htmlDoc.getText(content_offset, 816 doc_len_remaining); 817 818 writeContent(txt_value); 819 820 doc_len_remaining = 0; 821 } // else 822 823 } // if(matchNameAttribute(attrSet, HTML.Tag.CONTENT)) 824 else if (matchNameAttribute(attrSet, HTML.Tag.COMMENT)) 825 { 826 comment(currElem); 827 } // else if(matchNameAttribute(attrSet, HTML.Tag.COMMENT)) 828 else if (matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) 829 { 830 int child_elem_count = currElem.getElementCount(); 831 832 if (child_elem_count > 0) 833 { 834 for (int i = 0; i < child_elem_count; i++) 835 { 836 Element childElem = paramElem.getElement(i); 837 838 traverseHtmlFragment(childElem); 839 840 } // for(int i = 0; i < child_elem_count; i++) 841 } // if(child_elem_count > 0) 842 } // else if(matchNameAttribute(attrSet, HTML.Tag.IMPLIED)) 843 } // if(synthesizedElement(paramElem)) 844 else 845 { 846 // NOTE: 20061030 - fchoong - the isLeaf() condition seems to 847 // generate the closest behavior to the RI. 848 if (paramElem.isLeaf()) 849 { 850 if (doc_offset_remaining > 0) 851 { 852 doc_offset_remaining--; 853 } // if(doc_offset_remaining > 0) 854 else if (doc_len_remaining > 0) 855 { 856 doc_len_remaining--; 857 } // else if(doc_len_remaining > 0) 858 } // if(paramElem.isLeaf()) 859 860 // NOTE: 20061030 - fchoong - title is treated specially here. 861 // based on RI behavior. 862 if (matchNameAttribute(attrSet, HTML.Tag.TITLE)) 863 { 864 boolean fg_is_end_tag = false; 865 Enumeration<?> attrNameEnum = attrSet.getAttributeNames(); 866 867 while (attrNameEnum.hasMoreElements()) 868 { 869 Object key = attrNameEnum.nextElement(); 870 Object value = attrSet.getAttribute(key); 871 872 if (key == HTML.Attribute.ENDTAG && value.equals("true")) 873 fg_is_end_tag = true; 874 } // while(attrNameEnum.hasMoreElements()) 875 876 if (fg_is_end_tag) 877 writeRaw("</title>"); 878 else 879 { 880 indent(); 881 writeRaw("<title>"); 882 883 String title_str = 884 (String) htmlDoc.getProperty(HTMLDocument.TitleProperty); 885 886 if (title_str != null) 887 writeContent(title_str); 888 889 } // else 890 } // if(matchNameAttribute(attrSet, HTML.Tag.TITLE)) 891 else if (matchNameAttribute(attrSet, HTML.Tag.PRE)) 892 { 893 // We pursue more stringent formating here. 894 attrSet = paramElem.getAttributes(); 895 896 indent(); 897 writeRaw("<pre"); 898 writeAttributes(attrSet); 899 writeRaw(">"); 900 901 int child_elem_count = currElem.getElementCount(); 902 903 for (int i = 0; i < child_elem_count; i++) 904 { 905 Element childElem = paramElem.getElement(i); 906 907 traverseHtmlFragment(childElem); 908 909 } // for(int i = 0; i < child_elem_count; i++) 910 911 writeRaw("</pre>"); 912 913 } // else if(matchNameAttribute(attrSet, HTML.Tag.PRE)) 914 else if (matchNameAttribute(attrSet, HTML.Tag.SELECT)) 915 { 916 selectContent(attrSet); 917 } // else if(matchNameAttribute(attrSet, HTML.Tag.SELECT)) 918 else if (matchNameAttribute(attrSet, HTML.Tag.TEXTAREA)) 919 { 920 textAreaContent(attrSet); 921 } // else if(matchNameAttribute(attrSet, HTML.Tag.TEXTAREA)) 922 else 923 { 924 int child_elem_count = currElem.getElementCount(); 925 926 if (child_elem_count > 0) 927 { 928 startTag(currElem); 929 930 for (int i = 0; i < child_elem_count; i++) 931 { 932 Element childElem = paramElem.getElement(i); 933 934 traverseHtmlFragment(childElem); 935 936 } // for(int i = 0; i < child_elem_count; i++) 937 938 endTag(currElem); 939 940 } // if(child_elem_count > 0) 941 else 942 { 943 emptyTag(currElem); 944 } // else 945 } // else 946 } // else 947 948 } // if(fg_is_fragment_parent_elem || (fg_pass_start_elem 949 // && fg_pass_end_elem == false) || fg_is_start_and_end_elem) 950 951 if (paramElem == endElem) 952 fg_pass_end_elem = true; 953 954 } // private void traverseHtmlFragment(Element paramElem) 955 // throws IOException, BadLocationException 956 957 /** 958 * Write to the writer without any modifications. 959 * 960 * @param param_str the str to write out 961 * 962 * @throws IOException on any I/O exceptions 963 */ 964 private void writeRaw(String param_str) 965 throws IOException 966 { 967 super.output(param_str.toCharArray(), 0, param_str.length()); 968 } // private void writeRaw(char[] chars, int off, int len) 969 // throws IOException 970 971 /** 972 * Write to the writer, escaping HTML character entitie where neccessary. 973 * 974 * @param param_str the str to write out 975 * 976 * @throws IOException on any I/O exceptions 977 */ 978 private void writeContent(String param_str) 979 throws IOException 980 { 981 char[] str_char_arr = param_str.toCharArray(); 982 983 if (hasHtmlEntity(param_str)) 984 output(str_char_arr, 0, str_char_arr.length); 985 else 986 super.output(str_char_arr, 0, str_char_arr.length); 987 988 } // private void writeContent(String param_str) throws IOException 989 990 /** 991 * Use this for debugging. Writes out all attributes regardless of type. 992 * 993 * @param attrSet the <code>javax.swing.text.AttributeSet</code> to 994 * write out 995 * 996 * @throws IOException on any I/O exceptions 997 */ 998 private void writeAllAttributes(AttributeSet attrSet) 999 throws IOException 1000 { 1001 Enumeration<?> attrNameEnum = attrSet.getAttributeNames(); 1002 1003 while (attrNameEnum.hasMoreElements()) 1004 { 1005 Object key = attrNameEnum.nextElement(); 1006 Object value = attrSet.getAttribute(key); 1007 1008 writeRaw(" " + key + "=\"" + value + "\""); 1009 writeRaw(" " + key.getClass().toString() + "=\"" 1010 + value.getClass().toString() + "\""); 1011 } // while(attrNameEnum.hasMoreElements()) 1012 1013 } // private void writeAllAttributes(AttributeSet attrSet) 1014 // throws IOException 1015 1016 /** 1017 * Tests if the str contains any html entities. 1018 * 1019 * @param param_str the str to test 1020 * 1021 * @return <code>true</code> if it has a html entity 1022 * <code>false</code> if it does not have a html entity 1023 */ 1024 private boolean hasHtmlEntity(String param_str) 1025 { 1026 boolean ret_bool = false; 1027 1028 for (int i = 0; i < html_entity_char_arr.length; i++) 1029 { 1030 if (param_str.indexOf(html_entity_char_arr[i]) != -1) 1031 { 1032 ret_bool = true; 1033 break; 1034 } // if(param_str.indexOf(html_entity_char_arr[i]) != -1) 1035 } // for(int i = 0; i < html_entity_char_arr.length; i++) 1036 1037 return ret_bool; 1038 } // private boolean hasHtmlEntity(String param_str) 1039 1040 /** 1041 * Tests if the char is a html entities. 1042 * 1043 * @param param_char the char to test 1044 * 1045 * @return <code>true</code> if it is a html entity 1046 * <code>false</code> if it is not a html entity. 1047 */ 1048 private boolean isCharHtmlEntity(char param_char) 1049 { 1050 boolean ret_bool = false; 1051 1052 for (int i = 0; i < html_entity_char_arr.length; i++) 1053 { 1054 if (param_char == html_entity_char_arr[i]) 1055 { 1056 ret_bool = true; 1057 break; 1058 } // if(param_char == html_entity_char_arr[i]) 1059 } // for(int i = 0; i < html_entity_char_arr.length; i++) 1060 1061 return ret_bool; 1062 } // private boolean hasHtmlEntity(String param_str) 1063 1064 /** 1065 * Escape html entities. 1066 * 1067 * @param param_char the char to escape 1068 * 1069 * @return escaped html entity. Original char is returned as a str if is 1070 * is not a html entity 1071 */ 1072 private String escapeCharHtmlEntity(char param_char) 1073 { 1074 String ret_str = "" + param_char; 1075 1076 for (int i = 0; i < html_entity_char_arr.length; i++) 1077 { 1078 if (param_char == html_entity_char_arr[i]) 1079 { 1080 ret_str = html_entity_escape_str_arr[i]; 1081 break; 1082 } // if(param_char == html_entity_char_arr[i]) 1083 } // for(int i = 0; i < html_entity_char_arr.length; i++) 1084 1085 return ret_str; 1086 } // private String escapeCharHtmlEntity(char param_char) 1087 1088 } // public class HTMLWriter extends AbstractWriter