001package org.apache.maven.doxia.module.itext; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import com.lowagie.text.BadElementException; 023import com.lowagie.text.ElementTags; 024import com.lowagie.text.Image; 025 026import java.awt.Color; 027import java.io.File; 028import java.io.IOException; 029import java.io.LineNumberReader; 030import java.io.StringReader; 031import java.io.StringWriter; 032import java.io.Writer; 033import java.net.MalformedURLException; 034import java.net.URL; 035import java.util.HashMap; 036import java.util.Locale; 037import java.util.Map; 038import java.util.Set; 039import java.util.TreeSet; 040 041import org.apache.maven.doxia.sink.Sink; 042import org.apache.maven.doxia.sink.SinkEventAttributes; 043import org.apache.maven.doxia.sink.impl.AbstractXmlSink; 044import org.apache.maven.doxia.util.DoxiaUtils; 045import org.apache.maven.doxia.util.HtmlTools; 046 047import org.codehaus.plexus.util.IOUtil; 048import org.codehaus.plexus.util.StringUtils; 049import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter; 050import org.codehaus.plexus.util.xml.XMLWriter; 051 052/** 053 * <p>A doxia Sink which produces an XML Front End document for <code>iText</code> framework.</p> 054 * Known limitations: 055 * <ul> 056 * <li>Roman lists are not supported.</li> 057 * <li>Horizontal rule is not supported with 1.3. 058 * See <a href="http://www.mail-archive.com/itext-questions@lists.sourceforge.net/msg10323.html"> 059 * http://www.mail-archive.com/itext-questions@lists.sourceforge.net/msg10323.html</a></li> 060 * <li>iText has some problems with <code>ElementTags.TABLE</code> and <code>ElementTags.TABLEFITSPAGE</code>. 061 * See http://sourceforge.net/tracker/index.php?func=detail&aid=786427&group_id=15255&atid=115255.</li> 062 * <li>Images could be on another page and next text on the last one.</li> 063 * </ul> 064 * 065 * @see <a href="http://www.lowagie.com/iText/tutorial/ch07.html">http://www.lowagie.com/iText/tutorial/ch07.html</a> 066 * 067 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a> 068 * @version $Id$ 069 */ 070public class ITextSink 071 extends AbstractXmlSink 072{ 073 /** This is the place where the iText DTD is located. IMPORTANT: this DTD is not uptodate! */ 074 public static final String DTD = "http://itext.sourceforge.net/itext.dtd"; 075 076 /** This is the reference to the DTD. */ 077 public static final String DOCTYPE = "ITEXT SYSTEM \"" + DTD + "\""; 078 079 /** This is the default leading for chapter title */ 080 public static final String DEFAULT_CHAPTER_TITLE_LEADING = "36.0"; 081 082 /** This is the default leading for section title */ 083 public static final String DEFAULT_SECTION_TITLE_LEADING = "24.0"; 084 085 /** The ClassLoader used */ 086 private ClassLoader currentClassLoader; 087 088 /** The action context */ 089 private SinkActionContext actionContext; 090 091 /** The Writer used */ 092 private Writer writer; 093 094 /** The XML Writer used */ 095 private final XMLWriter xmlWriter; 096 097 private boolean writeStart; 098 099 /** The Header object */ 100 private ITextHeader header; 101 102 /** The font object */ 103 private ITextFont font; 104 105 private int numberDepth = 1; 106 107 private int depth = 0; 108 109 private StringWriter tableCaptionWriter = null; 110 111 private XMLWriter tableCaptionXMLWriter = null; 112 113 /** Flag to know if an anchor is defined or not. Used as workaround for iText which needs a defined local 114 * destination. */ 115 private boolean anchorDefined = false; 116 117 /** Flag to know if an figure event is called. */ 118 private boolean figureDefined = false; 119 120 /** Map of warn messages with a String as key to describe the error type and a Set as value. 121 * Using to reduce warn messages. */ 122 private Map<String, Set<String>> warnMessages; 123 124 /** 125 * <p>Constructor for ITextSink.</p> 126 * 127 * @param writer the writer. 128 */ 129 protected ITextSink( Writer writer ) 130 { 131 this( writer, "UTF-8" ); 132 } 133 134 /** 135 * <p>Constructor for ITextSink.</p> 136 * 137 * @param writer the writer. 138 * @param encoding the encoding. 139 * @since 1.1 140 */ 141 protected ITextSink( Writer writer, String encoding ) 142 { 143 // No doctype since itext doctype is not up to date! 144 this( new PrettyPrintXMLWriter( writer, encoding, null ) ); 145 146 this.writer = writer; 147 this.writeStart = true; 148 } 149 150 /** 151 * <p>Constructor for ITextSink.</p> 152 * 153 * @param xmlWriter a pretty-printing xml writer. 154 */ 155 protected ITextSink( PrettyPrintXMLWriter xmlWriter ) 156 { 157 this.xmlWriter = xmlWriter; 158 159 this.writeStart = false; 160 161 init(); 162 } 163 164 /** 165 * Get the current classLoader 166 * 167 * @return the current class loader 168 */ 169 public ClassLoader getClassLoader() 170 { 171 return currentClassLoader; 172 } 173 174 /** 175 * Set a new class loader 176 * 177 * @param cl the class loader. 178 */ 179 public void setClassLoader( ClassLoader cl ) 180 { 181 currentClassLoader = cl; 182 } 183 184 // ---------------------------------------------------------------------- 185 // Document 186 // ---------------------------------------------------------------------- 187 188 /** {@inheritDoc} */ 189 public void close() 190 { 191 IOUtil.close( writer ); 192 193 init(); 194 } 195 196 /** {@inheritDoc} */ 197 public void flush() 198 { 199 if ( getLog().isWarnEnabled() && this.warnMessages != null ) 200 { 201 for ( Map.Entry<String, Set<String>> entry : this.warnMessages.entrySet() ) 202 { 203 for ( String msg : entry.getValue() ) 204 { 205 getLog().warn( msg ); 206 } 207 } 208 } 209 210 this.warnMessages = null; 211 } 212 213 // ---------------------------------------------------------------------- 214 // Header 215 // ---------------------------------------------------------------------- 216 217 /** {@inheritDoc} */ 218 public void head_() 219 { 220 actionContext.release(); 221 } 222 223 /** {@inheritDoc} */ 224 public void head() 225 { 226 //init(); // why? this causes DOXIA-413 227 228 actionContext.setAction( SinkActionContext.HEAD ); 229 } 230 231 /** {@inheritDoc} */ 232 public void author_() 233 { 234 actionContext.release(); 235 } 236 237 /** {@inheritDoc} */ 238 public void author() 239 { 240 actionContext.setAction( SinkActionContext.AUTHOR ); 241 } 242 243 /** {@inheritDoc} */ 244 public void date_() 245 { 246 actionContext.release(); 247 } 248 249 /** {@inheritDoc} */ 250 public void date() 251 { 252 actionContext.setAction( SinkActionContext.DATE ); 253 } 254 255 /** {@inheritDoc} */ 256 public void title_() 257 { 258 actionContext.release(); 259 } 260 261 /** {@inheritDoc} */ 262 public void title() 263 { 264 actionContext.setAction( SinkActionContext.TITLE ); 265 } 266 267 // ---------------------------------------------------------------------- 268 // Body 269 // ---------------------------------------------------------------------- 270 271 /** {@inheritDoc} */ 272 public void body_() 273 { 274 if ( writeStart ) 275 { 276 writeEndElement(); // ElementTags.CHAPTER 277 278 writeEndElement(); // ElementTags.ITEXT 279 } 280 281 actionContext.release(); 282 } 283 284 /** {@inheritDoc} */ 285 public void body() 286 { 287 if ( writeStart ) 288 { 289 writeStartElement( ElementTags.ITEXT ); 290 writeAddAttribute( ElementTags.TITLE, header.getTitle() ); 291 writeAddAttribute( ElementTags.AUTHOR, header.getAuthors() ); 292 writeAddAttribute( ElementTags.CREATIONDATE, header.getDate() ); 293 writeAddAttribute( ElementTags.SUBJECT, header.getTitle() ); 294 writeAddAttribute( ElementTags.KEYWORDS, "" ); 295 writeAddAttribute( ElementTags.PRODUCER, "Generated with Doxia by " + System.getProperty( "user.name" ) ); 296 writeAddAttribute( ElementTags.PAGE_SIZE, ITextUtil.getPageSize( ITextUtil.getDefaultPageSize() ) ); 297 298 writeStartElement( ElementTags.CHAPTER ); 299 writeAddAttribute( ElementTags.NUMBERDEPTH, numberDepth ); 300 writeAddAttribute( ElementTags.DEPTH, depth ); 301 writeAddAttribute( ElementTags.INDENT, "0.0" ); 302 303 writeStartElement( ElementTags.TITLE ); 304 writeAddAttribute( ElementTags.LEADING, DEFAULT_CHAPTER_TITLE_LEADING ); 305 writeAddAttribute( ElementTags.FONT, ITextFont.DEFAULT_FONT_NAME ); 306 writeAddAttribute( ElementTags.SIZE, ITextFont.getSectionFontSize( 0 ) ); 307 writeAddAttribute( ElementTags.STYLE, ITextFont.BOLD ); 308 writeAddAttribute( ElementTags.BLUE, ITextFont.DEFAULT_FONT_COLOR_BLUE ); 309 writeAddAttribute( ElementTags.GREEN, ITextFont.DEFAULT_FONT_COLOR_GREEN ); 310 writeAddAttribute( ElementTags.RED, ITextFont.DEFAULT_FONT_COLOR_RED ); 311 writeAddAttribute( ElementTags.ALIGN, ElementTags.ALIGN_CENTER ); 312 313// startChunk( ITextFont.DEFAULT_FONT_NAME, ITextFont.getSectionFontSize( 0 ), 314// ITextFont.BOLD, ITextFont.DEFAULT_FONT_COLOR_BLUE, ITextFont.DEFAULT_FONT_COLOR_GREEN, 315// ITextFont.DEFAULT_FONT_COLOR_RED, "top" ); 316 317 writeStartElement( ElementTags.CHUNK ); 318 writeAddAttribute( ElementTags.FONT, ITextFont.DEFAULT_FONT_NAME ); 319 writeAddAttribute( ElementTags.SIZE, ITextFont.getSectionFontSize( 0 ) ); 320 writeAddAttribute( ElementTags.STYLE, ITextFont.BOLD ); 321 writeAddAttribute( ElementTags.BLUE, ITextFont.DEFAULT_FONT_COLOR_BLUE ); 322 writeAddAttribute( ElementTags.GREEN, ITextFont.DEFAULT_FONT_COLOR_GREEN ); 323 writeAddAttribute( ElementTags.RED, ITextFont.DEFAULT_FONT_COLOR_RED ); 324// writeAddAttribute( ElementTags.LOCALDESTINATION, "top" ); 325 326 write( header.getTitle() ); 327 328 writeEndElement(); // ElementTags.CHUNK 329 330 writeEndElement(); // ElementTags.TITLE 331 } 332 333 actionContext.setAction( SinkActionContext.BODY ); 334 } 335 336 // ---------------------------------------------------------------------- 337 // Sections 338 // ---------------------------------------------------------------------- 339 340 /** {@inheritDoc} */ 341 public void sectionTitle() 342 { 343 actionContext.release(); 344 } 345 346 /** {@inheritDoc} */ 347 public void sectionTitle_() 348 { 349 actionContext.setAction( SinkActionContext.SECTION_TITLE ); 350 } 351 352 /** {@inheritDoc} */ 353 public void section1_() 354 { 355 writeEndElement(); // ElementTags.SECTION 356 357 numberDepth--; 358 depth = 0; 359 360 actionContext.release(); 361 } 362 363 /** {@inheritDoc} */ 364 public void section1() 365 { 366 numberDepth++; 367 depth = 1; 368 369 writeStartElement( ElementTags.SECTION ); 370 writeAddAttribute( ElementTags.NUMBERDEPTH, numberDepth ); 371 writeAddAttribute( ElementTags.DEPTH, depth ); 372 writeAddAttribute( ElementTags.INDENT, "0.0" ); 373 374 lineBreak(); 375 376 actionContext.setAction( SinkActionContext.SECTION_1 ); 377 } 378 379 /** {@inheritDoc} */ 380 public void sectionTitle1_() 381 { 382 writeEndElement(); // ElementTags.TITLE 383 384 font.setSize( ITextFont.DEFAULT_FONT_SIZE ); 385 bold_(); 386 387 actionContext.release(); 388 } 389 390 /** {@inheritDoc} */ 391 public void sectionTitle1() 392 { 393 font.setSize( ITextFont.getSectionFontSize( 1 ) ); 394 font.setColor( Color.BLACK ); 395 bold(); 396 397 writeStartElement( ElementTags.TITLE ); 398 writeAddAttribute( ElementTags.LEADING, DEFAULT_SECTION_TITLE_LEADING ); 399 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 400 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 401 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 402 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 403 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 404 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 405// writeAddAttribute( ElementTags.LOCALDESTINATION, "top" ); // trygve 406 407 actionContext.setAction( SinkActionContext.SECTION_TITLE_1 ); 408 } 409 410 /** {@inheritDoc} */ 411 public void section2_() 412 { 413 writeEndElement(); // ElementTags.SECTION 414 415 numberDepth--; 416 depth = 0; 417 418 actionContext.release(); 419 } 420 421 /** {@inheritDoc} */ 422 public void section2() 423 { 424 numberDepth++; 425 depth = 1; 426 427 writeStartElement( ElementTags.SECTION ); 428 writeAddAttribute( ElementTags.NUMBERDEPTH, numberDepth ); 429 writeAddAttribute( ElementTags.DEPTH, depth ); 430 writeAddAttribute( ElementTags.INDENT, "0.0" ); 431 432 lineBreak(); 433 434 actionContext.setAction( SinkActionContext.SECTION_2 ); 435 } 436 437 /** {@inheritDoc} */ 438 public void sectionTitle2_() 439 { 440 writeEndElement(); // ElementTags.TITLE 441 442 font.setSize( ITextFont.DEFAULT_FONT_SIZE ); 443 bold_(); 444 445 actionContext.release(); 446 } 447 448 /** {@inheritDoc} */ 449 public void sectionTitle2() 450 { 451 font.setSize( ITextFont.getSectionFontSize( 2 ) ); 452 font.setColor( Color.BLACK ); 453 bold(); 454 455 writeStartElement( ElementTags.TITLE ); 456 writeAddAttribute( ElementTags.LEADING, DEFAULT_SECTION_TITLE_LEADING ); 457 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 458 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 459 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 460 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 461 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 462 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 463// writeAddAttribute( ElementTags.LOCALDESTINATION, "top" ); // trygve 464 465 actionContext.setAction( SinkActionContext.SECTION_TITLE_2 ); 466 } 467 468 /** {@inheritDoc} */ 469 public void section3_() 470 { 471 writeEndElement(); // ElementTags.SECTION 472 473 numberDepth--; 474 depth = 1; 475 476 actionContext.release(); 477 } 478 479 /** {@inheritDoc} */ 480 public void section3() 481 { 482 numberDepth++; 483 depth = 1; 484 485 writeStartElement( ElementTags.SECTION ); 486 writeAddAttribute( ElementTags.NUMBERDEPTH, numberDepth ); 487 writeAddAttribute( ElementTags.DEPTH, depth ); 488 writeAddAttribute( ElementTags.INDENT, "0.0" ); 489 490 lineBreak(); 491 492 actionContext.setAction( SinkActionContext.SECTION_3 ); 493 } 494 495 /** {@inheritDoc} */ 496 public void sectionTitle3_() 497 { 498 writeEndElement(); // ElementTags.TITLE 499 500 font.setSize( ITextFont.DEFAULT_FONT_SIZE ); 501 bold_(); 502 503 actionContext.release(); 504 } 505 506 /** {@inheritDoc} */ 507 public void sectionTitle3() 508 { 509 font.setSize( ITextFont.getSectionFontSize( 3 ) ); 510 font.setColor( Color.BLACK ); 511 bold(); 512 513 writeStartElement( ElementTags.TITLE ); 514 writeAddAttribute( ElementTags.LEADING, DEFAULT_SECTION_TITLE_LEADING ); 515 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 516 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 517 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 518 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 519 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 520 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 521// writeAddAttribute( ElementTags.LOCALDESTINATION, "top" ); // trygve 522 523 actionContext.setAction( SinkActionContext.SECTION_TITLE_3 ); 524 } 525 526 /** {@inheritDoc} */ 527 public void section4_() 528 { 529 writeEndElement(); // ElementTags.SECTION 530 531 numberDepth--; 532 depth = 1; 533 534 actionContext.release(); 535 } 536 537 /** {@inheritDoc} */ 538 public void section4() 539 { 540 numberDepth++; 541 depth = 1; 542 543 writeStartElement( ElementTags.SECTION ); 544 writeAddAttribute( ElementTags.NUMBERDEPTH, numberDepth ); 545 writeAddAttribute( ElementTags.DEPTH, depth ); 546 writeAddAttribute( ElementTags.INDENT, "0.0" ); 547 548 lineBreak(); 549 550 actionContext.setAction( SinkActionContext.SECTION_4 ); 551 } 552 553 /** {@inheritDoc} */ 554 public void sectionTitle4_() 555 { 556 writeEndElement(); // ElementTags.TITLE 557 558 font.setSize( ITextFont.DEFAULT_FONT_SIZE ); 559 bold_(); 560 561 actionContext.release(); 562 } 563 564 /** {@inheritDoc} */ 565 public void sectionTitle4() 566 { 567 font.setSize( ITextFont.getSectionFontSize( 4 ) ); 568 font.setColor( Color.BLACK ); 569 bold(); 570 571 writeStartElement( ElementTags.TITLE ); 572 writeAddAttribute( ElementTags.LEADING, DEFAULT_SECTION_TITLE_LEADING ); 573 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 574 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 575 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 576 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 577 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 578 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 579// writeAddAttribute( ElementTags.LOCALDESTINATION, "top" ); // trygve 580 581 actionContext.setAction( SinkActionContext.SECTION_TITLE_4 ); 582 } 583 584 /** {@inheritDoc} */ 585 public void section5_() 586 { 587 writeEndElement(); // ElementTags.SECTION 588 589 numberDepth--; 590 depth = 1; 591 592 actionContext.release(); 593 } 594 595 /** {@inheritDoc} */ 596 public void section5() 597 { 598 numberDepth++; 599 depth = 1; 600 601 writeStartElement( ElementTags.SECTION ); 602 writeAddAttribute( ElementTags.NUMBERDEPTH, numberDepth ); 603 writeAddAttribute( ElementTags.DEPTH, depth ); 604 writeAddAttribute( ElementTags.INDENT, "0.0" ); 605 606 lineBreak(); 607 608 actionContext.setAction( SinkActionContext.SECTION_5 ); 609 } 610 611 /** {@inheritDoc} */ 612 public void sectionTitle5_() 613 { 614 writeEndElement(); // ElementTags.TITLE 615 616 font.setSize( ITextFont.DEFAULT_FONT_SIZE ); 617 bold_(); 618 619 actionContext.release(); 620 } 621 622 /** {@inheritDoc} */ 623 public void sectionTitle5() 624 { 625 font.setSize( ITextFont.getSectionFontSize( 5 ) ); 626 font.setColor( Color.BLACK ); 627 bold(); 628 629 writeStartElement( ElementTags.TITLE ); 630 writeAddAttribute( ElementTags.LEADING, DEFAULT_SECTION_TITLE_LEADING ); 631 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 632 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 633 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 634 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 635 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 636 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 637// writeAddAttribute( ElementTags.LOCALDESTINATION, "top" ); // trygve 638 639 actionContext.setAction( SinkActionContext.SECTION_TITLE_5 ); 640 } 641 642 // ---------------------------------------------------------------------- 643 // Paragraph 644 // ---------------------------------------------------------------------- 645 646 /** {@inheritDoc} */ 647 public void paragraph_() 648 { 649 // Special case 650 if ( ( actionContext.getCurrentAction() == SinkActionContext.LIST_ITEM ) 651 || ( actionContext.getCurrentAction() == SinkActionContext.NUMBERED_LIST_ITEM ) 652 || ( actionContext.getCurrentAction() == SinkActionContext.DEFINITION ) ) 653 { 654 return; 655 } 656 657 writeEndElement(); // ElementTags.PARAGRAPH 658 659 actionContext.release(); 660 } 661 662 /** {@inheritDoc} */ 663 public void paragraph() 664 { 665 // Special case 666 if ( ( actionContext.getCurrentAction() == SinkActionContext.LIST_ITEM ) 667 || ( actionContext.getCurrentAction() == SinkActionContext.NUMBERED_LIST_ITEM ) 668 || ( actionContext.getCurrentAction() == SinkActionContext.DEFINITION ) ) 669 { 670 return; 671 } 672 673 writeStartElement( ElementTags.PARAGRAPH ); 674 writeStartElement( ElementTags.NEWLINE ); 675 writeEndElement(); 676 677 actionContext.setAction( SinkActionContext.PARAGRAPH ); 678 } 679 680 // ---------------------------------------------------------------------- 681 // Lists 682 // ---------------------------------------------------------------------- 683 684 /** {@inheritDoc} */ 685 public void list_() 686 { 687 writeEndElement(); // ElementTags.LIST 688 689 writeEndElement(); // ElementTags.CHUNK 690 691 actionContext.release(); 692 } 693 694 /** {@inheritDoc} */ 695 public void list() 696 { 697 writeStartElement( ElementTags.CHUNK ); 698 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 699 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 700 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 701 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 702 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 703 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 704 705 writeStartElement( ElementTags.LIST ); 706 writeAddAttribute( ElementTags.NUMBERED, Boolean.FALSE.toString() ); 707 writeAddAttribute( ElementTags.SYMBOLINDENT, "15" ); 708 709 actionContext.setAction( SinkActionContext.LIST ); 710 } 711 712 /** {@inheritDoc} */ 713 public void listItem_() 714 { 715 writeEndElement(); // ElementTags.LISTITEM 716 717 actionContext.release(); 718 } 719 720 /** {@inheritDoc} */ 721 public void listItem() 722 { 723 writeStartElement( ElementTags.LISTITEM ); 724 writeAddAttribute( ElementTags.INDENTATIONLEFT, "20.0" ); 725 726 actionContext.setAction( SinkActionContext.LIST_ITEM ); 727 } 728 729 /** {@inheritDoc} */ 730 public void numberedList_() 731 { 732 writeEndElement(); // ElementTags.LIST 733 734 writeEndElement(); // ElementTags.CHUNK 735 736 actionContext.release(); 737 } 738 739 /** {@inheritDoc} */ 740 public void numberedList( int numbering ) 741 { 742 writeStartElement( ElementTags.CHUNK ); 743 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 744 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 745 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 746 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 747 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 748 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 749 750 writeStartElement( ElementTags.LIST ); 751 writeAddAttribute( ElementTags.NUMBERED, Boolean.TRUE.toString() ); 752 writeAddAttribute( ElementTags.SYMBOLINDENT, "20" ); 753 754 switch ( numbering ) 755 { 756 case Sink.NUMBERING_UPPER_ALPHA: 757 writeAddAttribute( ElementTags.LETTERED, Boolean.TRUE.toString() ); 758 writeAddAttribute( ElementTags.FIRST, 'A' ); 759 break; 760 761 case Sink.NUMBERING_LOWER_ALPHA: 762 writeAddAttribute( ElementTags.LETTERED, Boolean.TRUE.toString() ); 763 writeAddAttribute( ElementTags.FIRST, 'a' ); 764 break; 765 766 // TODO Doesn't work 767 case Sink.NUMBERING_UPPER_ROMAN: 768 writeAddAttribute( ElementTags.LETTERED, Boolean.TRUE.toString() ); 769 writeAddAttribute( ElementTags.FIRST, 'I' ); 770 break; 771 772 case Sink.NUMBERING_LOWER_ROMAN: 773 writeAddAttribute( ElementTags.LETTERED, Boolean.TRUE.toString() ); 774 writeAddAttribute( ElementTags.FIRST, 'i' ); 775 break; 776 777 case Sink.NUMBERING_DECIMAL: 778 default: 779 writeAddAttribute( ElementTags.LETTERED, Boolean.FALSE.toString() ); 780 } 781 782 actionContext.setAction( SinkActionContext.NUMBERED_LIST ); 783 } 784 785 /** {@inheritDoc} */ 786 public void numberedListItem_() 787 { 788 writeEndElement(); // ElementTags.LISTITEM 789 790 actionContext.release(); 791 } 792 793 /** {@inheritDoc} */ 794 public void numberedListItem() 795 { 796 writeStartElement( ElementTags.LISTITEM ); 797 writeAddAttribute( ElementTags.INDENTATIONLEFT, "20" ); 798 799 actionContext.setAction( SinkActionContext.NUMBERED_LIST_ITEM ); 800 } 801 802 /** {@inheritDoc} */ 803 public void definitionList_() 804 { 805 actionContext.release(); 806 } 807 808 /** {@inheritDoc} */ 809 public void definitionList() 810 { 811 lineBreak(); 812 813 actionContext.setAction( SinkActionContext.DEFINITION_LIST ); 814 } 815 816 /** {@inheritDoc} */ 817 public void definedTerm_() 818 { 819 font.setSize( ITextFont.DEFAULT_FONT_SIZE ); 820 bold_(); 821 822 writeEndElement(); // ElementTags.CHUNK 823 824 actionContext.release(); 825 826 lineBreak(); 827 } 828 829 /** {@inheritDoc} */ 830 public void definedTerm() 831 { 832 font.setSize( ITextFont.DEFAULT_FONT_SIZE + 2 ); 833 bold(); 834 835 writeStartElement( ElementTags.CHUNK ); 836 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 837 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 838 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 839 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 840 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 841 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 842 843 actionContext.setAction( SinkActionContext.DEFINED_TERM ); 844 } 845 846 /** {@inheritDoc} */ 847 public void definition_() 848 { 849 writeEndElement(); // ElementTags.CHUNK 850 851 actionContext.release(); 852 853 lineBreak(); 854 } 855 856 /** {@inheritDoc} */ 857 public void definition() 858 { 859 writeStartElement( ElementTags.CHUNK ); 860 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 861 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 862 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 863 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 864 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 865 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 866 867 868 writeStartElement( ElementTags.CHUNK ); 869 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 870 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 871 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 872 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 873 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 874 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 875 876 // We need to add a non break space first to display empty string 877 write( "\u00A0" + StringUtils.repeat( " ", 16 ), false, false ); 878 879 writeEndElement(); // ElementTags.CHUNK 880 881 actionContext.setAction( SinkActionContext.DEFINITION ); 882 } 883 884 /** {@inheritDoc} */ 885 public void definitionListItem_() 886 { 887 actionContext.release(); 888 } 889 890 /** {@inheritDoc} */ 891 public void definitionListItem() 892 { 893 actionContext.setAction( SinkActionContext.DEFINITION_LIST_ITEM ); 894 } 895 896 // ---------------------------------------------------------------------- 897 // Tables 898 // ---------------------------------------------------------------------- 899 900 /** {@inheritDoc} */ 901 public void table_() 902 { 903 if ( tableCaptionXMLWriter != null ) 904 { 905 tableCaptionXMLWriter = null; 906 907 writeEndElement(); // ElementTags.TABLE 908 909 writeEndElement(); // ElementTags.CHUNK 910 911 writeStartElement( ElementTags.PARAGRAPH ); 912 writeAddAttribute( ElementTags.ALIGN, ElementTags.ALIGN_CENTER ); 913 914 write( tableCaptionWriter.toString(), true ); 915 916 writeEndElement(); // ElementTags.PARAGRAPH 917 918 tableCaptionWriter = null; 919 } 920 else 921 { 922 writeEndElement(); // ElementTags.TABLE 923 924 writeEndElement(); // ElementTags.CHUNK 925 } 926 actionContext.release(); 927 } 928 929 /** {@inheritDoc} */ 930 public void table() 931 { 932 writeStartElement( ElementTags.CHUNK ); 933 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 934 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 935 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 936 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 937 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 938 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 939 940 writeStartElement( ElementTags.TABLE ); 941 writeAddAttribute( ElementTags.LEFT, Boolean.TRUE.toString() ); 942 writeAddAttribute( ElementTags.RIGHT, Boolean.TRUE.toString() ); 943 writeAddAttribute( ElementTags.TOP, Boolean.TRUE.toString() ); 944 writeAddAttribute( ElementTags.BOTTOM, Boolean.TRUE.toString() ); 945 writeAddAttribute( ElementTags.ALIGN, ElementTags.ALIGN_CENTER ); 946 writeAddAttribute( ElementTags.WIDTH, "100.0%" ); 947 writeAddAttribute( ElementTags.TABLEFITSPAGE, Boolean.TRUE.toString() ); 948 writeAddAttribute( ElementTags.CELLSFITPAGE, Boolean.TRUE.toString() ); 949 writeAddAttribute( ElementTags.CELLPADDING, "10" ); 950 //writeAddAttribute( ElementTags.COLUMNS, "2" ); 951 952 actionContext.setAction( SinkActionContext.TABLE ); 953 } 954 955 /** {@inheritDoc} */ 956 public void tableCaption_() 957 { 958 actionContext.release(); 959 } 960 961 /** {@inheritDoc} */ 962 public void tableCaption() 963 { 964 tableCaptionWriter = new StringWriter(); 965 tableCaptionXMLWriter = new PrettyPrintXMLWriter( tableCaptionWriter ); 966 actionContext.setAction( SinkActionContext.TABLE_CAPTION ); 967 } 968 969 /** {@inheritDoc} */ 970 public void tableCell_() 971 { 972 writeEndElement(); // ElementTags.CELL 973 974 actionContext.release(); 975 } 976 977 /** {@inheritDoc} */ 978 public void tableCell() 979 { 980 writeStartElement( ElementTags.CELL ); 981 writeAddAttribute( ElementTags.LEFT, Boolean.TRUE.toString() ); 982 writeAddAttribute( ElementTags.RIGHT, Boolean.TRUE.toString() ); 983 writeAddAttribute( ElementTags.TOP, Boolean.TRUE.toString() ); 984 writeAddAttribute( ElementTags.BOTTOM, Boolean.TRUE.toString() ); 985 writeAddAttribute( ElementTags.HORIZONTALALIGN, ElementTags.ALIGN_LEFT ); 986 987 actionContext.setAction( SinkActionContext.TABLE_CELL ); 988 } 989 990 /** {@inheritDoc} */ 991 public void tableCell( String width ) 992 { 993 actionContext.setAction( SinkActionContext.TABLE_CELL ); 994 } 995 996 /** {@inheritDoc} */ 997 public void tableHeaderCell_() 998 { 999 writeEndElement(); // ElementTags.CELL 1000 1001 actionContext.release(); 1002 } 1003 1004 /** {@inheritDoc} */ 1005 public void tableHeaderCell() 1006 { 1007 writeStartElement( ElementTags.CELL ); 1008 writeAddAttribute( ElementTags.LEFT, Boolean.TRUE.toString() ); 1009 writeAddAttribute( ElementTags.RIGHT, Boolean.TRUE.toString() ); 1010 writeAddAttribute( ElementTags.TOP, Boolean.TRUE.toString() ); 1011 writeAddAttribute( ElementTags.BOTTOM, Boolean.TRUE.toString() ); 1012 writeAddAttribute( ElementTags.HEADER, Boolean.TRUE.toString() ); 1013 writeAddAttribute( ElementTags.BGRED, Color.GRAY.getRed() ); 1014 writeAddAttribute( ElementTags.BGBLUE, Color.GRAY.getBlue() ); 1015 writeAddAttribute( ElementTags.BGGREEN, Color.GRAY.getGreen() ); 1016 writeAddAttribute( ElementTags.HORIZONTALALIGN, ElementTags.ALIGN_CENTER ); 1017 1018 actionContext.setAction( SinkActionContext.TABLE_HEADER_CELL ); 1019 } 1020 1021 /** {@inheritDoc} */ 1022 public void tableHeaderCell( String width ) 1023 { 1024 actionContext.setAction( SinkActionContext.TABLE_HEADER_CELL ); 1025 } 1026 1027 /** {@inheritDoc} */ 1028 public void tableRow_() 1029 { 1030 writeEndElement(); // ElementTags.ROW 1031 1032 actionContext.release(); 1033 } 1034 1035 /** {@inheritDoc} */ 1036 public void tableRow() 1037 { 1038 writeStartElement( ElementTags.ROW ); 1039 1040 actionContext.setAction( SinkActionContext.TABLE_ROW ); 1041 } 1042 1043 /** {@inheritDoc} */ 1044 public void tableRows_() 1045 { 1046 //writeEndElement(); // ElementTags.TABLE 1047 1048 actionContext.release(); 1049 } 1050 1051 /** {@inheritDoc} */ 1052 public void tableRows( int[] justification, boolean grid ) 1053 { 1054 // ElementTags.TABLE 1055 writeAddAttribute( ElementTags.COLUMNS, justification.length ); 1056 1057 actionContext.setAction( SinkActionContext.TABLE_ROWS ); 1058 } 1059 1060 // ---------------------------------------------------------------------- 1061 // Verbatim 1062 // ---------------------------------------------------------------------- 1063 1064 /** {@inheritDoc} */ 1065 public void verbatim_() 1066 { 1067 writeEndElement(); // ElementTags.CELL 1068 1069 writeEndElement(); // ElementTags.ROW 1070 1071 writeEndElement(); // ElementTags.TABLE 1072 1073 writeEndElement(); // ElementTags.CHUNK 1074 1075 actionContext.release(); 1076 } 1077 1078 /** {@inheritDoc} */ 1079 public void verbatim( boolean boxed ) 1080 { 1081 // Always boxed 1082 writeStartElement( ElementTags.CHUNK ); 1083 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1084 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1085 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1086 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1087 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1088 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1089 1090 writeStartElement( ElementTags.TABLE ); 1091 writeAddAttribute( ElementTags.COLUMNS, "1" ); 1092 writeAddAttribute( ElementTags.LEFT, Boolean.TRUE.toString() ); 1093 writeAddAttribute( ElementTags.RIGHT, Boolean.TRUE.toString() ); 1094 writeAddAttribute( ElementTags.TOP, Boolean.TRUE.toString() ); 1095 writeAddAttribute( ElementTags.BOTTOM, Boolean.TRUE.toString() ); 1096 writeAddAttribute( ElementTags.ALIGN, ElementTags.ALIGN_CENTER ); 1097 writeAddAttribute( ElementTags.TABLEFITSPAGE, Boolean.TRUE.toString() ); 1098 writeAddAttribute( ElementTags.CELLSFITPAGE, Boolean.TRUE.toString() ); 1099 writeAddAttribute( ElementTags.CELLPADDING, "10" ); 1100 writeAddAttribute( ElementTags.WIDTH, "100.0%" ); 1101 1102 writeStartElement( ElementTags.ROW ); 1103 1104 writeStartElement( ElementTags.CELL ); 1105 writeAddAttribute( ElementTags.LEFT, Boolean.TRUE.toString() ); 1106 writeAddAttribute( ElementTags.RIGHT, Boolean.TRUE.toString() ); 1107 writeAddAttribute( ElementTags.TOP, Boolean.TRUE.toString() ); 1108 writeAddAttribute( ElementTags.BOTTOM, Boolean.TRUE.toString() ); 1109 1110 actionContext.setAction( SinkActionContext.VERBATIM ); 1111 } 1112 1113 // ---------------------------------------------------------------------- 1114 // Figures 1115 // ---------------------------------------------------------------------- 1116 1117 /** {@inheritDoc} */ 1118 public void figure_() 1119 { 1120 writeEndElement(); // ElementTags.IMAGE 1121 1122 writeEndElement(); // ElementTags.CHUNK 1123 1124 actionContext.release(); 1125 1126 figureDefined = false; 1127 } 1128 1129 /** {@inheritDoc} */ 1130 public void figure() 1131 { 1132 figureDefined = true; 1133 1134 writeStartElement( ElementTags.CHUNK ); 1135 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1136 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1137 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1138 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1139 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1140 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1141 1142 writeStartElement( ElementTags.IMAGE ); 1143 1144 actionContext.setAction( SinkActionContext.FIGURE ); 1145 } 1146 1147 /** {@inheritDoc} */ 1148 public void figureCaption_() 1149 { 1150 actionContext.release(); 1151 } 1152 1153 /** {@inheritDoc} */ 1154 public void figureCaption() 1155 { 1156 actionContext.setAction( SinkActionContext.FIGURE_CAPTION ); 1157 } 1158 1159 /** 1160 * If the <code>name</code> is a relative link, the internal link will used a System property 1161 * <code>itext.basedir</code>, or the class loader. 1162 * {@inheritDoc} 1163 */ 1164 public void figureGraphics( String name ) 1165 { 1166 String urlName = null; 1167 File nameFile = null; 1168 if ( ( name.toLowerCase( Locale.ENGLISH ).startsWith( "http://" ) ) 1169 || ( name.toLowerCase( Locale.ENGLISH ).startsWith( "https://" ) ) ) 1170 { 1171 urlName = name; 1172 } 1173 else 1174 { 1175 if ( System.getProperty( "itext.basedir" ) != null ) 1176 { 1177 try 1178 { 1179 nameFile = new File( System.getProperty( "itext.basedir" ), name ); 1180 urlName = nameFile.toURI().toURL().toString(); 1181 } 1182 catch ( MalformedURLException e ) 1183 { 1184 getLog().error( "MalformedURLException: " + e.getMessage(), e ); 1185 } 1186 } 1187 else 1188 { 1189 if ( getClassLoader() != null ) 1190 { 1191 if ( getClassLoader().getResource( name ) != null ) 1192 { 1193 urlName = getClassLoader().getResource( name ).toString(); 1194 } 1195 } 1196 else 1197 { 1198 if ( ITextSink.class.getClassLoader().getResource( name ) != null ) 1199 { 1200 urlName = ITextSink.class.getClassLoader().getResource( name ).toString(); 1201 } 1202 } 1203 } 1204 } 1205 1206 if ( urlName == null ) 1207 { 1208 String msg = 1209 "No image '" + name 1210 + "' found in the class loader. Try to call setClassLoader(ClassLoader) before."; 1211 logMessage( "imageNotFound", msg ); 1212 1213 return; 1214 } 1215 1216 if ( nameFile != null && !nameFile.exists() ) 1217 { 1218 String msg = "No image '" + nameFile + "' found in your system, check the path."; 1219 logMessage( "imageNotFound", msg ); 1220 1221 return; 1222 } 1223 1224 boolean figureCalled = figureDefined; 1225 if ( !figureCalled ) 1226 { 1227 figure(); 1228 } 1229 1230 float width = 0; 1231 float height = 0; 1232 try 1233 { 1234 Image image = Image.getInstance( new URL( urlName ) ); 1235 image.scaleToFit( ITextUtil.getDefaultPageSize().width() / 2, ITextUtil.getDefaultPageSize().height() / 2 ); 1236 width = image.plainWidth(); 1237 height = image.plainHeight(); 1238 } 1239 catch ( BadElementException e ) 1240 { 1241 getLog().error( "BadElementException: " + e.getMessage(), e ); 1242 } 1243 catch ( MalformedURLException e ) 1244 { 1245 getLog().error( "MalformedURLException: " + e.getMessage(), e ); 1246 } 1247 catch ( IOException e ) 1248 { 1249 getLog().error( "IOException: " + e.getMessage(), e ); 1250 } 1251 1252 writeAddAttribute( ElementTags.URL, urlName ); 1253 writeAddAttribute( ElementTags.ALIGN, ElementTags.ALIGN_MIDDLE ); 1254 writeAddAttribute( ElementTags.PLAINWIDTH, String.valueOf( width ) ); 1255 writeAddAttribute( ElementTags.PLAINHEIGHT, String.valueOf( height ) ); 1256 1257 actionContext.setAction( SinkActionContext.FIGURE_GRAPHICS ); 1258 1259 if ( !figureCalled ) 1260 { 1261 figure_(); 1262 } 1263 } 1264 1265 // ---------------------------------------------------------------------- 1266 // Fonts 1267 // ---------------------------------------------------------------------- 1268 1269 /** {@inheritDoc} */ 1270 public void bold_() 1271 { 1272 font.removeBold(); 1273 } 1274 1275 /** {@inheritDoc} */ 1276 public void bold() 1277 { 1278 font.addBold(); 1279 } 1280 1281 /** {@inheritDoc} */ 1282 public void italic_() 1283 { 1284 font.removeItalic(); 1285 } 1286 1287 /** {@inheritDoc} */ 1288 public void italic() 1289 { 1290 font.addItalic(); 1291 } 1292 1293 /** {@inheritDoc} */ 1294 public void monospaced_() 1295 { 1296 font.setMonoSpaced( false ); 1297 } 1298 1299 /** {@inheritDoc} */ 1300 public void monospaced() 1301 { 1302 font.setMonoSpaced( true ); 1303 } 1304 1305 // ---------------------------------------------------------------------- 1306 // Links 1307 // ---------------------------------------------------------------------- 1308 1309 /** {@inheritDoc} */ 1310 public void link_() 1311 { 1312 writeEndElement(); // ElementTags.ANCHOR 1313 1314 font.setColor( Color.BLACK ); 1315 font.removeUnderlined(); 1316 1317 actionContext.release(); 1318 } 1319 1320 /** {@inheritDoc} */ 1321 public void link( String name ) 1322 { 1323 if ( name == null ) 1324 { 1325 throw new NullPointerException( "Link name cannot be null!" ); 1326 } 1327 1328 font.setColor( Color.BLUE ); 1329 font.addUnderlined(); 1330 1331 writeStartElement( ElementTags.ANCHOR ); 1332 if ( StringUtils.isNotEmpty( name ) && name.startsWith( "#" ) && StringUtils.isNotEmpty( header.getTitle() ) ) 1333 { 1334 name = "#" + DoxiaUtils.encodeId( header.getTitle(), true ) + "_" + name.substring( 1 ); 1335 } 1336 writeAddAttribute( ElementTags.REFERENCE, HtmlTools.escapeHTML( name ) ); 1337 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1338 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1339 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1340 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1341 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1342 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1343 1344 actionContext.setAction( SinkActionContext.LINK ); 1345 } 1346 1347 /** {@inheritDoc} */ 1348 public void anchor_() 1349 { 1350 if ( !anchorDefined ) 1351 { 1352 // itext needs a defined local destination, we put an invisible text 1353 writeAddAttribute( ElementTags.BLUE, "255" ); 1354 writeAddAttribute( ElementTags.GREEN, "255" ); 1355 writeAddAttribute( ElementTags.RED, "255" ); 1356 1357 write( "_" ); 1358 } 1359 1360 anchorDefined = false; 1361 1362 writeEndElement(); // ElementTags.ANCHOR 1363 1364 actionContext.release(); 1365 } 1366 1367 /** {@inheritDoc} */ 1368 public void anchor( String name ) 1369 { 1370 if ( name == null ) 1371 { 1372 throw new NullPointerException( "Anchor name cannot be null!" ); 1373 } 1374 1375 if ( StringUtils.isNotEmpty( header.getTitle() ) ) 1376 { 1377 name = header.getTitle() + "_" + name; 1378 } 1379 String id = name; 1380 1381 if ( !DoxiaUtils.isValidId( id ) ) 1382 { 1383 id = DoxiaUtils.encodeId( name, true ); 1384 1385 String msg = "Modified invalid link: '" + name + "' to '" + id + "'"; 1386 logMessage( "modifiedLink", msg ); 1387 } 1388 1389 writeStartElement( ElementTags.ANCHOR ); 1390 writeAddAttribute( ElementTags.NAME, id ); 1391 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1392 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1393 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1394 1395 actionContext.setAction( SinkActionContext.ANCHOR ); 1396 } 1397 1398 // ---------------------------------------------------------------------- 1399 // Misc 1400 // ---------------------------------------------------------------------- 1401 1402 /** {@inheritDoc} */ 1403 public void lineBreak() 1404 { 1405 // Special case for the header 1406 if ( ( actionContext.getCurrentAction() == SinkActionContext.AUTHOR ) 1407 || ( actionContext.getCurrentAction() == SinkActionContext.DATE ) 1408 || ( actionContext.getCurrentAction() == SinkActionContext.TITLE ) ) 1409 { 1410 return; 1411 } 1412 1413 writeStartElement( ElementTags.NEWLINE ); 1414 writeEndElement(); 1415 } 1416 1417 /** {@inheritDoc} */ 1418 public void nonBreakingSpace() 1419 { 1420 write( " " ); 1421 } 1422 1423 /** {@inheritDoc} */ 1424 public void pageBreak() 1425 { 1426 writeStartElement( ElementTags.NEWPAGE ); 1427 writeEndElement(); 1428 } 1429 1430 /** {@inheritDoc} */ 1431 public void horizontalRule() 1432 { 1433 writeStartElement( ElementTags.PARAGRAPH ); 1434 writeAddAttribute( ElementTags.BLUE, "255" ); 1435 writeAddAttribute( ElementTags.GREEN, "255" ); 1436 writeAddAttribute( ElementTags.RED, "255" ); 1437 write( "_" ); 1438 writeEndElement(); 1439 1440 writeStartElement( ElementTags.PARAGRAPH ); 1441 writeStartElement( ElementTags.HORIZONTALRULE ); 1442 writeEndElement(); 1443 writeEndElement(); 1444 } 1445 1446 // ---------------------------------------------------------------------- 1447 // Text 1448 // ---------------------------------------------------------------------- 1449 1450 /** {@inheritDoc} */ 1451 public void rawText( String text ) 1452 { 1453 writeStartElement( ElementTags.CHUNK ); 1454 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1455 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1456 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1457 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1458 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1459 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1460 1461 write( text, false ); 1462 1463 writeEndElement(); // ElementTags.CHUNK 1464 } 1465 1466 /** {@inheritDoc} */ 1467 public void text( String text ) 1468 { 1469 if ( StringUtils.isEmpty( text ) ) 1470 { 1471 return; 1472 } 1473 1474 switch ( actionContext.getCurrentAction() ) 1475 { 1476 case SinkActionContext.AUTHOR: 1477 header.addAuthor( text ); 1478 break; 1479 1480 case SinkActionContext.DATE: 1481 header.setDate( text ); 1482 break; 1483 1484 case SinkActionContext.TITLE: 1485 header.setTitle( text ); 1486 break; 1487 1488 case SinkActionContext.TABLE_CAPTION: 1489 this.tableCaptionXMLWriter.writeText( text ); 1490 break; 1491 1492 case SinkActionContext.VERBATIM: 1493 // Used to preserve indentation and formating 1494 LineNumberReader lnr = new LineNumberReader( new StringReader( text ) ); 1495 String line; 1496 try 1497 { 1498 while ( ( line = lnr.readLine() ) != null ) 1499 { 1500 writeStartElement( ElementTags.CHUNK ); 1501 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1502 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1503 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1504 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1505 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1506 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1507 1508 write( "<![CDATA[", true ); 1509 // Special case 1510 line = StringUtils.replace( line, "<![CDATA[", "< ![CDATA[" ); 1511 line = StringUtils.replace( line, "]]>", "]] >" ); 1512 write( line, true, false ); 1513 write( "]]>", true ); 1514 1515 writeEndElement(); 1516 lineBreak(); 1517 } 1518 } 1519 catch ( IOException e ) 1520 { 1521 throw new RuntimeException( "IOException: ", e ); 1522 } 1523 break; 1524 1525 case SinkActionContext.FIGURE_CAPTION: 1526 writeAddAttribute( ElementTags.ALT, text ); 1527 break; 1528 1529 case SinkActionContext.SECTION_TITLE: 1530 case SinkActionContext.SECTION_1: 1531 case SinkActionContext.SECTION_2: 1532 case SinkActionContext.SECTION_3: 1533 case SinkActionContext.SECTION_4: 1534 case SinkActionContext.SECTION_5: 1535 case SinkActionContext.FIGURE: 1536 case SinkActionContext.FIGURE_GRAPHICS: 1537 case SinkActionContext.TABLE_ROW: 1538 case SinkActionContext.TABLE: 1539 case SinkActionContext.HEAD: 1540 case SinkActionContext.UNDEFINED: 1541 break; 1542 1543 case SinkActionContext.ANCHOR: 1544 anchorDefined = true; 1545 case SinkActionContext.PARAGRAPH: 1546 case SinkActionContext.LINK: 1547 case SinkActionContext.TABLE_CELL: 1548 case SinkActionContext.TABLE_HEADER_CELL: 1549 case SinkActionContext.DEFINITION: 1550 case SinkActionContext.DEFINED_TERM: 1551 case SinkActionContext.NUMBERED_LIST_ITEM: 1552 case SinkActionContext.LIST_ITEM: 1553 case SinkActionContext.SECTION_TITLE_5: 1554 case SinkActionContext.SECTION_TITLE_4: 1555 case SinkActionContext.SECTION_TITLE_3: 1556 case SinkActionContext.SECTION_TITLE_2: 1557 case SinkActionContext.SECTION_TITLE_1: 1558 default: 1559 writeStartElement( ElementTags.CHUNK ); 1560 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1561 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1562 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1563 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1564 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1565 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1566 1567 write( text ); 1568 1569 writeEndElement(); // ElementTags.CHUNK 1570 } 1571 } 1572 1573 /** 1574 * {@inheritDoc} 1575 * 1576 * Unkown events just log a warning message but are ignored otherwise. 1577 * @see org.apache.maven.doxia.sink.Sink#unknown(String,Object[],SinkEventAttributes) 1578 */ 1579 public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes ) 1580 { 1581 String msg = "Unknown Sink event: '" + name + "', ignoring!"; 1582 logMessage( "unknownEvent", msg ); 1583 } 1584 1585 /** {@inheritDoc} */ 1586 protected void init() 1587 { 1588 super.init(); 1589 1590 this.actionContext = new SinkActionContext(); 1591 this.font = new ITextFont(); 1592 this.header = new ITextHeader(); 1593 1594 this.numberDepth = 1; 1595 this.depth = 0; 1596 this.tableCaptionWriter = null; 1597 this.tableCaptionXMLWriter = null; 1598 this.anchorDefined = false; 1599 this.figureDefined = false; 1600 this.warnMessages = null; 1601 } 1602 1603 /** 1604 * Convenience method to write a starting element. 1605 * 1606 * @param tag the name of the tag 1607 */ 1608 private void writeStartElement( String tag ) 1609 { 1610 if ( tableCaptionXMLWriter == null ) 1611 { 1612 xmlWriter.startElement( tag ); 1613 } 1614 else 1615 { 1616 tableCaptionXMLWriter.startElement( tag ); 1617 } 1618 } 1619 1620 /** 1621 * Convenience method to write a key-value pair. 1622 * 1623 * @param key the name of an attribute 1624 * @param value the value of an attribute 1625 */ 1626 private void writeAddAttribute( String key, String value ) 1627 { 1628 if ( tableCaptionXMLWriter == null ) 1629 { 1630 xmlWriter.addAttribute( key, value ); 1631 } 1632 else 1633 { 1634 tableCaptionXMLWriter.addAttribute( key, value ); 1635 } 1636 } 1637 1638 /** 1639 * Convenience method to write a key-value pair. 1640 * 1641 * @param key the name of an attribute 1642 * @param value the value of an attribute 1643 */ 1644 private void writeAddAttribute( String key, int value ) 1645 { 1646 if ( tableCaptionXMLWriter == null ) 1647 { 1648 xmlWriter.addAttribute( key, String.valueOf( value ) ); 1649 } 1650 else 1651 { 1652 tableCaptionXMLWriter.addAttribute( key, String.valueOf( value ) ); 1653 } 1654 } 1655 1656 /** 1657 * Convenience method to write an end element. 1658 */ 1659 private void writeEndElement() 1660 { 1661 if ( tableCaptionXMLWriter == null ) 1662 { 1663 xmlWriter.endElement(); 1664 } 1665 else 1666 { 1667 tableCaptionXMLWriter.endElement(); 1668 } 1669 } 1670 1671 /** 1672 * Convenience method to write a String 1673 * 1674 * @param aString 1675 */ 1676 protected void write( String aString ) 1677 { 1678 write( aString, false ); 1679 } 1680 1681 /** 1682 * Convenience method to write a String depending the escapeHtml flag 1683 * 1684 * @param aString 1685 * @param escapeHtml 1686 */ 1687 private void write( String aString, boolean escapeHtml ) 1688 { 1689 write( aString, escapeHtml, true ); 1690 } 1691 1692 /** 1693 * Convenience method to write a String depending the escapeHtml flag 1694 * 1695 * @param aString 1696 * @param escapeHtml 1697 * @param trim 1698 */ 1699 private void write( String aString, boolean escapeHtml, boolean trim ) 1700 { 1701 if ( aString == null ) 1702 { 1703 return; 1704 } 1705 1706 if ( trim ) 1707 { 1708 aString = StringUtils.replace( aString, "\n", "" ); 1709 1710 LineNumberReader lnr = new LineNumberReader( new StringReader( aString ) ); 1711 StringBuilder sb = new StringBuilder(); 1712 String line; 1713 try 1714 { 1715 while ( ( line = lnr.readLine() ) != null ) 1716 { 1717 sb.append( beautifyPhrase( line.trim() ) ); 1718 sb.append( " " ); 1719 } 1720 1721 aString = sb.toString(); 1722 } 1723 catch ( IOException e ) 1724 { 1725 // nop 1726 } 1727 if ( aString.trim().length() == 0 ) 1728 { 1729 return; 1730 } 1731 } 1732 if ( escapeHtml ) 1733 { 1734 if ( tableCaptionXMLWriter == null ) 1735 { 1736 xmlWriter.writeMarkup( aString ); 1737 } 1738 else 1739 { 1740 tableCaptionXMLWriter.writeMarkup( aString ); 1741 } 1742 } 1743 else 1744 { 1745 if ( tableCaptionXMLWriter == null ) 1746 { 1747 xmlWriter.writeText( aString ); 1748 } 1749 else 1750 { 1751 tableCaptionXMLWriter.writeText( aString ); 1752 } 1753 } 1754 } 1755 1756 /** 1757 * Convenience method to return a beautify phrase, i.e. one space between words. 1758 * 1759 * @param aString 1760 * @return a String with only one space between words 1761 */ 1762 private static String beautifyPhrase( String aString ) 1763 { 1764 String[] strings = StringUtils.split( aString, " " ); 1765 StringBuilder sb = new StringBuilder(); 1766 for ( int i = 0; i < strings.length; i++ ) 1767 { 1768 if ( strings[i].trim().length() != 0 ) 1769 { 1770 sb.append( strings[i].trim() ); 1771 sb.append( " " ); 1772 } 1773 } 1774 1775 return sb.toString().trim(); 1776 } 1777 1778 private void startChunk( String fontName, int fontSize, String fontStyle, int fontColorBlue, int fontColorGreen, 1779 int fontColorRed, String localDestination ) 1780 { 1781 writeStartElement( ElementTags.CHUNK ); 1782 writeAddAttribute( ElementTags.FONT, fontName ); 1783 writeAddAttribute( ElementTags.SIZE, fontSize ); 1784 writeAddAttribute( ElementTags.STYLE, fontStyle ); 1785 writeAddAttribute( ElementTags.BLUE, fontColorBlue ); 1786 writeAddAttribute( ElementTags.GREEN, fontColorGreen ); 1787 writeAddAttribute( ElementTags.RED, fontColorRed ); 1788// writeAddAttribute( ElementTags.LOCALDESTINATION, localDestination ); 1789 } 1790 1791 /** 1792 * If debug mode is enabled, log the <code>msg</code> as is, otherwise add unique msg in <code>warnMessages</code>. 1793 * 1794 * @param key not null 1795 * @param msg not null 1796 * @see #close() 1797 * @since 1.1.1 1798 */ 1799 private void logMessage( String key, String msg ) 1800 { 1801 msg = "[iText Sink] " + msg; 1802 if ( getLog().isDebugEnabled() ) 1803 { 1804 getLog().debug( msg ); 1805 1806 return; 1807 } 1808 1809 if ( warnMessages == null ) 1810 { 1811 warnMessages = new HashMap<String, Set<String>>(); 1812 } 1813 1814 Set<String> set = warnMessages.get( key ); 1815 if ( set == null ) 1816 { 1817 set = new TreeSet<String>(); 1818 } 1819 set.add( msg ); 1820 warnMessages.put( key, set ); 1821 } 1822}