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