Coverage Report - org.apache.maven.doxia.module.latex.LatexSink
 
Classes in this File Line Coverage Branch Coverage Complexity
LatexSink
87%
367/418
63%
70/110
1,615
 
 1  
 package org.apache.maven.doxia.module.latex;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.maven.doxia.sink.AbstractTextSink;
 23  
 import org.apache.maven.doxia.sink.Sink;
 24  
 import org.apache.maven.doxia.sink.SinkEventAttributes;
 25  
 import org.apache.maven.doxia.sink.SinkEventAttributeSet;
 26  
 import org.apache.maven.doxia.util.DoxiaUtils;
 27  
 import org.apache.maven.doxia.util.LineBreaker;
 28  
 
 29  
 import org.codehaus.plexus.util.IOUtil;
 30  
 import org.codehaus.plexus.util.StringUtils;
 31  
 
 32  
 import java.io.IOException;
 33  
 import java.io.InputStream;
 34  
 import java.io.Writer;
 35  
 import java.util.Locale;
 36  
 
 37  
 /**
 38  
  * Latex Sink implementation.
 39  
  * <br/>
 40  
  * <b>Note</b>: The encoding used is UTF-8.
 41  
  *
 42  
  * @version $Id: LatexSink.java 807174 2009-08-24 12:15:08Z vsiveton $
 43  
  * @since 1.0
 44  
  */
 45  
 public class LatexSink
 46  
     extends AbstractTextSink
 47  
 {
 48  
     /**
 49  
      * Flag that indicates if the document to be written is only a fragment.
 50  
      *
 51  
      * This implies that <code>\\begin{document}</code>, <code>\\title{..}</code> will not be output.
 52  
      */
 53  
     private final boolean fragmentDocument;
 54  
 
 55  
     private boolean ignoreText;
 56  
 
 57  
     private final LineBreaker out;
 58  
 
 59  
     private final String sinkCommands;
 60  
 
 61  
     private final String preamble;
 62  
 
 63  
     private boolean titleFlag;
 64  
 
 65  
     private int numberedListNesting;
 66  
 
 67  
     private boolean verbatimFlag;
 68  
 
 69  
     private boolean figureFlag;
 70  
 
 71  
     private boolean tableFlag;
 72  
 
 73  
     private boolean gridFlag;
 74  
 
 75  
     private int[] cellJustif;
 76  
 
 77  
     private int cellCount;
 78  
 
 79  
     private boolean isTitle;
 80  
 
 81  
     private String title;
 82  
 
 83  
     // ----------------------------------------------------------------------
 84  
     //
 85  
     // ----------------------------------------------------------------------
 86  
 
 87  
     /**
 88  
      * Constructor, initialize the Writer and the variables.
 89  
      *
 90  
      * @param out not null writer to write the result. <b>Should</b> be an UTF-8 Writer.
 91  
      * You could use <code>newWriter</code> methods from {@link org.codehaus.plexus.util.WriterFactory}.
 92  
      */
 93  
     protected LatexSink( Writer out )
 94  
     {
 95  64
         this( out, null, null );
 96  64
     }
 97  
 
 98  
     /**
 99  
      * 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  64
         this( out, sinkCommands, preamble, false );
 109  64
     }
 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  64
     {
 123  64
         this.out = new LineBreaker( out );
 124  
 
 125  64
         if ( sinkCommands == null )
 126  
         {
 127  64
             sinkCommands = defaultSinkCommands();
 128  
         }
 129  64
         if ( preamble == null )
 130  
         {
 131  64
             preamble = defaultPreamble();
 132  
         }
 133  
 
 134  64
         this.sinkCommands = sinkCommands;
 135  64
         this.preamble = preamble;
 136  64
         this.fragmentDocument = fragmentDocument;
 137  
 
 138  64
         init();
 139  64
     }
 140  
 
 141  
     // ----------------------------------------------------------------------
 142  
     // Overridables
 143  
     // ----------------------------------------------------------------------
 144  
 
 145  
     /**
 146  
      * Returns a default \documentclass declaration.
 147  
      *
 148  
      * @return String.
 149  
      */
 150  
     protected String getDocumentStart()
 151  
     {
 152  4
         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  4
         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  4
         return "\\end{document}" + EOL;
 173  
     }
 174  
 
 175  
     // ----------------------------------------------------------------------
 176  
     // Sink Implementation
 177  
     // ----------------------------------------------------------------------
 178  
 
 179  
     /**
 180  
      * {@inheritDoc}
 181  
      */
 182  
     public void head()
 183  
     {
 184  4
         head( null );
 185  4
     }
 186  
 
 187  
     /** {@inheritDoc} */
 188  
     public void head( SinkEventAttributes attributes )
 189  
     {
 190  4
         init();
 191  
 
 192  4
         if ( !fragmentDocument )
 193  
         {
 194  4
             markup( sinkCommands );
 195  
 
 196  4
             markup( getDocumentStart() );
 197  
 
 198  4
             markup( preamble );
 199  
 
 200  4
             markup( getDocumentBegin() );
 201  
         }
 202  4
     }
 203  
 
 204  
     /**
 205  
      * {@inheritDoc}
 206  
      */
 207  
     public void body()
 208  
     {
 209  4
         body( null );
 210  4
     }
 211  
 
 212  
     /** {@inheritDoc} */
 213  
     public void body( SinkEventAttributes attributes )
 214  
     {
 215  4
         if ( titleFlag )
 216  
         {
 217  2
             if ( fragmentDocument  )
 218  
             {
 219  0
                 markup( "\\section" );
 220  
             }
 221  
             else
 222  
             {
 223  2
                 titleFlag = false;
 224  2
                 markup( "\\maketitle" + EOL + EOL );
 225  
             }
 226  
         }
 227  4
     }
 228  
 
 229  
     /**
 230  
      * {@inheritDoc}
 231  
      */
 232  
     public void body_()
 233  
     {
 234  4
         if ( !fragmentDocument )
 235  
         {
 236  4
             markup( getDocumentEnd() );
 237  
         }
 238  
 
 239  4
         flush();
 240  4
     }
 241  
 
 242  
     /**
 243  
      * {@inheritDoc}
 244  
      */
 245  
     public void title()
 246  
     {
 247  4
         title( null );
 248  4
     }
 249  
 
 250  
     /** {@inheritDoc} */
 251  
     public void title( SinkEventAttributes attributes )
 252  
     {
 253  4
         if ( !fragmentDocument )
 254  
         {
 255  4
             titleFlag = true;
 256  4
             markup( "\\title{" );
 257  
         }
 258  
         else
 259  
         {
 260  0
             ignoreText = true;
 261  
         }
 262  4
     }
 263  
 
 264  
     /**
 265  
      * {@inheritDoc}
 266  
      */
 267  
     public void title_()
 268  
     {
 269  4
         if ( !fragmentDocument )
 270  
         {
 271  4
             markup( "}" + EOL );
 272  
         }
 273  
         else
 274  
         {
 275  0
             ignoreText = false;
 276  
         }
 277  4
     }
 278  
 
 279  
     /**
 280  
      * {@inheritDoc}
 281  
      */
 282  
     public void author()
 283  
     {
 284  4
         author( null );
 285  4
     }
 286  
 
 287  
     /** {@inheritDoc} */
 288  
     public void author( SinkEventAttributes attributes )
 289  
     {
 290  4
         if ( !fragmentDocument )
 291  
         {
 292  4
             markup( "\\author{" );
 293  
         }
 294  
         else
 295  
         {
 296  0
             ignoreText = true;
 297  
         }
 298  4
     }
 299  
 
 300  
     /**
 301  
      * {@inheritDoc}
 302  
      */
 303  
     public void author_()
 304  
     {
 305  4
         if ( !fragmentDocument )
 306  
         {
 307  4
             markup( "}" + EOL );
 308  
         }
 309  
         else
 310  
         {
 311  0
             ignoreText = false;
 312  
         }
 313  4
     }
 314  
 
 315  
     /**
 316  
      * {@inheritDoc}
 317  
      */
 318  
     public void date()
 319  
     {
 320  4
         date( null );
 321  4
     }
 322  
 
 323  
     /** {@inheritDoc} */
 324  
     public void date( SinkEventAttributes attributes )
 325  
     {
 326  4
         if ( !fragmentDocument )
 327  
         {
 328  4
             markup( "\\date{" );
 329  
         }
 330  
         else
 331  
         {
 332  0
             ignoreText = true;
 333  
         }
 334  4
     }
 335  
 
 336  
     /**
 337  
      * {@inheritDoc}
 338  
      */
 339  
     public void date_()
 340  
     {
 341  4
         if ( !fragmentDocument )
 342  
         {
 343  4
             markup( "}" + EOL );
 344  
         }
 345  
         else
 346  
         {
 347  0
             ignoreText = false;
 348  
         }
 349  4
     }
 350  
 
 351  
     /** {@inheritDoc} */
 352  
     public void sectionTitle( int level, SinkEventAttributes attributes )
 353  
     {
 354  20
         isTitle = true;
 355  20
     }
 356  
 
 357  
     /** {@inheritDoc} */
 358  
     public void sectionTitle_( int level )
 359  
     {
 360  20
         String command = "";
 361  20
         switch ( level )
 362  
         {
 363  
             case SECTION_LEVEL_1:
 364  4
                 command = "section";
 365  4
                 break;
 366  
             case SECTION_LEVEL_2:
 367  4
                 command = "subsection";
 368  4
                 break;
 369  
             case SECTION_LEVEL_3:
 370  4
                 command = "subsubsection";
 371  4
                 break;
 372  
             case SECTION_LEVEL_4:
 373  4
                 command = "paragraph";
 374  4
                 break;
 375  
             case SECTION_LEVEL_5:
 376  4
                 command = "subparagraph";
 377  4
                 break;
 378  
             default:
 379  0
                 throw new IllegalArgumentException( "Not a section level: " + level );
 380  
         }
 381  
 
 382  20
         isTitle = false;
 383  
 
 384  20
         if ( StringUtils.isNotEmpty( title ) )
 385  
         {
 386  20
             markup( EOL + "\\" + command + "{" + title + "}" + EOL );
 387  
 
 388  20
             title = null;
 389  
         }
 390  20
     }
 391  
 
 392  
     // ----------------------------------------------------------------------
 393  
     // Section Title 1
 394  
     // ----------------------------------------------------------------------
 395  
 
 396  
     /**
 397  
      * {@inheritDoc}
 398  
      */
 399  
     public void sectionTitle1()
 400  
     {
 401  4
         sectionTitle( SECTION_LEVEL_1, null );
 402  4
     }
 403  
 
 404  
     /**
 405  
      * {@inheritDoc}
 406  
      */
 407  
     public void sectionTitle1_()
 408  
     {
 409  4
         sectionTitle_( SECTION_LEVEL_1 );
 410  4
     }
 411  
 
 412  
     // ----------------------------------------------------------------------
 413  
     // Section Title 2
 414  
     // ----------------------------------------------------------------------
 415  
 
 416  
     /**
 417  
      * {@inheritDoc}
 418  
      */
 419  
     public void sectionTitle2()
 420  
     {
 421  4
         sectionTitle( SECTION_LEVEL_2, null );
 422  4
     }
 423  
 
 424  
     /**
 425  
      * {@inheritDoc}
 426  
      */
 427  
     public void sectionTitle2_()
 428  
     {
 429  4
         sectionTitle_( SECTION_LEVEL_2 );
 430  4
     }
 431  
 
 432  
     // ----------------------------------------------------------------------
 433  
     // Section Title 3
 434  
     // ----------------------------------------------------------------------
 435  
 
 436  
     /**
 437  
      * {@inheritDoc}
 438  
      */
 439  
     public void sectionTitle3()
 440  
     {
 441  4
         sectionTitle( SECTION_LEVEL_3, null );
 442  4
     }
 443  
 
 444  
     /**
 445  
      * {@inheritDoc}
 446  
      */
 447  
     public void sectionTitle3_()
 448  
     {
 449  4
         sectionTitle_( SECTION_LEVEL_3 );
 450  4
     }
 451  
 
 452  
     // ----------------------------------------------------------------------
 453  
     // Section Title 4
 454  
     // ----------------------------------------------------------------------
 455  
 
 456  
     /**
 457  
      * {@inheritDoc}
 458  
      */
 459  
     public void sectionTitle4()
 460  
     {
 461  4
         sectionTitle( SECTION_LEVEL_4, null );
 462  4
     }
 463  
 
 464  
     /**
 465  
      * {@inheritDoc}
 466  
      */
 467  
     public void sectionTitle4_()
 468  
     {
 469  4
         sectionTitle_( SECTION_LEVEL_4 );
 470  4
     }
 471  
 
 472  
     // ----------------------------------------------------------------------
 473  
     // Section Title 5
 474  
     // ----------------------------------------------------------------------
 475  
 
 476  
     /**
 477  
      * {@inheritDoc}
 478  
      */
 479  
     public void sectionTitle5()
 480  
     {
 481  4
         sectionTitle( SECTION_LEVEL_5, null );
 482  4
     }
 483  
 
 484  
     /**
 485  
      * {@inheritDoc}
 486  
      */
 487  
     public void sectionTitle5_()
 488  
     {
 489  4
         sectionTitle_( SECTION_LEVEL_5 );
 490  4
     }
 491  
 
 492  
     // ----------------------------------------------------------------------
 493  
     // List
 494  
     // ----------------------------------------------------------------------
 495  
 
 496  
     /**
 497  
      * {@inheritDoc}
 498  
      */
 499  
     public void list()
 500  
     {
 501  6
         list( null );
 502  6
     }
 503  
 
 504  
     /** {@inheritDoc} */
 505  
     public void list( SinkEventAttributes attributes )
 506  
     {
 507  6
         markup( EOL + "\\begin{itemize}" );
 508  6
     }
 509  
 
 510  
     /**
 511  
      * {@inheritDoc}
 512  
      */
 513  
     public void list_()
 514  
     {
 515  6
         markup( EOL + "\\end{itemize}" + EOL );
 516  6
     }
 517  
 
 518  
     /**
 519  
      * {@inheritDoc}
 520  
      */
 521  
     public void listItem()
 522  
     {
 523  12
         listItem( null );
 524  12
     }
 525  
 
 526  
     /** {@inheritDoc} */
 527  
     public void listItem( SinkEventAttributes attributes )
 528  
     {
 529  12
         markup( EOL + "\\item " );
 530  12
     }
 531  
 
 532  
     /**
 533  
      * {@inheritDoc}
 534  
      */
 535  
     public void numberedList( int numbering )
 536  
     {
 537  6
         numberedList( numbering, null );
 538  6
     }
 539  
 
 540  
     /** {@inheritDoc} */
 541  
     public void numberedList( int numbering, SinkEventAttributes attributes )
 542  
     {
 543  6
         ++numberedListNesting;
 544  
 
 545  
         String counter;
 546  6
         switch ( numberedListNesting )
 547  
         {
 548  
             case 1:
 549  4
                 counter = "enumi";
 550  4
                 break;
 551  
             case 2:
 552  2
                 counter = "enumii";
 553  2
                 break;
 554  
             case 3:
 555  0
                 counter = "enumiii";
 556  0
                 break;
 557  
             case 4:
 558  
             default:
 559  0
                 counter = "enumiv";
 560  
         }
 561  
 
 562  
         String style;
 563  6
         switch ( numbering )
 564  
         {
 565  
             case NUMBERING_UPPER_ALPHA:
 566  2
                 style = "Alph";
 567  2
                 break;
 568  
             case NUMBERING_LOWER_ALPHA:
 569  0
                 style = "alph";
 570  0
                 break;
 571  
             case NUMBERING_UPPER_ROMAN:
 572  0
                 style = "Roman";
 573  0
                 break;
 574  
             case NUMBERING_LOWER_ROMAN:
 575  2
                 style = "roman";
 576  2
                 break;
 577  
             case NUMBERING_DECIMAL:
 578  
             default:
 579  2
                 style = "arabic";
 580  
         }
 581  
 
 582  6
         markup( EOL + "\\begin{enumerate}" + EOL );
 583  6
         markup( "\\renewcommand{\\the" + counter + "}{\\" + style + "{" + counter + "}}" + EOL );
 584  6
     }
 585  
 
 586  
     /**
 587  
      * {@inheritDoc}
 588  
      */
 589  
     public void numberedList_()
 590  
     {
 591  6
         markup( EOL + "\\end{enumerate}" + EOL );
 592  6
         --numberedListNesting;
 593  6
     }
 594  
 
 595  
     /**
 596  
      * {@inheritDoc}
 597  
      */
 598  
     public void numberedListItem()
 599  
     {
 600  10
         numberedListItem( null );
 601  10
     }
 602  
 
 603  
     /** {@inheritDoc} */
 604  
     public void numberedListItem( SinkEventAttributes attributes )
 605  
     {
 606  10
         markup( "\\item " );
 607  10
     }
 608  
 
 609  
     /**
 610  
      * {@inheritDoc}
 611  
      */
 612  
     public void definitionList()
 613  
     {
 614  4
         definitionList( null );
 615  4
     }
 616  
 
 617  
     /** {@inheritDoc} */
 618  
     public void definitionList( SinkEventAttributes attributes )
 619  
     {
 620  4
         markup( EOL + "\\begin{description}" );
 621  4
     }
 622  
 
 623  
     /**
 624  
      * {@inheritDoc}
 625  
      */
 626  
     public void definitionList_()
 627  
     {
 628  4
         markup( EOL + "\\end{description}" + EOL );
 629  4
     }
 630  
 
 631  
     /**
 632  
      * {@inheritDoc}
 633  
      */
 634  
     public void definedTerm()
 635  
     {
 636  6
         definedTerm( null );
 637  6
     }
 638  
 
 639  
     /** {@inheritDoc} */
 640  
     public void definedTerm( SinkEventAttributes attributes )
 641  
     {
 642  6
         markup( EOL + "\\item[\\mbox{" );
 643  6
     }
 644  
 
 645  
     /**
 646  
      * {@inheritDoc}
 647  
      */
 648  
     public void definedTerm_()
 649  
     {
 650  6
         markup( "}] " );
 651  6
     }
 652  
 
 653  
     /** {@inheritDoc} */
 654  
     public void definitionListItem()
 655  
     {
 656  6
         definitionListItem( null );
 657  6
     }
 658  
 
 659  
     /** {@inheritDoc} */
 660  
     public void definitionListItem( SinkEventAttributes attributes )
 661  
     {
 662  
         // nop
 663  6
     }
 664  
 
 665  
     /** {@inheritDoc} */
 666  
     public void definitionListItem_()
 667  
     {
 668  
         // nop
 669  6
     }
 670  
 
 671  
     /** {@inheritDoc} */
 672  
     public void definition()
 673  
     {
 674  6
         definition( null );
 675  6
     }
 676  
 
 677  
     /** {@inheritDoc} */
 678  
     public void definition( SinkEventAttributes attributes )
 679  
     {
 680  
         // nop
 681  6
     }
 682  
 
 683  
     /** {@inheritDoc} */
 684  
     public void definition_()
 685  
     {
 686  
         // nop
 687  6
     }
 688  
 
 689  
     // ----------------------------------------------------------------------
 690  
     // Figure
 691  
     // ----------------------------------------------------------------------
 692  
 
 693  
     /**
 694  
      * {@inheritDoc}
 695  
      */
 696  
     public void figure()
 697  
     {
 698  2
         figure( null );
 699  2
     }
 700  
 
 701  
     /** {@inheritDoc} */
 702  
     public void figure( SinkEventAttributes attributes )
 703  
     {
 704  4
         figureFlag = true;
 705  4
         markup( EOL + "\\begin{figure}[htb]" + EOL );
 706  4
     }
 707  
 
 708  
     /**
 709  
      * {@inheritDoc}
 710  
      */
 711  
     public void figure_()
 712  
     {
 713  4
         markup( "\\end{figure}" + EOL );
 714  4
         figureFlag = false;
 715  4
     }
 716  
 
 717  
     /**
 718  
      * {@inheritDoc}
 719  
      */
 720  
     public void figureGraphics( String name )
 721  
     {
 722  2
         figureGraphics( name, null );
 723  2
     }
 724  
 
 725  
     /** {@inheritDoc} */
 726  
     public void figureGraphics( String src, SinkEventAttributes attributes )
 727  
     {
 728  4
         if ( !src.toLowerCase( Locale.ENGLISH ).endsWith( ".eps" ) )
 729  
         {
 730  4
             getLog().warn( "[Latex Sink] Found non-eps figure graphics!" );
 731  
         }
 732  
 
 733  4
         markup( "\\begin{center}" + EOL );
 734  4
         markup( "\\includegraphics{" + src + "}" + EOL );
 735  4
         markup( "\\end{center}" + EOL );
 736  4
     }
 737  
 
 738  
     /**
 739  
      * {@inheritDoc}
 740  
      */
 741  
     public void figureCaption()
 742  
     {
 743  2
         figureCaption( null );
 744  2
     }
 745  
 
 746  
     /** {@inheritDoc} */
 747  
     public void figureCaption( SinkEventAttributes attributes )
 748  
     {
 749  4
         markup( "\\caption{" );
 750  4
     }
 751  
 
 752  
     /**
 753  
      * {@inheritDoc}
 754  
      */
 755  
     public void figureCaption_()
 756  
     {
 757  4
         markup( "}" + EOL );
 758  4
     }
 759  
 
 760  
     // ----------------------------------------------------------------------
 761  
     // Table
 762  
     // ----------------------------------------------------------------------
 763  
 
 764  
     /**
 765  
      * {@inheritDoc}
 766  
      */
 767  
     public void table()
 768  
     {
 769  8
         table( null );
 770  8
     }
 771  
 
 772  
     /** {@inheritDoc} */
 773  
     public void table( SinkEventAttributes attributes )
 774  
     {
 775  8
         tableFlag = true;
 776  8
         markup( EOL + "\\begin{table}[htp]" + EOL );
 777  8
     }
 778  
 
 779  
     /**
 780  
      * {@inheritDoc}
 781  
      */
 782  
     public void table_()
 783  
     {
 784  8
         markup( "\\end{table}" + EOL );
 785  8
         tableFlag = false;
 786  8
     }
 787  
 
 788  
     /**
 789  
      * {@inheritDoc}
 790  
      */
 791  
     public void tableRows( int[] justification, boolean grid )
 792  
 
 793  
     {
 794  8
         StringBuffer justif = new StringBuffer();
 795  24
         for ( int i = 0; i < justification.length; ++i )
 796  
         {
 797  16
             if ( grid )
 798  
             {
 799  10
                 justif.append( '|' );
 800  
             }
 801  16
             switch ( justification[i] )
 802  
             {
 803  
                 case Sink.JUSTIFY_CENTER:
 804  12
                     justif.append( 'c' );
 805  12
                     break;
 806  
                 case Sink.JUSTIFY_LEFT:
 807  2
                     justif.append( 'l' );
 808  2
                     break;
 809  
                 case Sink.JUSTIFY_RIGHT:
 810  2
                     justif.append( 'r' );
 811  2
                     break;
 812  
                 default:
 813  
                     break;
 814  
             }
 815  
         }
 816  8
         if ( grid )
 817  
         {
 818  4
             justif.append( '|' );
 819  
         }
 820  
 
 821  8
         markup( "\\begin{center}" + EOL );
 822  8
         markup( "\\begin{tabular}{" + justif.toString() + "}" + EOL );
 823  8
         if ( grid )
 824  
         {
 825  4
             markup( "\\hline" + EOL );
 826  
         }
 827  8
         gridFlag = grid;
 828  8
         cellJustif = justification;
 829  8
     }
 830  
 
 831  
     /**
 832  
      * {@inheritDoc}
 833  
      */
 834  
     public void tableRows_()
 835  
     {
 836  8
         markup( "\\end{tabular}" + EOL );
 837  8
         markup( "\\end{center}" + EOL );
 838  
 
 839  8
         gridFlag = false;
 840  8
         cellJustif = null;
 841  8
     }
 842  
 
 843  
     /**
 844  
      * {@inheritDoc}
 845  
      */
 846  
     public void tableRow()
 847  
     {
 848  14
         tableRow( null );
 849  14
     }
 850  
 
 851  
     /** {@inheritDoc} */
 852  
     public void tableRow( SinkEventAttributes attributes )
 853  
     {
 854  14
         cellCount = 0;
 855  14
     }
 856  
 
 857  
     /**
 858  
      * {@inheritDoc}
 859  
      */
 860  
     public void tableRow_()
 861  
     {
 862  14
         markup( "\\\\" + EOL );
 863  14
         if ( gridFlag || lastCellWasHeader )
 864  
         {
 865  8
             markup( "\\hline" + EOL );
 866  
         }
 867  14
         cellCount = 0;
 868  14
         lastCellWasHeader = false;
 869  14
     }
 870  
 
 871  
     /**
 872  
      * {@inheritDoc}
 873  
      */
 874  
     public void tableCell()
 875  
     {
 876  26
         tableCell( (SinkEventAttributes) null );
 877  26
     }
 878  
 
 879  
     /** {@inheritDoc} */
 880  
     public void tableCell( String width )
 881  
     {
 882  0
         SinkEventAttributeSet att = new SinkEventAttributeSet();
 883  0
         att.addAttribute( javax.swing.text.html.HTML.Attribute.WIDTH, width );
 884  
 
 885  0
         tableCell( att );
 886  0
     }
 887  
 
 888  
     /** {@inheritDoc} */
 889  
     public void tableCell( SinkEventAttributes attributes )
 890  
     {
 891  30
         tableCell( false );
 892  30
     }
 893  
 
 894  
     /**
 895  
      * {@inheritDoc}
 896  
      */
 897  
     public void tableCell_()
 898  
     {
 899  30
         markup( "\\end{tabular}" );
 900  30
         ++cellCount;
 901  30
     }
 902  
 
 903  
     /**
 904  
      * {@inheritDoc}
 905  
      */
 906  
     public void tableHeaderCell()
 907  
     {
 908  4
         tableCell( (SinkEventAttributes) null );
 909  4
     }
 910  
 
 911  
     /** {@inheritDoc} */
 912  
     public void tableHeaderCell( String width )
 913  
     {
 914  0
         SinkEventAttributeSet att = new SinkEventAttributeSet();
 915  0
         att.addAttribute( javax.swing.text.html.HTML.Attribute.WIDTH, width );
 916  
 
 917  0
         tableHeaderCell( att );
 918  0
     }
 919  
 
 920  
     /** {@inheritDoc} */
 921  
     public void tableHeaderCell( SinkEventAttributes attributes )
 922  
     {
 923  0
         tableCell( true );
 924  0
     }
 925  
 
 926  
     /**
 927  
      * {@inheritDoc}
 928  
      */
 929  
     public void tableHeaderCell_()
 930  
     {
 931  4
         tableCell_();
 932  4
     }
 933  
 
 934  64
     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  30
         lastCellWasHeader = header;
 944  
 
 945  30
         if ( cellCount > 0 )
 946  
         {
 947  16
             markup( " &" + EOL );
 948  
         }
 949  
 
 950  
         char justif;
 951  30
         switch ( cellJustif[cellCount] )
 952  
         {
 953  
             case Sink.JUSTIFY_LEFT:
 954  4
                 justif = 'l';
 955  4
                 break;
 956  
             case Sink.JUSTIFY_RIGHT:
 957  4
                 justif = 'r';
 958  4
                 break;
 959  
             case Sink.JUSTIFY_CENTER:
 960  
             default:
 961  22
                 justif = 'c';
 962  
                 break;
 963  
         }
 964  30
         markup( "\\begin{tabular}[t]{" + justif + "}" );
 965  30
     }
 966  
 
 967  
     /**
 968  
      * {@inheritDoc}
 969  
      */
 970  
     public void tableCaption()
 971  
     {
 972  4
         tableCaption( null );
 973  4
     }
 974  
 
 975  
     /** {@inheritDoc} */
 976  
     public void tableCaption( SinkEventAttributes attributes )
 977  
     {
 978  4
         markup( "\\caption{" );
 979  4
     }
 980  
 
 981  
     /**
 982  
      * {@inheritDoc}
 983  
      */
 984  
     public void tableCaption_()
 985  
     {
 986  4
         markup( "}" + EOL );
 987  4
     }
 988  
 
 989  
     /**
 990  
      * {@inheritDoc}
 991  
      */
 992  
     public void paragraph()
 993  
     {
 994  30
         paragraph( null );
 995  30
     }
 996  
 
 997  
     /** {@inheritDoc} */
 998  
     public void paragraph( SinkEventAttributes attributes )
 999  
     {
 1000  30
         markup( EOL + EOL );
 1001  30
     }
 1002  
 
 1003  
     /**
 1004  
      * {@inheritDoc}
 1005  
      */
 1006  
     public void paragraph_()
 1007  
     {
 1008  30
         markup( EOL );
 1009  30
     }
 1010  
 
 1011  
     /**
 1012  
      * {@inheritDoc}
 1013  
      */
 1014  
     public void verbatim( boolean boxed )
 1015  
     {
 1016  0
         verbatim( boxed ? SinkEventAttributeSet.BOXED : null );
 1017  0
     }
 1018  
 
 1019  
     /** {@inheritDoc} */
 1020  
     public void verbatim( SinkEventAttributes attributes )
 1021  
     {
 1022  6
         boolean boxed = false;
 1023  
 
 1024  6
         if ( attributes != null && attributes.isDefined( SinkEventAttributes.DECORATION ) )
 1025  
         {
 1026  6
             boxed = "boxed".equals(
 1027  
                 attributes.getAttribute( SinkEventAttributes.DECORATION ) );
 1028  
         }
 1029  
 
 1030  6
         markup( EOL + "\\begin{small}" + EOL );
 1031  
 
 1032  6
         if ( boxed )
 1033  
         {
 1034  6
             markup( "\\begin{Verbatim}[frame=single]" + EOL );
 1035  
         }
 1036  
         else
 1037  
         {
 1038  0
             markup( "\\begin{Verbatim}" + EOL );
 1039  
         }
 1040  
 
 1041  6
         verbatimFlag = true;
 1042  6
     }
 1043  
 
 1044  
     /**
 1045  
      * {@inheritDoc}
 1046  
      */
 1047  
     public void verbatim_()
 1048  
     {
 1049  6
         markup( EOL + "\\end{Verbatim}" + EOL );
 1050  6
         markup( "\\end{small}" + EOL );
 1051  
 
 1052  6
         verbatimFlag = false;
 1053  6
     }
 1054  
 
 1055  
     /**
 1056  
      * {@inheritDoc}
 1057  
      */
 1058  
     public void horizontalRule()
 1059  
     {
 1060  4
         horizontalRule( null );
 1061  4
     }
 1062  
 
 1063  
     /** {@inheritDoc} */
 1064  
     public void horizontalRule( SinkEventAttributes attributes )
 1065  
     {
 1066  4
         markup( EOL + "\\begin{center}\\rule[0.5ex]{\\linewidth}{1pt}\\end{center}" + EOL );
 1067  4
     }
 1068  
 
 1069  
     /**
 1070  
      * {@inheritDoc}
 1071  
      */
 1072  
     public void pageBreak()
 1073  
     {
 1074  4
         markup( EOL + "\\newpage" + EOL );
 1075  4
     }
 1076  
 
 1077  
     /**
 1078  
      * {@inheritDoc}
 1079  
      */
 1080  
     public void anchor( String name )
 1081  
     {
 1082  4
         anchor( name, null );
 1083  4
     }
 1084  
 
 1085  
     /** {@inheritDoc} */
 1086  
     public void anchor( String name, SinkEventAttributes attributes )
 1087  
     {
 1088  4
         markup( "\\hypertarget{" + name + "}{" );
 1089  4
     }
 1090  
 
 1091  
     /**
 1092  
      * {@inheritDoc}
 1093  
      */
 1094  
     public void anchor_()
 1095  
     {
 1096  4
         markup( "}" );
 1097  4
     }
 1098  
 
 1099  
     /**
 1100  
      * {@inheritDoc}
 1101  
      */
 1102  
     public void link( String name )
 1103  
     {
 1104  10
         link( name, null );
 1105  10
     }
 1106  
 
 1107  
     /** {@inheritDoc} */
 1108  
     public void link( String name, SinkEventAttributes attributes )
 1109  
     {
 1110  
         // TODO: use \\url for simple links
 1111  10
         if ( DoxiaUtils.isExternalLink( name ) )
 1112  
         {
 1113  4
             markup( "\\href{" + name + "}{" );
 1114  
         }
 1115  
         else
 1116  
         {
 1117  6
             markup( "\\hyperlink{" + name + "}{" );
 1118  
         }
 1119  10
     }
 1120  
 
 1121  
     /**
 1122  
      * {@inheritDoc}
 1123  
      */
 1124  
     public void link_()
 1125  
     {
 1126  10
         markup( "}" );
 1127  10
     }
 1128  
 
 1129  
     /**
 1130  
      * {@inheritDoc}
 1131  
      */
 1132  
     public void italic()
 1133  
     {
 1134  4
         markup( "\\textit{" );
 1135  4
     }
 1136  
 
 1137  
     /**
 1138  
      * {@inheritDoc}
 1139  
      */
 1140  
     public void italic_()
 1141  
     {
 1142  4
         markup( "}" );
 1143  4
     }
 1144  
 
 1145  
     /**
 1146  
      * {@inheritDoc}
 1147  
      */
 1148  
     public void bold()
 1149  
     {
 1150  4
         markup( "\\textbf{" );
 1151  4
     }
 1152  
 
 1153  
     /**
 1154  
      * {@inheritDoc}
 1155  
      */
 1156  
     public void bold_()
 1157  
     {
 1158  4
         markup( "}" );
 1159  4
     }
 1160  
 
 1161  
     /**
 1162  
      * {@inheritDoc}
 1163  
      */
 1164  
     public void monospaced()
 1165  
     {
 1166  4
         markup( "\\texttt{\\small " );
 1167  4
     }
 1168  
 
 1169  
     /**
 1170  
      * {@inheritDoc}
 1171  
      */
 1172  
     public void monospaced_()
 1173  
     {
 1174  4
         markup( "}" );
 1175  4
     }
 1176  
 
 1177  
     /**
 1178  
      * {@inheritDoc}
 1179  
      */
 1180  
     public void lineBreak()
 1181  
     {
 1182  36
         lineBreak( null );
 1183  36
     }
 1184  
 
 1185  
     /** {@inheritDoc} */
 1186  
     public void lineBreak( SinkEventAttributes attributes )
 1187  
     {
 1188  36
         markup( ( figureFlag || tableFlag || titleFlag || verbatimFlag ) ? EOL : "\\newline" + EOL );
 1189  36
     }
 1190  
 
 1191  
     /**
 1192  
      * {@inheritDoc}
 1193  
      */
 1194  
     public void nonBreakingSpace()
 1195  
     {
 1196  6
         markup( "~" );
 1197  6
     }
 1198  
 
 1199  
     /**
 1200  
      * {@inheritDoc}
 1201  
      */
 1202  
     public void text( String text )
 1203  
     {
 1204  218
         text( text, null );
 1205  218
     }
 1206  
 
 1207  
     /** {@inheritDoc} */
 1208  
     public void text( String text, SinkEventAttributes attributes )
 1209  
     {
 1210  220
         if ( ignoreText )
 1211  
         {
 1212  0
             return;
 1213  
         }
 1214  220
         if ( isTitle )
 1215  
         {
 1216  20
             title = text;
 1217  
         }
 1218  200
         else if ( verbatimFlag )
 1219  
         {
 1220  6
             verbatimContent( text );
 1221  
         }
 1222  
         else
 1223  
         {
 1224  194
             content( text );
 1225  
         }
 1226  220
     }
 1227  
 
 1228  
     /** {@inheritDoc} */
 1229  
     public void rawText( String text )
 1230  
     {
 1231  6
         verbatimContent( text );
 1232  6
     }
 1233  
 
 1234  
     /** {@inheritDoc} */
 1235  
     public void comment( String comment )
 1236  
     {
 1237  4
         rawText( EOL + "% " + comment );
 1238  4
     }
 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  0
         getLog().warn( "[Latex Sink] Unknown Sink event: '" + name + "', ignoring!" );
 1249  0
     }
 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  510
         if ( text != null )
 1261  
         {
 1262  510
             out.write( text, /*preserveSpace*/ true );
 1263  
         }
 1264  510
     }
 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  194
         out.write( escaped( text ), /*preserveSpace*/ false );
 1274  194
     }
 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  12
         out.write( text, /*preserveSpace*/ true );
 1284  12
     }
 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  204
         int length = text.length();
 1297  204
         StringBuffer buffer = new StringBuffer( length );
 1298  
 
 1299  2434
         for ( int i = 0; i < length; ++i )
 1300  
         {
 1301  2230
             char c = text.charAt( i );
 1302  2230
             switch ( c )
 1303  
             {
 1304  
                 case '-':
 1305  
                 case '<':
 1306  
                 case '>':
 1307  30
                     buffer.append( "\\symbol{" ).append( (int) c ).append( "}" );
 1308  30
                     break;
 1309  
                 case '~':
 1310  4
                     buffer.append( "\\textasciitilde " );
 1311  4
                     break;
 1312  
                 case '^':
 1313  0
                     buffer.append( "\\textasciicircum " );
 1314  0
                     break;
 1315  
                 case '|':
 1316  0
                     buffer.append( "\\textbar " );
 1317  0
                     break;
 1318  
                 case '\\':
 1319  4
                     buffer.append( "\\textbackslash " );
 1320  4
                     break;
 1321  
                 case '$':
 1322  0
                     buffer.append( "\\$" );
 1323  0
                     break;
 1324  
                 case '&':
 1325  0
                     buffer.append( "\\&" );
 1326  0
                     break;
 1327  
                 case '%':
 1328  0
                     buffer.append( "\\%" );
 1329  0
                     break;
 1330  
                 case '#':
 1331  0
                     buffer.append( "\\#" );
 1332  0
                     break;
 1333  
                 case '{':
 1334  4
                     buffer.append( "\\{" );
 1335  4
                     break;
 1336  
                 case '}':
 1337  4
                     buffer.append( "\\}" );
 1338  4
                     break;
 1339  
                 case '_':
 1340  42
                     buffer.append( "\\_" );
 1341  42
                     break;
 1342  
                 default:
 1343  2142
                     buffer.append( c );
 1344  
             }
 1345  
         }
 1346  
 
 1347  204
         return buffer.toString();
 1348  
     }
 1349  
 
 1350  
     // ----------------------------------------------------------------------
 1351  
     //
 1352  
     // ----------------------------------------------------------------------
 1353  
 
 1354  
     /**
 1355  
      * {@inheritDoc}
 1356  
      */
 1357  
     public void flush()
 1358  
     {
 1359  66
         out.flush();
 1360  66
     }
 1361  
 
 1362  
     /**
 1363  
      * {@inheritDoc}
 1364  
      */
 1365  
     public void close()
 1366  
     {
 1367  62
         out.close();
 1368  
 
 1369  62
         init();
 1370  62
     }
 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  66
         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  66
         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  66
             return IOUtil.toString( getDefaultSinkCommands() );
 1410  
         }
 1411  0
         catch ( IOException ioe )
 1412  
         {
 1413  
             // this should not happen
 1414  0
             getLog().warn( "Could not read default LaTeX commands, the generated LaTeX file will not compile!" );
 1415  0
             getLog().debug( ioe );
 1416  
 
 1417  0
             return "";
 1418  
         }
 1419  
     }
 1420  
 
 1421  
     /**
 1422  
      * Returns the default preamble.
 1423  
      *
 1424  
      * @return String.
 1425  
      */
 1426  
     protected String defaultPreamble()
 1427  
     {
 1428  
         try
 1429  
         {
 1430  66
             return IOUtil.toString( getDefaultPreamble() );
 1431  
         }
 1432  0
         catch ( IOException ioe )
 1433  
         {
 1434  
             // this should not happen
 1435  0
             getLog().warn( "Could not read default LaTeX preamble, the generated LaTeX file will not compile!" );
 1436  0
             getLog().debug( ioe );
 1437  
 
 1438  0
             return "";
 1439  
         }
 1440  
     }
 1441  
 
 1442  
     /** {@inheritDoc} */
 1443  
     protected void init()
 1444  
     {
 1445  130
         super.init();
 1446  
 
 1447  130
         this.ignoreText = false;
 1448  130
         this.titleFlag = false;
 1449  130
         this.numberedListNesting = 0;
 1450  130
         this.verbatimFlag = false;
 1451  130
         this.figureFlag = false;
 1452  130
         this.tableFlag = false;
 1453  130
         this.gridFlag = false;
 1454  130
         this.cellJustif = null;
 1455  130
         this.cellCount = 0;
 1456  130
         this.isTitle = false;
 1457  130
         this.title = null;
 1458  130
     }
 1459  
 }