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.AbstractXmlSink; 042import org.apache.maven.doxia.sink.Sink; 043import org.apache.maven.doxia.sink.SinkEventAttributes; 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: ITextSink.html 905940 2014-04-12 16:27:29Z hboutemy $ 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 <code>itext.basedir</code>, 1161 * or the class loader. 1162 * {@inheritDoc} */ 1163 public void figureGraphics( String name ) 1164 { 1165 String urlName = null; 1166 File nameFile = null; 1167 if ( ( name.toLowerCase( Locale.ENGLISH ).startsWith( "http://" ) ) 1168 || ( name.toLowerCase( Locale.ENGLISH ).startsWith( "https://" ) ) ) 1169 { 1170 urlName = name; 1171 } 1172 else 1173 { 1174 if ( System.getProperty( "itext.basedir" ) != null ) 1175 { 1176 try 1177 { 1178 nameFile = new File( System.getProperty( "itext.basedir" ), name ); 1179 urlName = nameFile.toURI().toURL().toString(); 1180 } 1181 catch ( MalformedURLException e ) 1182 { 1183 getLog().error( "MalformedURLException: " + e.getMessage(), e ); 1184 } 1185 } 1186 else 1187 { 1188 if ( getClassLoader() != null ) 1189 { 1190 if ( getClassLoader().getResource( name ) != null ) 1191 { 1192 urlName = getClassLoader().getResource( name ).toString(); 1193 } 1194 } 1195 else 1196 { 1197 if ( ITextSink.class.getClassLoader().getResource( name ) != null ) 1198 { 1199 urlName = ITextSink.class.getClassLoader().getResource( name ).toString(); 1200 } 1201 } 1202 } 1203 } 1204 1205 if ( urlName == null ) 1206 { 1207 String msg = 1208 "No image '" + name 1209 + "' found in the class loader. Try to call setClassLoader(ClassLoader) before."; 1210 logMessage( "imageNotFound", msg ); 1211 1212 return; 1213 } 1214 1215 if ( nameFile != null && !nameFile.exists() ) 1216 { 1217 String msg = "No image '" + nameFile + "' found in your system, check the path."; 1218 logMessage( "imageNotFound", msg ); 1219 1220 return; 1221 } 1222 1223 boolean figureCalled = figureDefined; 1224 if ( !figureCalled ) 1225 { 1226 figure(); 1227 } 1228 1229 float width = 0; 1230 float height = 0; 1231 try 1232 { 1233 Image image = Image.getInstance( new URL( urlName ) ); 1234 image.scaleToFit( ITextUtil.getDefaultPageSize().width() / 2, ITextUtil.getDefaultPageSize().height() / 2 ); 1235 width = image.plainWidth(); 1236 height = image.plainHeight(); 1237 } 1238 catch ( BadElementException e ) 1239 { 1240 getLog().error( "BadElementException: " + e.getMessage(), e ); 1241 } 1242 catch ( MalformedURLException e ) 1243 { 1244 getLog().error( "MalformedURLException: " + e.getMessage(), e ); 1245 } 1246 catch ( IOException e ) 1247 { 1248 getLog().error( "IOException: " + e.getMessage(), e ); 1249 } 1250 1251 writeAddAttribute( ElementTags.URL, urlName ); 1252 writeAddAttribute( ElementTags.ALIGN, ElementTags.ALIGN_MIDDLE ); 1253 writeAddAttribute( ElementTags.PLAINWIDTH, String.valueOf( width ) ); 1254 writeAddAttribute( ElementTags.PLAINHEIGHT, String.valueOf( height ) ); 1255 1256 actionContext.setAction( SinkActionContext.FIGURE_GRAPHICS ); 1257 1258 if ( !figureCalled ) 1259 { 1260 figure_(); 1261 } 1262 } 1263 1264 // ---------------------------------------------------------------------- 1265 // Fonts 1266 // ---------------------------------------------------------------------- 1267 1268 /** {@inheritDoc} */ 1269 public void bold_() 1270 { 1271 font.removeBold(); 1272 } 1273 1274 /** {@inheritDoc} */ 1275 public void bold() 1276 { 1277 font.addBold(); 1278 } 1279 1280 /** {@inheritDoc} */ 1281 public void italic_() 1282 { 1283 font.removeItalic(); 1284 } 1285 1286 /** {@inheritDoc} */ 1287 public void italic() 1288 { 1289 font.addItalic(); 1290 } 1291 1292 /** {@inheritDoc} */ 1293 public void monospaced_() 1294 { 1295 font.setMonoSpaced( false ); 1296 } 1297 1298 /** {@inheritDoc} */ 1299 public void monospaced() 1300 { 1301 font.setMonoSpaced( true ); 1302 } 1303 1304 // ---------------------------------------------------------------------- 1305 // Links 1306 // ---------------------------------------------------------------------- 1307 1308 /** {@inheritDoc} */ 1309 public void link_() 1310 { 1311 writeEndElement(); // ElementTags.ANCHOR 1312 1313 font.setColor( Color.BLACK ); 1314 font.removeUnderlined(); 1315 1316 actionContext.release(); 1317 } 1318 1319 /** {@inheritDoc} */ 1320 public void link( String name ) 1321 { 1322 if ( name == null ) 1323 { 1324 throw new NullPointerException( "Link name cannot be null!" ); 1325 } 1326 1327 font.setColor( Color.BLUE ); 1328 font.addUnderlined(); 1329 1330 writeStartElement( ElementTags.ANCHOR ); 1331 if ( StringUtils.isNotEmpty( name )&& name.startsWith( "#" ) && StringUtils.isNotEmpty( header.getTitle() )) 1332 { 1333 name = "#" + DoxiaUtils.encodeId( header.getTitle(), true ) + "_" + name.substring( 1 ); 1334 } 1335 writeAddAttribute( ElementTags.REFERENCE, HtmlTools.escapeHTML( name ) ); 1336 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1337 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1338 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1339 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1340 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1341 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1342 1343 actionContext.setAction( SinkActionContext.LINK ); 1344 } 1345 1346 /** {@inheritDoc} */ 1347 public void anchor_() 1348 { 1349 if ( !anchorDefined ) 1350 { 1351 // itext needs a defined local destination, we put an invisible text 1352 writeAddAttribute( ElementTags.BLUE, "255" ); 1353 writeAddAttribute( ElementTags.GREEN, "255" ); 1354 writeAddAttribute( ElementTags.RED, "255" ); 1355 1356 write( "_" ); 1357 } 1358 1359 anchorDefined = false; 1360 1361 writeEndElement(); // ElementTags.ANCHOR 1362 1363 actionContext.release(); 1364 } 1365 1366 /** {@inheritDoc} */ 1367 public void anchor( String name ) 1368 { 1369 if ( name == null ) 1370 { 1371 throw new NullPointerException( "Anchor name cannot be null!" ); 1372 } 1373 1374 if ( StringUtils.isNotEmpty( header.getTitle() ) ) 1375 { 1376 name = header.getTitle() + "_" + name; 1377 } 1378 String id = name; 1379 1380 if ( !DoxiaUtils.isValidId( id ) ) 1381 { 1382 id = DoxiaUtils.encodeId( name, true ); 1383 1384 String msg = "Modified invalid link: '" + name + "' to '" + id + "'"; 1385 logMessage( "modifiedLink", msg ); 1386 } 1387 1388 writeStartElement( ElementTags.ANCHOR ); 1389 writeAddAttribute( ElementTags.NAME, id ); 1390 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1391 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1392 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1393 1394 actionContext.setAction( SinkActionContext.ANCHOR ); 1395 } 1396 1397 // ---------------------------------------------------------------------- 1398 // Misc 1399 // ---------------------------------------------------------------------- 1400 1401 /** {@inheritDoc} */ 1402 public void lineBreak() 1403 { 1404 // Special case for the header 1405 if ( ( actionContext.getCurrentAction() == SinkActionContext.AUTHOR ) 1406 || ( actionContext.getCurrentAction() == SinkActionContext.DATE ) 1407 || ( actionContext.getCurrentAction() == SinkActionContext.TITLE ) ) 1408 { 1409 return; 1410 } 1411 1412 writeStartElement( ElementTags.NEWLINE ); 1413 writeEndElement(); 1414 } 1415 1416 /** {@inheritDoc} */ 1417 public void nonBreakingSpace() 1418 { 1419 write( " " ); 1420 } 1421 1422 /** {@inheritDoc} */ 1423 public void pageBreak() 1424 { 1425 writeStartElement( ElementTags.NEWPAGE ); 1426 writeEndElement(); 1427 } 1428 1429 /** {@inheritDoc} */ 1430 public void horizontalRule() 1431 { 1432 writeStartElement( ElementTags.PARAGRAPH ); 1433 writeAddAttribute( ElementTags.BLUE, "255" ); 1434 writeAddAttribute( ElementTags.GREEN, "255" ); 1435 writeAddAttribute( ElementTags.RED, "255" ); 1436 write( "_" ); 1437 writeEndElement(); 1438 1439 writeStartElement( ElementTags.PARAGRAPH ); 1440 writeStartElement( ElementTags.HORIZONTALRULE ); 1441 writeEndElement(); 1442 writeEndElement(); 1443 } 1444 1445 // ---------------------------------------------------------------------- 1446 // Text 1447 // ---------------------------------------------------------------------- 1448 1449 /** {@inheritDoc} */ 1450 public void rawText( String text ) 1451 { 1452 writeStartElement( ElementTags.CHUNK ); 1453 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1454 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1455 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1456 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1457 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1458 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1459 1460 write( text, false ); 1461 1462 writeEndElement(); // ElementTags.CHUNK 1463 } 1464 1465 /** {@inheritDoc} */ 1466 public void text( String text ) 1467 { 1468 if ( StringUtils.isEmpty( text ) ) 1469 { 1470 return; 1471 } 1472 1473 switch ( actionContext.getCurrentAction() ) 1474 { 1475 case SinkActionContext.AUTHOR: 1476 header.addAuthor( text ); 1477 break; 1478 1479 case SinkActionContext.DATE: 1480 header.setDate( text ); 1481 break; 1482 1483 case SinkActionContext.TITLE: 1484 header.setTitle( text ); 1485 break; 1486 1487 case SinkActionContext.TABLE_CAPTION: 1488 this.tableCaptionXMLWriter.writeText( text ); 1489 break; 1490 1491 case SinkActionContext.VERBATIM: 1492 // Used to preserve indentation and formating 1493 LineNumberReader lnr = new LineNumberReader( new StringReader( text ) ); 1494 String line; 1495 try 1496 { 1497 while ( ( line = lnr.readLine() ) != null ) 1498 { 1499 writeStartElement( ElementTags.CHUNK ); 1500 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1501 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1502 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1503 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1504 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1505 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1506 1507 write( "<![CDATA[", true ); 1508 // Special case 1509 line = StringUtils.replace( line, "<![CDATA[", "< ![CDATA[" ); 1510 line = StringUtils.replace( line, "]]>", "]] >" ); 1511 write( line, true, false ); 1512 write( "]]>", true ); 1513 1514 writeEndElement(); 1515 lineBreak(); 1516 } 1517 } 1518 catch ( IOException e ) 1519 { 1520 throw new RuntimeException( "IOException: ", e ); 1521 } 1522 break; 1523 1524 case SinkActionContext.FIGURE_CAPTION: 1525 writeAddAttribute( ElementTags.ALT, text ); 1526 break; 1527 1528 case SinkActionContext.SECTION_TITLE: 1529 case SinkActionContext.SECTION_1: 1530 case SinkActionContext.SECTION_2: 1531 case SinkActionContext.SECTION_3: 1532 case SinkActionContext.SECTION_4: 1533 case SinkActionContext.SECTION_5: 1534 case SinkActionContext.FIGURE: 1535 case SinkActionContext.FIGURE_GRAPHICS: 1536 case SinkActionContext.TABLE_ROW: 1537 case SinkActionContext.TABLE: 1538 case SinkActionContext.HEAD: 1539 case SinkActionContext.UNDEFINED: 1540 break; 1541 1542 case SinkActionContext.ANCHOR: 1543 anchorDefined = true; 1544 case SinkActionContext.PARAGRAPH: 1545 case SinkActionContext.LINK: 1546 case SinkActionContext.TABLE_CELL: 1547 case SinkActionContext.TABLE_HEADER_CELL: 1548 case SinkActionContext.DEFINITION: 1549 case SinkActionContext.DEFINED_TERM: 1550 case SinkActionContext.NUMBERED_LIST_ITEM: 1551 case SinkActionContext.LIST_ITEM: 1552 case SinkActionContext.SECTION_TITLE_5: 1553 case SinkActionContext.SECTION_TITLE_4: 1554 case SinkActionContext.SECTION_TITLE_3: 1555 case SinkActionContext.SECTION_TITLE_2: 1556 case SinkActionContext.SECTION_TITLE_1: 1557 default: 1558 writeStartElement( ElementTags.CHUNK ); 1559 writeAddAttribute( ElementTags.FONT, font.getFontName() ); 1560 writeAddAttribute( ElementTags.SIZE, font.getFontSize() ); 1561 writeAddAttribute( ElementTags.STYLE, font.getFontStyle() ); 1562 writeAddAttribute( ElementTags.BLUE, font.getFontColorBlue() ); 1563 writeAddAttribute( ElementTags.GREEN, font.getFontColorGreen() ); 1564 writeAddAttribute( ElementTags.RED, font.getFontColorRed() ); 1565 1566 write( text ); 1567 1568 writeEndElement(); // ElementTags.CHUNK 1569 } 1570 } 1571 1572 /** 1573 * {@inheritDoc} 1574 * 1575 * Unkown events just log a warning message but are ignored otherwise. 1576 * @see org.apache.maven.doxia.sink.Sink#unknown(String,Object[],SinkEventAttributes) 1577 */ 1578 public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes ) 1579 { 1580 String msg = "Unknown Sink event: '" + name + "', ignoring!"; 1581 logMessage( "unknownEvent", msg ); 1582 } 1583 1584 /** {@inheritDoc} */ 1585 protected void init() 1586 { 1587 super.init(); 1588 1589 this.actionContext = new SinkActionContext(); 1590 this.font = new ITextFont(); 1591 this.header = new ITextHeader(); 1592 1593 this.numberDepth = 1; 1594 this.depth = 0; 1595 this.tableCaptionWriter = null; 1596 this.tableCaptionXMLWriter = null; 1597 this.anchorDefined = false; 1598 this.figureDefined = false; 1599 this.warnMessages = null; 1600 } 1601 1602 /** 1603 * Convenience method to write a starting element. 1604 * 1605 * @param tag the name of the tag 1606 */ 1607 private void writeStartElement( String tag ) 1608 { 1609 if ( tableCaptionXMLWriter == null ) 1610 { 1611 xmlWriter.startElement( tag ); 1612 } 1613 else 1614 { 1615 tableCaptionXMLWriter.startElement( tag ); 1616 } 1617 } 1618 1619 /** 1620 * Convenience method to write a key-value pair. 1621 * 1622 * @param key the name of an attribute 1623 * @param value the value of an attribute 1624 */ 1625 private void writeAddAttribute( String key, String value ) 1626 { 1627 if ( tableCaptionXMLWriter == null ) 1628 { 1629 xmlWriter.addAttribute( key, value ); 1630 } 1631 else 1632 { 1633 tableCaptionXMLWriter.addAttribute( key, value ); 1634 } 1635 } 1636 1637 /** 1638 * Convenience method to write a key-value pair. 1639 * 1640 * @param key the name of an attribute 1641 * @param value the value of an attribute 1642 */ 1643 private void writeAddAttribute( String key, int value ) 1644 { 1645 if ( tableCaptionXMLWriter == null ) 1646 { 1647 xmlWriter.addAttribute( key, String.valueOf( value ) ); 1648 } 1649 else 1650 { 1651 tableCaptionXMLWriter.addAttribute( key, String.valueOf( value ) ); 1652 } 1653 } 1654 1655 /** 1656 * Convenience method to write an end element. 1657 */ 1658 private void writeEndElement() 1659 { 1660 if ( tableCaptionXMLWriter == null ) 1661 { 1662 xmlWriter.endElement(); 1663 } 1664 else 1665 { 1666 tableCaptionXMLWriter.endElement(); 1667 } 1668 } 1669 1670 /** 1671 * Convenience method to write a String 1672 * 1673 * @param aString 1674 */ 1675 protected void write( String aString ) 1676 { 1677 write( aString, false ); 1678 } 1679 1680 /** 1681 * Convenience method to write a String depending the escapeHtml flag 1682 * 1683 * @param aString 1684 * @param escapeHtml 1685 */ 1686 private void write( String aString, boolean escapeHtml ) 1687 { 1688 write( aString, escapeHtml, true ); 1689 } 1690 1691 /** 1692 * Convenience method to write a String depending the escapeHtml flag 1693 * 1694 * @param aString 1695 * @param escapeHtml 1696 * @param trim 1697 */ 1698 private void write( String aString, boolean escapeHtml, boolean trim ) 1699 { 1700 if ( aString == null ) 1701 { 1702 return; 1703 } 1704 1705 if ( trim ) 1706 { 1707 aString = StringUtils.replace( aString, "\n", "" ); 1708 1709 LineNumberReader lnr = new LineNumberReader( new StringReader( aString ) ); 1710 StringBuilder sb = new StringBuilder(); 1711 String line; 1712 try 1713 { 1714 while ( ( line = lnr.readLine() ) != null ) 1715 { 1716 sb.append( beautifyPhrase( line.trim() ) ); 1717 sb.append( " " ); 1718 } 1719 1720 aString = sb.toString(); 1721 } 1722 catch ( IOException e ) 1723 { 1724 // nop 1725 } 1726 if ( aString.trim().length() == 0 ) 1727 { 1728 return; 1729 } 1730 } 1731 if ( escapeHtml ) 1732 { 1733 if ( tableCaptionXMLWriter == null ) 1734 { 1735 xmlWriter.writeMarkup( aString ); 1736 } 1737 else 1738 { 1739 tableCaptionXMLWriter.writeMarkup( aString ); 1740 } 1741 } 1742 else 1743 { 1744 if ( tableCaptionXMLWriter == null ) 1745 { 1746 xmlWriter.writeText( aString ); 1747 } 1748 else 1749 { 1750 tableCaptionXMLWriter.writeText( aString ); 1751 } 1752 } 1753 } 1754 1755 /** 1756 * Convenience method to return a beautify phrase, i.e. one space between words. 1757 * 1758 * @param aString 1759 * @return a String with only one space between words 1760 */ 1761 private static String beautifyPhrase( String aString ) 1762 { 1763 String[] strings = StringUtils.split( aString, " " ); 1764 StringBuilder sb = new StringBuilder(); 1765 for ( int i = 0; i < strings.length; i++ ) 1766 { 1767 if ( strings[i].trim().length() != 0 ) 1768 { 1769 sb.append( strings[i].trim() ); 1770 sb.append( " " ); 1771 } 1772 } 1773 1774 return sb.toString().trim(); 1775 } 1776 1777 private void startChunk( String fontName, int fontSize, String fontStyle, int fontColorBlue, int fontColorGreen, 1778 int fontColorRed, String localDestination ) 1779 { 1780 writeStartElement( ElementTags.CHUNK ); 1781 writeAddAttribute( ElementTags.FONT, fontName ); 1782 writeAddAttribute( ElementTags.SIZE, fontSize ); 1783 writeAddAttribute( ElementTags.STYLE, fontStyle ); 1784 writeAddAttribute( ElementTags.BLUE, fontColorBlue ); 1785 writeAddAttribute( ElementTags.GREEN, fontColorGreen ); 1786 writeAddAttribute( ElementTags.RED, fontColorRed ); 1787// writeAddAttribute( ElementTags.LOCALDESTINATION, localDestination ); 1788 } 1789 1790 /** 1791 * If debug mode is enabled, log the <code>msg</code> as is, otherwise add unique msg in <code>warnMessages</code>. 1792 * 1793 * @param key not null 1794 * @param msg not null 1795 * @see #close() 1796 * @since 1.1.1 1797 */ 1798 private void logMessage( String key, String msg ) 1799 { 1800 msg = "[iText Sink] " + msg; 1801 if ( getLog().isDebugEnabled() ) 1802 { 1803 getLog().debug( msg ); 1804 1805 return; 1806 } 1807 1808 if ( warnMessages == null ) 1809 { 1810 warnMessages = new HashMap<String, Set<String>>(); 1811 } 1812 1813 Set<String> set = warnMessages.get( key ); 1814 if ( set == null ) 1815 { 1816 set = new TreeSet<String>(); 1817 } 1818 set.add( msg ); 1819 warnMessages.put( key, set ); 1820 } 1821}