001package org.apache.maven.doxia.module.latex; 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 org.apache.maven.doxia.sink.AbstractTextSink; 023import org.apache.maven.doxia.sink.Sink; 024import org.apache.maven.doxia.sink.SinkEventAttributes; 025import org.apache.maven.doxia.sink.SinkEventAttributeSet; 026import org.apache.maven.doxia.util.DoxiaUtils; 027import org.apache.maven.doxia.util.LineBreaker; 028 029import org.codehaus.plexus.util.IOUtil; 030import org.codehaus.plexus.util.StringUtils; 031 032import java.io.IOException; 033import java.io.InputStream; 034import java.io.Writer; 035import java.util.Locale; 036 037/** 038 * Latex Sink implementation. 039 * <br/> 040 * <b>Note</b>: The encoding used is UTF-8. 041 * 042 * @version $Id: LatexSink.html 905940 2014-04-12 16:27:29Z hboutemy $ 043 * @since 1.0 044 */ 045public class LatexSink 046 extends AbstractTextSink 047{ 048 /** 049 * Flag that indicates if the document to be written is only a fragment. 050 * 051 * This implies that <code>\\begin{document}</code>, <code>\\title{..}</code> will not be output. 052 */ 053 private final boolean fragmentDocument; 054 055 private boolean ignoreText; 056 057 private final LineBreaker out; 058 059 private final String sinkCommands; 060 061 private final String preamble; 062 063 private boolean titleFlag; 064 065 private int numberedListNesting; 066 067 private boolean verbatimFlag; 068 069 private boolean figureFlag; 070 071 private boolean tableFlag; 072 073 private boolean gridFlag; 074 075 private int[] cellJustif; 076 077 private int cellCount; 078 079 private boolean isTitle; 080 081 private String title; 082 083 // ---------------------------------------------------------------------- 084 // 085 // ---------------------------------------------------------------------- 086 087 /** 088 * Constructor, initialize the Writer and the variables. 089 * 090 * @param out not null writer to write the result. <b>Should</b> be an UTF-8 Writer. 091 * You could use <code>newWriter</code> methods from {@link org.codehaus.plexus.util.WriterFactory}. 092 */ 093 protected LatexSink( Writer out ) 094 { 095 this( out, null, null ); 096 } 097 098 /** 099 * Constructor, initialize the Writer and the variables. 100 * 101 * @param out not null writer to write the result. <b>Should</b> be an UTF-8 Writer. 102 * You could use <code>newWriter</code> methods from {@link org.codehaus.plexus.util.WriterFactory}. 103 * @param sinkCommands A String representation of commands that go before \documentclass. 104 * @param preamble A String representation of commands that go between \documentclass and \begin{document}. 105 */ 106 protected LatexSink( Writer out, String sinkCommands, String preamble ) 107 { 108 this( out, sinkCommands, preamble, false ); 109 } 110 111 /** 112 * Constructor, initialize the Writer and the variables. 113 * 114 * @param out not null writer to write the result. <b>Should</b> be an UTF-8 Writer. 115 * You could use <code>newWriter</code> methods from {@link org.codehaus.plexus.util.WriterFactory}. 116 * @param sinkCommands A String representation of commands that go before \documentclass. 117 * @param preamble A String representation of commands that go between \documentclass and \begin{document}. 118 * @param fragmentDocument If this receives events that that are only part of a document. 119 * Typically, headers are omitted if this is true. 120 */ 121 protected LatexSink( Writer out, String sinkCommands, String preamble, boolean fragmentDocument ) 122 { 123 this.out = new LineBreaker( out ); 124 125 if ( sinkCommands == null ) 126 { 127 sinkCommands = defaultSinkCommands(); 128 } 129 if ( preamble == null ) 130 { 131 preamble = defaultPreamble(); 132 } 133 134 this.sinkCommands = sinkCommands; 135 this.preamble = preamble; 136 this.fragmentDocument = fragmentDocument; 137 138 init(); 139 } 140 141 // ---------------------------------------------------------------------- 142 // Overridables 143 // ---------------------------------------------------------------------- 144 145 /** 146 * Returns a default \documentclass declaration. 147 * 148 * @return String. 149 */ 150 protected String getDocumentStart() 151 { 152 return "\\documentclass[a4paper]{article}" + EOL + EOL; 153 } 154 155 /** 156 * Returns a default \begin{document} declaration. 157 * 158 * @return String. 159 */ 160 protected String getDocumentBegin() 161 { 162 return "\\begin{document}" + EOL + EOL; 163 } 164 165 /** 166 * Returns a default \end{document} declaration. 167 * 168 * @return String. 169 */ 170 protected String getDocumentEnd() 171 { 172 return "\\end{document}" + EOL; 173 } 174 175 // ---------------------------------------------------------------------- 176 // Sink Implementation 177 // ---------------------------------------------------------------------- 178 179 /** 180 * {@inheritDoc} 181 */ 182 public void head() 183 { 184 head( null ); 185 } 186 187 /** {@inheritDoc} */ 188 public void head( SinkEventAttributes attributes ) 189 { 190 init(); 191 192 if ( !fragmentDocument ) 193 { 194 markup( sinkCommands ); 195 196 markup( getDocumentStart() ); 197 198 markup( preamble ); 199 200 markup( getDocumentBegin() ); 201 } 202 } 203 204 /** 205 * {@inheritDoc} 206 */ 207 public void body() 208 { 209 body( null ); 210 } 211 212 /** {@inheritDoc} */ 213 public void body( SinkEventAttributes attributes ) 214 { 215 if ( titleFlag ) 216 { 217 if ( fragmentDocument ) 218 { 219 markup( "\\section" ); 220 } 221 else 222 { 223 titleFlag = false; 224 markup( "\\maketitle" + EOL + EOL ); 225 } 226 } 227 } 228 229 /** 230 * {@inheritDoc} 231 */ 232 public void body_() 233 { 234 if ( !fragmentDocument ) 235 { 236 markup( getDocumentEnd() ); 237 } 238 239 flush(); 240 } 241 242 /** 243 * {@inheritDoc} 244 */ 245 public void title() 246 { 247 title( null ); 248 } 249 250 /** {@inheritDoc} */ 251 public void title( SinkEventAttributes attributes ) 252 { 253 if ( !fragmentDocument ) 254 { 255 titleFlag = true; 256 markup( "\\title{" ); 257 } 258 else 259 { 260 ignoreText = true; 261 } 262 } 263 264 /** 265 * {@inheritDoc} 266 */ 267 public void title_() 268 { 269 if ( !fragmentDocument ) 270 { 271 markup( "}" + EOL ); 272 } 273 else 274 { 275 ignoreText = false; 276 } 277 } 278 279 /** 280 * {@inheritDoc} 281 */ 282 public void author() 283 { 284 author( null ); 285 } 286 287 /** {@inheritDoc} */ 288 public void author( SinkEventAttributes attributes ) 289 { 290 if ( !fragmentDocument ) 291 { 292 markup( "\\author{" ); 293 } 294 else 295 { 296 ignoreText = true; 297 } 298 } 299 300 /** 301 * {@inheritDoc} 302 */ 303 public void author_() 304 { 305 if ( !fragmentDocument ) 306 { 307 markup( "}" + EOL ); 308 } 309 else 310 { 311 ignoreText = false; 312 } 313 } 314 315 /** 316 * {@inheritDoc} 317 */ 318 public void date() 319 { 320 date( null ); 321 } 322 323 /** {@inheritDoc} */ 324 public void date( SinkEventAttributes attributes ) 325 { 326 if ( !fragmentDocument ) 327 { 328 markup( "\\date{" ); 329 } 330 else 331 { 332 ignoreText = true; 333 } 334 } 335 336 /** 337 * {@inheritDoc} 338 */ 339 public void date_() 340 { 341 if ( !fragmentDocument ) 342 { 343 markup( "}" + EOL ); 344 } 345 else 346 { 347 ignoreText = false; 348 } 349 } 350 351 /** {@inheritDoc} */ 352 public void sectionTitle( int level, SinkEventAttributes attributes ) 353 { 354 isTitle = true; 355 } 356 357 /** {@inheritDoc} */ 358 public void sectionTitle_( int level ) 359 { 360 String command = ""; 361 switch ( level ) 362 { 363 case SECTION_LEVEL_1: 364 command = "section"; 365 break; 366 case SECTION_LEVEL_2: 367 command = "subsection"; 368 break; 369 case SECTION_LEVEL_3: 370 command = "subsubsection"; 371 break; 372 case SECTION_LEVEL_4: 373 command = "paragraph"; 374 break; 375 case SECTION_LEVEL_5: 376 command = "subparagraph"; 377 break; 378 default: 379 throw new IllegalArgumentException( "Not a section level: " + level ); 380 } 381 382 isTitle = false; 383 384 if ( StringUtils.isNotEmpty( title ) ) 385 { 386 markup( EOL + "\\" + command + "{" + title + "}" + EOL ); 387 388 title = null; 389 } 390 } 391 392 // ---------------------------------------------------------------------- 393 // Section Title 1 394 // ---------------------------------------------------------------------- 395 396 /** 397 * {@inheritDoc} 398 */ 399 public void sectionTitle1() 400 { 401 sectionTitle( SECTION_LEVEL_1, null ); 402 } 403 404 /** 405 * {@inheritDoc} 406 */ 407 public void sectionTitle1_() 408 { 409 sectionTitle_( SECTION_LEVEL_1 ); 410 } 411 412 // ---------------------------------------------------------------------- 413 // Section Title 2 414 // ---------------------------------------------------------------------- 415 416 /** 417 * {@inheritDoc} 418 */ 419 public void sectionTitle2() 420 { 421 sectionTitle( SECTION_LEVEL_2, null ); 422 } 423 424 /** 425 * {@inheritDoc} 426 */ 427 public void sectionTitle2_() 428 { 429 sectionTitle_( SECTION_LEVEL_2 ); 430 } 431 432 // ---------------------------------------------------------------------- 433 // Section Title 3 434 // ---------------------------------------------------------------------- 435 436 /** 437 * {@inheritDoc} 438 */ 439 public void sectionTitle3() 440 { 441 sectionTitle( SECTION_LEVEL_3, null ); 442 } 443 444 /** 445 * {@inheritDoc} 446 */ 447 public void sectionTitle3_() 448 { 449 sectionTitle_( SECTION_LEVEL_3 ); 450 } 451 452 // ---------------------------------------------------------------------- 453 // Section Title 4 454 // ---------------------------------------------------------------------- 455 456 /** 457 * {@inheritDoc} 458 */ 459 public void sectionTitle4() 460 { 461 sectionTitle( SECTION_LEVEL_4, null ); 462 } 463 464 /** 465 * {@inheritDoc} 466 */ 467 public void sectionTitle4_() 468 { 469 sectionTitle_( SECTION_LEVEL_4 ); 470 } 471 472 // ---------------------------------------------------------------------- 473 // Section Title 5 474 // ---------------------------------------------------------------------- 475 476 /** 477 * {@inheritDoc} 478 */ 479 public void sectionTitle5() 480 { 481 sectionTitle( SECTION_LEVEL_5, null ); 482 } 483 484 /** 485 * {@inheritDoc} 486 */ 487 public void sectionTitle5_() 488 { 489 sectionTitle_( SECTION_LEVEL_5 ); 490 } 491 492 // ---------------------------------------------------------------------- 493 // List 494 // ---------------------------------------------------------------------- 495 496 /** 497 * {@inheritDoc} 498 */ 499 public void list() 500 { 501 list( null ); 502 } 503 504 /** {@inheritDoc} */ 505 public void list( SinkEventAttributes attributes ) 506 { 507 markup( EOL + "\\begin{itemize}" ); 508 } 509 510 /** 511 * {@inheritDoc} 512 */ 513 public void list_() 514 { 515 markup( EOL + "\\end{itemize}" + EOL ); 516 } 517 518 /** 519 * {@inheritDoc} 520 */ 521 public void listItem() 522 { 523 listItem( null ); 524 } 525 526 /** {@inheritDoc} */ 527 public void listItem( SinkEventAttributes attributes ) 528 { 529 markup( EOL + "\\item " ); 530 } 531 532 /** 533 * {@inheritDoc} 534 */ 535 public void numberedList( int numbering ) 536 { 537 numberedList( numbering, null ); 538 } 539 540 /** {@inheritDoc} */ 541 public void numberedList( int numbering, SinkEventAttributes attributes ) 542 { 543 ++numberedListNesting; 544 545 String counter; 546 switch ( numberedListNesting ) 547 { 548 case 1: 549 counter = "enumi"; 550 break; 551 case 2: 552 counter = "enumii"; 553 break; 554 case 3: 555 counter = "enumiii"; 556 break; 557 case 4: 558 default: 559 counter = "enumiv"; 560 } 561 562 String style; 563 switch ( numbering ) 564 { 565 case NUMBERING_UPPER_ALPHA: 566 style = "Alph"; 567 break; 568 case NUMBERING_LOWER_ALPHA: 569 style = "alph"; 570 break; 571 case NUMBERING_UPPER_ROMAN: 572 style = "Roman"; 573 break; 574 case NUMBERING_LOWER_ROMAN: 575 style = "roman"; 576 break; 577 case NUMBERING_DECIMAL: 578 default: 579 style = "arabic"; 580 } 581 582 markup( EOL + "\\begin{enumerate}" + EOL ); 583 markup( "\\renewcommand{\\the" + counter + "}{\\" + style + "{" + counter + "}}" + EOL ); 584 } 585 586 /** 587 * {@inheritDoc} 588 */ 589 public void numberedList_() 590 { 591 markup( EOL + "\\end{enumerate}" + EOL ); 592 --numberedListNesting; 593 } 594 595 /** 596 * {@inheritDoc} 597 */ 598 public void numberedListItem() 599 { 600 numberedListItem( null ); 601 } 602 603 /** {@inheritDoc} */ 604 public void numberedListItem( SinkEventAttributes attributes ) 605 { 606 markup( "\\item " ); 607 } 608 609 /** 610 * {@inheritDoc} 611 */ 612 public void definitionList() 613 { 614 definitionList( null ); 615 } 616 617 /** {@inheritDoc} */ 618 public void definitionList( SinkEventAttributes attributes ) 619 { 620 markup( EOL + "\\begin{description}" ); 621 } 622 623 /** 624 * {@inheritDoc} 625 */ 626 public void definitionList_() 627 { 628 markup( EOL + "\\end{description}" + EOL ); 629 } 630 631 /** 632 * {@inheritDoc} 633 */ 634 public void definedTerm() 635 { 636 definedTerm( null ); 637 } 638 639 /** {@inheritDoc} */ 640 public void definedTerm( SinkEventAttributes attributes ) 641 { 642 markup( EOL + "\\item[\\mbox{" ); 643 } 644 645 /** 646 * {@inheritDoc} 647 */ 648 public void definedTerm_() 649 { 650 markup( "}] " ); 651 } 652 653 /** {@inheritDoc} */ 654 public void definitionListItem() 655 { 656 definitionListItem( null ); 657 } 658 659 /** {@inheritDoc} */ 660 public void definitionListItem( SinkEventAttributes attributes ) 661 { 662 // nop 663 } 664 665 /** {@inheritDoc} */ 666 public void definitionListItem_() 667 { 668 // nop 669 } 670 671 /** {@inheritDoc} */ 672 public void definition() 673 { 674 definition( null ); 675 } 676 677 /** {@inheritDoc} */ 678 public void definition( SinkEventAttributes attributes ) 679 { 680 // nop 681 } 682 683 /** {@inheritDoc} */ 684 public void definition_() 685 { 686 // nop 687 } 688 689 // ---------------------------------------------------------------------- 690 // Figure 691 // ---------------------------------------------------------------------- 692 693 /** 694 * {@inheritDoc} 695 */ 696 public void figure() 697 { 698 figure( null ); 699 } 700 701 /** {@inheritDoc} */ 702 public void figure( SinkEventAttributes attributes ) 703 { 704 figureFlag = true; 705 markup( EOL + "\\begin{figure}[htb]" + EOL ); 706 } 707 708 /** 709 * {@inheritDoc} 710 */ 711 public void figure_() 712 { 713 markup( "\\end{figure}" + EOL ); 714 figureFlag = false; 715 } 716 717 /** 718 * {@inheritDoc} 719 */ 720 public void figureGraphics( String name ) 721 { 722 figureGraphics( name, null ); 723 } 724 725 /** {@inheritDoc} */ 726 public void figureGraphics( String src, SinkEventAttributes attributes ) 727 { 728 if ( !src.toLowerCase( Locale.ENGLISH ).endsWith( ".eps" ) ) 729 { 730 getLog().warn( "[Latex Sink] Found non-eps figure graphics!" ); 731 } 732 733 markup( "\\begin{center}" + EOL ); 734 markup( "\\includegraphics{" + src + "}" + EOL ); 735 markup( "\\end{center}" + EOL ); 736 } 737 738 /** 739 * {@inheritDoc} 740 */ 741 public void figureCaption() 742 { 743 figureCaption( null ); 744 } 745 746 /** {@inheritDoc} */ 747 public void figureCaption( SinkEventAttributes attributes ) 748 { 749 markup( "\\caption{" ); 750 } 751 752 /** 753 * {@inheritDoc} 754 */ 755 public void figureCaption_() 756 { 757 markup( "}" + EOL ); 758 } 759 760 // ---------------------------------------------------------------------- 761 // Table 762 // ---------------------------------------------------------------------- 763 764 /** 765 * {@inheritDoc} 766 */ 767 public void table() 768 { 769 table( null ); 770 } 771 772 /** {@inheritDoc} */ 773 public void table( SinkEventAttributes attributes ) 774 { 775 tableFlag = true; 776 markup( EOL + "\\begin{table}[htp]" + EOL ); 777 } 778 779 /** 780 * {@inheritDoc} 781 */ 782 public void table_() 783 { 784 markup( "\\end{table}" + EOL ); 785 tableFlag = false; 786 } 787 788 /** 789 * {@inheritDoc} 790 */ 791 public void tableRows( int[] justification, boolean grid ) 792 793 { 794 StringBuilder justif = new StringBuilder(); 795 for ( int i = 0; i < justification.length; ++i ) 796 { 797 if ( grid ) 798 { 799 justif.append( '|' ); 800 } 801 switch ( justification[i] ) 802 { 803 case Sink.JUSTIFY_CENTER: 804 justif.append( 'c' ); 805 break; 806 case Sink.JUSTIFY_LEFT: 807 justif.append( 'l' ); 808 break; 809 case Sink.JUSTIFY_RIGHT: 810 justif.append( 'r' ); 811 break; 812 default: 813 break; 814 } 815 } 816 if ( grid ) 817 { 818 justif.append( '|' ); 819 } 820 821 markup( "\\begin{center}" + EOL ); 822 markup( "\\begin{tabular}{" + justif.toString() + "}" + EOL ); 823 if ( grid ) 824 { 825 markup( "\\hline" + EOL ); 826 } 827 gridFlag = grid; 828 cellJustif = justification; 829 } 830 831 /** 832 * {@inheritDoc} 833 */ 834 public void tableRows_() 835 { 836 markup( "\\end{tabular}" + EOL ); 837 markup( "\\end{center}" + EOL ); 838 839 gridFlag = false; 840 cellJustif = null; 841 } 842 843 /** 844 * {@inheritDoc} 845 */ 846 public void tableRow() 847 { 848 tableRow( null ); 849 } 850 851 /** {@inheritDoc} */ 852 public void tableRow( SinkEventAttributes attributes ) 853 { 854 cellCount = 0; 855 } 856 857 /** 858 * {@inheritDoc} 859 */ 860 public void tableRow_() 861 { 862 markup( "\\\\" + EOL ); 863 if ( gridFlag || lastCellWasHeader ) 864 { 865 markup( "\\hline" + EOL ); 866 } 867 cellCount = 0; 868 lastCellWasHeader = false; 869 } 870 871 /** 872 * {@inheritDoc} 873 */ 874 public void tableCell() 875 { 876 tableCell( (SinkEventAttributes) null ); 877 } 878 879 /** {@inheritDoc} */ 880 public void tableCell( String width ) 881 { 882 SinkEventAttributeSet att = new SinkEventAttributeSet(); 883 att.addAttribute( javax.swing.text.html.HTML.Attribute.WIDTH, width ); 884 885 tableCell( att ); 886 } 887 888 /** {@inheritDoc} */ 889 public void tableCell( SinkEventAttributes attributes ) 890 { 891 tableCell( false ); 892 } 893 894 /** 895 * {@inheritDoc} 896 */ 897 public void tableCell_() 898 { 899 markup( "\\end{tabular}" ); 900 ++cellCount; 901 } 902 903 /** 904 * {@inheritDoc} 905 */ 906 public void tableHeaderCell() 907 { 908 tableCell( (SinkEventAttributes) null ); 909 } 910 911 /** {@inheritDoc} */ 912 public void tableHeaderCell( String width ) 913 { 914 SinkEventAttributeSet att = new SinkEventAttributeSet(); 915 att.addAttribute( javax.swing.text.html.HTML.Attribute.WIDTH, width ); 916 917 tableHeaderCell( att ); 918 } 919 920 /** {@inheritDoc} */ 921 public void tableHeaderCell( SinkEventAttributes attributes ) 922 { 923 tableCell( true ); 924 } 925 926 /** 927 * {@inheritDoc} 928 */ 929 public void tableHeaderCell_() 930 { 931 tableCell_(); 932 } 933 934 private boolean lastCellWasHeader = false; 935 936 /** 937 * Starts a table cell. 938 * 939 * @param header True if this is a header cell. 940 */ 941 private void tableCell( boolean header ) 942 { 943 lastCellWasHeader = header; 944 945 if ( cellCount > 0 ) 946 { 947 markup( " &" + EOL ); 948 } 949 950 char justif; 951 switch ( cellJustif[cellCount] ) 952 { 953 case Sink.JUSTIFY_LEFT: 954 justif = 'l'; 955 break; 956 case Sink.JUSTIFY_RIGHT: 957 justif = 'r'; 958 break; 959 case Sink.JUSTIFY_CENTER: 960 default: 961 justif = 'c'; 962 break; 963 } 964 markup( "\\begin{tabular}[t]{" + justif + "}" ); 965 } 966 967 /** 968 * {@inheritDoc} 969 */ 970 public void tableCaption() 971 { 972 tableCaption( null ); 973 } 974 975 /** {@inheritDoc} */ 976 public void tableCaption( SinkEventAttributes attributes ) 977 { 978 markup( "\\caption{" ); 979 } 980 981 /** 982 * {@inheritDoc} 983 */ 984 public void tableCaption_() 985 { 986 markup( "}" + EOL ); 987 } 988 989 /** 990 * {@inheritDoc} 991 */ 992 public void paragraph() 993 { 994 paragraph( null ); 995 } 996 997 /** {@inheritDoc} */ 998 public void paragraph( SinkEventAttributes attributes ) 999 { 1000 markup( EOL + EOL ); 1001 } 1002 1003 /** 1004 * {@inheritDoc} 1005 */ 1006 public void paragraph_() 1007 { 1008 markup( EOL ); 1009 } 1010 1011 /** 1012 * {@inheritDoc} 1013 */ 1014 public void verbatim( boolean boxed ) 1015 { 1016 verbatim( boxed ? SinkEventAttributeSet.BOXED : null ); 1017 } 1018 1019 /** {@inheritDoc} */ 1020 public void verbatim( SinkEventAttributes attributes ) 1021 { 1022 boolean boxed = false; 1023 1024 if ( attributes != null && attributes.isDefined( SinkEventAttributes.DECORATION ) ) 1025 { 1026 boxed = "boxed".equals( 1027 attributes.getAttribute( SinkEventAttributes.DECORATION ) ); 1028 } 1029 1030 markup( EOL + "\\begin{small}" + EOL ); 1031 1032 if ( boxed ) 1033 { 1034 markup( "\\begin{Verbatim}[frame=single]" + EOL ); 1035 } 1036 else 1037 { 1038 markup( "\\begin{Verbatim}" + EOL ); 1039 } 1040 1041 verbatimFlag = true; 1042 } 1043 1044 /** 1045 * {@inheritDoc} 1046 */ 1047 public void verbatim_() 1048 { 1049 markup( EOL + "\\end{Verbatim}" + EOL ); 1050 markup( "\\end{small}" + EOL ); 1051 1052 verbatimFlag = false; 1053 } 1054 1055 /** 1056 * {@inheritDoc} 1057 */ 1058 public void horizontalRule() 1059 { 1060 horizontalRule( null ); 1061 } 1062 1063 /** {@inheritDoc} */ 1064 public void horizontalRule( SinkEventAttributes attributes ) 1065 { 1066 markup( EOL + "\\begin{center}\\rule[0.5ex]{\\linewidth}{1pt}\\end{center}" + EOL ); 1067 } 1068 1069 /** 1070 * {@inheritDoc} 1071 */ 1072 public void pageBreak() 1073 { 1074 markup( EOL + "\\newpage" + EOL ); 1075 } 1076 1077 /** 1078 * {@inheritDoc} 1079 */ 1080 public void anchor( String name ) 1081 { 1082 anchor( name, null ); 1083 } 1084 1085 /** {@inheritDoc} */ 1086 public void anchor( String name, SinkEventAttributes attributes ) 1087 { 1088 markup( "\\hypertarget{" + name + "}{" ); 1089 } 1090 1091 /** 1092 * {@inheritDoc} 1093 */ 1094 public void anchor_() 1095 { 1096 markup( "}" ); 1097 } 1098 1099 /** 1100 * {@inheritDoc} 1101 */ 1102 public void link( String name ) 1103 { 1104 link( name, null ); 1105 } 1106 1107 /** {@inheritDoc} */ 1108 public void link( String name, SinkEventAttributes attributes ) 1109 { 1110 // TODO: use \\url for simple links 1111 if ( DoxiaUtils.isExternalLink( name ) ) 1112 { 1113 markup( "\\href{" + name + "}{" ); 1114 } 1115 else 1116 { 1117 markup( "\\hyperlink{" + name + "}{" ); 1118 } 1119 } 1120 1121 /** 1122 * {@inheritDoc} 1123 */ 1124 public void link_() 1125 { 1126 markup( "}" ); 1127 } 1128 1129 /** 1130 * {@inheritDoc} 1131 */ 1132 public void italic() 1133 { 1134 markup( "\\textit{" ); 1135 } 1136 1137 /** 1138 * {@inheritDoc} 1139 */ 1140 public void italic_() 1141 { 1142 markup( "}" ); 1143 } 1144 1145 /** 1146 * {@inheritDoc} 1147 */ 1148 public void bold() 1149 { 1150 markup( "\\textbf{" ); 1151 } 1152 1153 /** 1154 * {@inheritDoc} 1155 */ 1156 public void bold_() 1157 { 1158 markup( "}" ); 1159 } 1160 1161 /** 1162 * {@inheritDoc} 1163 */ 1164 public void monospaced() 1165 { 1166 markup( "\\texttt{\\small " ); 1167 } 1168 1169 /** 1170 * {@inheritDoc} 1171 */ 1172 public void monospaced_() 1173 { 1174 markup( "}" ); 1175 } 1176 1177 /** 1178 * {@inheritDoc} 1179 */ 1180 public void lineBreak() 1181 { 1182 lineBreak( null ); 1183 } 1184 1185 /** {@inheritDoc} */ 1186 public void lineBreak( SinkEventAttributes attributes ) 1187 { 1188 markup( ( figureFlag || tableFlag || titleFlag || verbatimFlag ) ? EOL : "\\newline" + EOL ); 1189 } 1190 1191 /** 1192 * {@inheritDoc} 1193 */ 1194 public void nonBreakingSpace() 1195 { 1196 markup( "~" ); 1197 } 1198 1199 /** 1200 * {@inheritDoc} 1201 */ 1202 public void text( String text ) 1203 { 1204 text( text, null ); 1205 } 1206 1207 /** {@inheritDoc} */ 1208 public void text( String text, SinkEventAttributes attributes ) 1209 { 1210 if ( ignoreText ) 1211 { 1212 return; 1213 } 1214 if ( isTitle ) 1215 { 1216 title = text; 1217 } 1218 else if ( verbatimFlag ) 1219 { 1220 verbatimContent( text ); 1221 } 1222 else 1223 { 1224 content( text ); 1225 } 1226 } 1227 1228 /** {@inheritDoc} */ 1229 public void rawText( String text ) 1230 { 1231 verbatimContent( text ); 1232 } 1233 1234 /** {@inheritDoc} */ 1235 public void comment( String comment ) 1236 { 1237 rawText( EOL + "% " + comment ); 1238 } 1239 1240 /** 1241 * {@inheritDoc} 1242 * 1243 * Unkown events just log a warning message but are ignored otherwise. 1244 * @see org.apache.maven.doxia.sink.Sink#unknown(String,Object[],SinkEventAttributes) 1245 */ 1246 public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes ) 1247 { 1248 getLog().warn( "[Latex Sink] Unknown Sink event: '" + name + "', ignoring!" ); 1249 } 1250 1251 // ----------------------------------------------------------------------- 1252 1253 /** 1254 * Writes the text, preserving whitespace. 1255 * 1256 * @param text the text to write. 1257 */ 1258 protected void markup( String text ) 1259 { 1260 if ( text != null ) 1261 { 1262 out.write( text, /*preserveSpace*/ true ); 1263 } 1264 } 1265 1266 /** 1267 * Writes the text, without preserving whitespace. 1268 * 1269 * @param text the text to write. 1270 */ 1271 protected void content( String text ) 1272 { 1273 out.write( escaped( text ), /*preserveSpace*/ false ); 1274 } 1275 1276 /** 1277 * Writes the text, preserving whitespace. 1278 * 1279 * @param text the text to write. 1280 */ 1281 protected void verbatimContent( String text ) 1282 { 1283 out.write( text, /*preserveSpace*/ true ); 1284 } 1285 1286 // ----------------------------------------------------------------------- 1287 1288 /** 1289 * Escapes special characters. 1290 * 1291 * @param text The text to escape. 1292 * @return The text with special characters replaced. 1293 */ 1294 public static String escaped( String text ) 1295 { 1296 int length = text.length(); 1297 StringBuilder buffer = new StringBuilder( length ); 1298 1299 for ( int i = 0; i < length; ++i ) 1300 { 1301 char c = text.charAt( i ); 1302 switch ( c ) 1303 { 1304 case '-': 1305 case '<': 1306 case '>': 1307 buffer.append( "\\symbol{" ).append( (int) c ).append( "}" ); 1308 break; 1309 case '~': 1310 buffer.append( "\\textasciitilde " ); 1311 break; 1312 case '^': 1313 buffer.append( "\\textasciicircum " ); 1314 break; 1315 case '|': 1316 buffer.append( "\\textbar " ); 1317 break; 1318 case '\\': 1319 buffer.append( "\\textbackslash " ); 1320 break; 1321 case '$': 1322 buffer.append( "\\$" ); 1323 break; 1324 case '&': 1325 buffer.append( "\\&" ); 1326 break; 1327 case '%': 1328 buffer.append( "\\%" ); 1329 break; 1330 case '#': 1331 buffer.append( "\\#" ); 1332 break; 1333 case '{': 1334 buffer.append( "\\{" ); 1335 break; 1336 case '}': 1337 buffer.append( "\\}" ); 1338 break; 1339 case '_': 1340 buffer.append( "\\_" ); 1341 break; 1342 default: 1343 buffer.append( c ); 1344 } 1345 } 1346 1347 return buffer.toString(); 1348 } 1349 1350 // ---------------------------------------------------------------------- 1351 // 1352 // ---------------------------------------------------------------------- 1353 1354 /** 1355 * {@inheritDoc} 1356 */ 1357 public void flush() 1358 { 1359 out.flush(); 1360 } 1361 1362 /** 1363 * {@inheritDoc} 1364 */ 1365 public void close() 1366 { 1367 out.close(); 1368 1369 init(); 1370 } 1371 1372 // ---------------------------------------------------------------------- 1373 // 1374 // ---------------------------------------------------------------------- 1375 1376 /** 1377 * Returns the default sink commands from a resource. 1378 * 1379 * @throws java.io.IOException if the resource file cannot be read. 1380 * @return InputStream 1381 */ 1382 private static InputStream getDefaultSinkCommands() 1383 throws IOException 1384 { 1385 return LatexSink.class.getResource( "default_sink_commands.tex" ).openStream(); 1386 } 1387 1388 /** 1389 * Returns the default preamble from a resource. 1390 * 1391 * @return InputStream 1392 * @throws java.io.IOException if the resource file cannot be read. 1393 */ 1394 private static InputStream getDefaultPreamble() 1395 throws IOException 1396 { 1397 return LatexSink.class.getResource( "default_preamble.tex" ).openStream(); 1398 } 1399 1400 /** 1401 * Returns the default sink commands. 1402 * 1403 * @return String. 1404 */ 1405 protected String defaultSinkCommands() 1406 { 1407 try 1408 { 1409 return IOUtil.toString( getDefaultSinkCommands() ); 1410 } 1411 catch ( IOException ioe ) 1412 { 1413 // this should not happen 1414 getLog().warn( "Could not read default LaTeX commands, the generated LaTeX file will not compile!" ); 1415 getLog().debug( ioe ); 1416 1417 return ""; 1418 } 1419 } 1420 1421 /** 1422 * Returns the default preamble. 1423 * 1424 * @return String. 1425 */ 1426 protected String defaultPreamble() 1427 { 1428 try 1429 { 1430 return IOUtil.toString( getDefaultPreamble() ); 1431 } 1432 catch ( IOException ioe ) 1433 { 1434 // this should not happen 1435 getLog().warn( "Could not read default LaTeX preamble, the generated LaTeX file will not compile!" ); 1436 getLog().debug( ioe ); 1437 1438 return ""; 1439 } 1440 } 1441 1442 /** {@inheritDoc} */ 1443 protected void init() 1444 { 1445 super.init(); 1446 1447 this.ignoreText = false; 1448 this.titleFlag = false; 1449 this.numberedListNesting = 0; 1450 this.verbatimFlag = false; 1451 this.figureFlag = false; 1452 this.tableFlag = false; 1453 this.gridFlag = false; 1454 this.cellJustif = null; 1455 this.cellCount = 0; 1456 this.isTitle = false; 1457 this.title = null; 1458 } 1459}