1 package org.apache.maven.doxia.module.fo;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.IOException;
23 import java.io.Writer;
24
25 import java.util.Calendar;
26 import java.util.Date;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.ResourceBundle;
31 import java.util.Stack;
32
33 import javax.swing.text.MutableAttributeSet;
34 import javax.swing.text.html.HTML.Tag;
35
36 import org.apache.maven.doxia.document.DocumentCover;
37 import org.apache.maven.doxia.document.DocumentMeta;
38 import org.apache.maven.doxia.document.DocumentModel;
39 import org.apache.maven.doxia.document.DocumentTOC;
40 import org.apache.maven.doxia.document.DocumentTOCItem;
41 import org.apache.maven.doxia.sink.SinkEventAttributeSet;
42 import org.apache.maven.doxia.sink.SinkEventAttributes;
43 import org.apache.maven.doxia.util.DoxiaUtils;
44 import org.apache.maven.doxia.util.HtmlTools;
45
46 import org.codehaus.plexus.util.StringUtils;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class FoAggregateSink
70 extends FoSink
71 {
72
73
74
75
76 public static int TOC_NONE = 0;
77
78
79
80
81
82 public static int TOC_START = 1;
83
84
85
86
87
88 public static int TOC_END = 2;
89
90
91 private static final String COVER_HEADER_HEIGHT = "1.5in";
92
93
94 private DocumentModel docModel;
95
96
97 private int chapter = 0;
98
99
100 private String docName;
101
102
103 private String docTitle = "";
104
105
106 private boolean ignoreText;
107
108
109 private int tocPosition;
110
111
112 private final Stack<NumberedListItem> tocStack = new Stack<NumberedListItem>();
113
114
115
116
117
118
119 public FoAggregateSink( Writer writer )
120 {
121 super( writer );
122 }
123
124
125 public void head()
126 {
127 head( null );
128 }
129
130
131 public void head( SinkEventAttributes attributes )
132 {
133 init();
134
135 ignoreText = true;
136 }
137
138
139 public void head_()
140 {
141 ignoreText = false;
142 writeEOL();
143 }
144
145
146 public void title()
147 {
148 title( null );
149 }
150
151
152 public void title( SinkEventAttributes attributes )
153 {
154
155 }
156
157
158 public void title_()
159 {
160
161 }
162
163
164 public void author()
165 {
166 author( null );
167 }
168
169
170 public void author( SinkEventAttributes attributes )
171 {
172
173 }
174
175
176 public void author_()
177 {
178
179 }
180
181
182 public void date()
183 {
184 date( null );
185 }
186
187
188 public void date( SinkEventAttributes attributes )
189 {
190
191 }
192
193
194 public void date_()
195 {
196
197 }
198
199
200 public void body()
201 {
202 body( null );
203 }
204
205
206 public void body( SinkEventAttributes attributes )
207 {
208 chapter++;
209
210 resetSectionCounter();
211
212 startPageSequence( getHeaderText(), getFooterText() );
213
214 if ( docName == null )
215 {
216 getLog().warn( "No document root specified, local links will not be resolved correctly!" );
217 }
218 else
219 {
220 writeStartTag( BLOCK_TAG, "id", docName );
221 }
222
223 }
224
225
226 public void body_()
227 {
228 writeEOL();
229 writeEndTag( BLOCK_TAG );
230 writeEndTag( FLOW_TAG );
231 writeEndTag( PAGE_SEQUENCE_TAG );
232
233
234 docName = null;
235 }
236
237
238
239
240
241
242 public void setDocumentTitle( String title )
243 {
244 this.docTitle = title;
245
246 if ( title == null )
247 {
248 this.docTitle = "";
249 }
250 }
251
252
253
254
255
256
257
258 public void setDocumentName( String name )
259 {
260 this.docName = getIdName( name );
261 }
262
263
264
265
266
267
268
269
270
271
272
273 public void setDocumentModel( DocumentModel model )
274 {
275 setDocumentModel( model, TOC_START );
276 }
277
278
279
280
281
282
283
284
285
286 public void setDocumentModel( DocumentModel model, int tocPos )
287 {
288 this.docModel = model;
289 if ( !( tocPos == TOC_NONE || tocPos == TOC_START || tocPos == TOC_END ) )
290 {
291 if ( getLog().isDebugEnabled() )
292 {
293 getLog().debug( "Unrecognized value for tocPosition: " + tocPos + ", using no toc." );
294 }
295 tocPos = TOC_NONE;
296 }
297 this.tocPosition = tocPos;
298
299 if ( this.docModel != null && this.docModel.getToc() != null && this.tocPosition != TOC_NONE )
300 {
301 DocumentTOCItem tocItem = new DocumentTOCItem();
302 tocItem.setName( this.docModel.getToc().getName() );
303 tocItem.setRef( "./toc" );
304 List<DocumentTOCItem> items = new LinkedList<DocumentTOCItem>();
305 if ( this.tocPosition == TOC_START )
306 {
307 items.add( tocItem );
308 }
309 items.addAll( this.docModel.getToc().getItems() );
310 if ( this.tocPosition == TOC_END )
311 {
312 items.add( tocItem );
313 }
314
315 this.docModel.getToc().setItems( items );
316 }
317 }
318
319
320
321
322
323
324
325
326 private String getIdName( String name )
327 {
328 if ( StringUtils.isEmpty( name ) )
329 {
330 getLog().warn( "Empty document reference, links will not be resolved correctly!" );
331 return "";
332 }
333
334 String idName = name.replace( '\\', '/' );
335
336
337 if ( !idName.startsWith( "./" ) )
338 {
339 idName = "./" + idName;
340 }
341
342 if ( idName.substring( 2 ).lastIndexOf( "." ) != -1 )
343 {
344 idName = idName.substring( 0, idName.lastIndexOf( "." ) );
345 }
346
347 while ( idName.indexOf( "//" ) != -1 )
348 {
349 idName = StringUtils.replace( idName, "//", "/" );
350 }
351
352 return idName;
353 }
354
355
356
357
358
359
360 public void figureGraphics( String name )
361 {
362 figureGraphics( name, null );
363 }
364
365
366 public void figureGraphics( String src, SinkEventAttributes attributes )
367 {
368 String anchor = src;
369
370 while ( anchor.startsWith( "./" ) )
371 {
372 anchor = anchor.substring( 2 );
373 }
374
375 if ( anchor.startsWith( "../" ) && docName != null )
376 {
377 anchor = resolveLinkRelativeToBase( anchor );
378 }
379
380 super.figureGraphics( anchor, attributes );
381 }
382
383
384 public void anchor( String name )
385 {
386 anchor( name, null );
387 }
388
389
390 public void anchor( String name, SinkEventAttributes attributes )
391 {
392 if ( name == null )
393 {
394 throw new NullPointerException( "Anchor name cannot be null!" );
395 }
396
397 String anchor = name;
398
399 if ( !DoxiaUtils.isValidId( anchor ) )
400 {
401 anchor = DoxiaUtils.encodeId( name, true );
402
403 String msg = "Modified invalid anchor name: '" + name + "' to '" + anchor + "'";
404 logMessage( "modifiedLink", msg );
405 }
406
407 anchor = "#" + anchor;
408
409 if ( docName != null )
410 {
411 anchor = docName + anchor;
412 }
413
414 writeStartTag( INLINE_TAG, "id", anchor );
415 }
416
417
418 public void link( String name )
419 {
420 link( name, null );
421 }
422
423
424 public void link( String name, SinkEventAttributes attributes )
425 {
426 if ( name == null )
427 {
428 throw new NullPointerException( "Link name cannot be null!" );
429 }
430
431 if ( DoxiaUtils.isExternalLink( name ) )
432 {
433
434 writeStartTag( BASIC_LINK_TAG, "external-destination", HtmlTools.escapeHTML( name ) );
435 writeStartTag( INLINE_TAG, "href.external" );
436 return;
437 }
438
439 while ( name.indexOf( "//" ) != -1 )
440 {
441 name = StringUtils.replace( name, "//", "/" );
442 }
443
444 if ( DoxiaUtils.isInternalLink( name ) )
445 {
446
447 String anchor = name.substring( 1 );
448
449 if ( !DoxiaUtils.isValidId( anchor ) )
450 {
451 String tmp = anchor;
452 anchor = DoxiaUtils.encodeId( anchor, true );
453
454 String msg = "Modified invalid anchor name: '" + tmp + "' to '" + anchor + "'";
455 logMessage( "modifiedLink", msg );
456 }
457
458 if ( docName != null )
459 {
460 anchor = docName + "#" + anchor;
461 }
462
463 writeStartTag( BASIC_LINK_TAG, "internal-destination", HtmlTools.escapeHTML( anchor ) );
464 writeStartTag( INLINE_TAG, "href.internal" );
465 }
466 else if ( name.startsWith( "../" ) )
467 {
468
469
470 if ( docName == null )
471 {
472
473 writeStartTag( BASIC_LINK_TAG, "internal-destination", HtmlTools.escapeHTML( name ) );
474 writeStartTag( INLINE_TAG, "href.internal" );
475
476 return;
477 }
478
479 String anchor = resolveLinkRelativeToBase( chopExtension( name ) );
480
481 writeStartTag( BASIC_LINK_TAG, "internal-destination", HtmlTools.escapeHTML( anchor ) );
482 writeStartTag( INLINE_TAG, "href.internal" );
483 }
484 else
485 {
486
487
488 String anchor = name;
489
490 if ( anchor.startsWith( "./" ) )
491 {
492 this.link( anchor.substring( 2 ) );
493 return;
494 }
495
496 anchor = chopExtension( anchor );
497
498 String base = docName.substring( 0, docName.lastIndexOf( "/" ) );
499 anchor = base + "/" + anchor;
500
501 writeStartTag( BASIC_LINK_TAG, "internal-destination", HtmlTools.escapeHTML( anchor ) );
502 writeStartTag( INLINE_TAG, "href.internal" );
503 }
504 }
505
506
507 private String resolveLinkRelativeToBase( String name )
508 {
509 String anchor = name;
510
511 String base = docName.substring( 0, docName.lastIndexOf( "/" ) );
512
513 if ( base.indexOf( "/" ) != -1 )
514 {
515 while ( anchor.startsWith( "../" ) )
516 {
517 base = base.substring( 0, base.lastIndexOf( "/" ) );
518
519 anchor = anchor.substring( 3 );
520
521 if ( base.lastIndexOf( "/" ) == -1 )
522 {
523 while ( anchor.startsWith( "../" ) )
524 {
525 anchor = anchor.substring( 3 );
526 }
527 break;
528 }
529 }
530 }
531
532 return base + "/" + anchor;
533 }
534
535 private String chopExtension( String name )
536 {
537 String anchor = name;
538
539 int dot = anchor.lastIndexOf( "." );
540
541 if ( dot != -1 && dot != anchor.length() && anchor.charAt( dot + 1 ) != '/' )
542 {
543 int hash = anchor.indexOf( "#", dot );
544
545 if ( hash != -1 )
546 {
547 int dot2 = anchor.indexOf( ".", hash );
548
549 if ( dot2 != -1 )
550 {
551 anchor =
552 anchor.substring( 0, dot ) + "#" + HtmlTools.encodeId( anchor.substring( hash + 1, dot2 ) );
553 }
554 else
555 {
556 anchor =
557 anchor.substring( 0, dot ) + "#"
558 + HtmlTools.encodeId( anchor.substring( hash + 1, anchor.length() ) );
559 }
560 }
561 else
562 {
563 anchor = anchor.substring( 0, dot );
564 }
565 }
566
567 return anchor;
568 }
569
570
571
572
573
574
575
576
577
578
579 protected void writeStartTag( Tag tag, String attributeId )
580 {
581 if ( !ignoreText )
582 {
583 super.writeStartTag( tag, attributeId );
584 }
585 }
586
587
588
589
590
591
592 protected void writeStartTag( Tag tag, String id, String name )
593 {
594 if ( !ignoreText )
595 {
596 super.writeStartTag( tag, id, name );
597 }
598 }
599
600
601
602
603
604
605 protected void writeEndTag( Tag t )
606 {
607 if ( !ignoreText )
608 {
609 super.writeEndTag( t );
610 }
611 }
612
613
614
615
616
617
618 protected void writeEmptyTag( Tag tag, String attributeId )
619 {
620 if ( !ignoreText )
621 {
622 super.writeEmptyTag( tag, attributeId );
623 }
624 }
625
626
627
628
629
630
631 protected void write( String text )
632 {
633 if ( !ignoreText )
634 {
635 super.write( text );
636 }
637 }
638
639
640
641
642
643
644 protected void writeln( String text )
645 {
646 if ( !ignoreText )
647 {
648 super.writeln( text );
649 }
650 }
651
652
653
654
655
656
657 protected void content( String text )
658 {
659 if ( !ignoreText )
660 {
661 super.content( text );
662 }
663 }
664
665
666
667
668 protected void newline()
669 {
670 if ( !ignoreText )
671 {
672 writeEOL();
673 }
674 }
675
676
677
678
679
680
681
682 protected void startPageSequence( String headerText, String footerText )
683 {
684 if ( chapter == 1 )
685 {
686 startPageSequence( "0", headerText, footerText );
687 }
688 else
689 {
690 startPageSequence( "auto", headerText, footerText );
691 }
692 }
693
694
695
696
697
698
699 protected String getHeaderText()
700 {
701 return Integer.toString( chapter ) + " " + docTitle;
702 }
703
704
705
706
707
708
709 protected String getFooterText()
710 {
711 int actualYear;
712 String add = " • " + getBundle( Locale.US ).getString( "footer.rights" );
713 String companyName = "";
714
715 if ( docModel != null && docModel.getMeta() != null && docModel.getMeta().isConfidential() )
716 {
717 add = add + " • " + getBundle( Locale.US ).getString( "footer.confidential" );
718 }
719
720 if ( docModel != null && docModel.getCover() != null && docModel.getCover().getCompanyName() != null )
721 {
722 companyName = docModel.getCover().getCompanyName();
723 }
724
725 if ( docModel != null && docModel.getMeta() != null && docModel.getMeta().getDate() != null )
726 {
727 Calendar date = Calendar.getInstance();
728 date.setTime( docModel.getMeta().getDate() );
729 actualYear = date.get( Calendar.YEAR );
730 }
731 else
732 {
733 actualYear = Calendar.getInstance().get( Calendar.YEAR );
734 }
735
736 return "©" + actualYear + ", " + companyName + add;
737 }
738
739
740
741
742
743
744 protected String getChapterString()
745 {
746 return Integer.toString( chapter ) + ".";
747 }
748
749
750
751
752
753
754 protected void regionBefore( String headerText )
755 {
756 writeStartTag( STATIC_CONTENT_TAG, "flow-name", "xsl-region-before" );
757 writeln( "<fo:table table-layout=\"fixed\" width=\"100%\" >" );
758 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "5.625in" );
759 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "0.625in" );
760 writeStartTag( TABLE_BODY_TAG, "" );
761 writeStartTag( TABLE_ROW_TAG, "" );
762 writeStartTag( TABLE_CELL_TAG, "" );
763 writeStartTag( BLOCK_TAG, "header.style" );
764
765 if ( headerText != null )
766 {
767 write( headerText );
768 }
769
770 writeEndTag( BLOCK_TAG );
771 writeEndTag( TABLE_CELL_TAG );
772 writeStartTag( TABLE_CELL_TAG, "" );
773 writeStartTag( BLOCK_TAG, "page.number" );
774 writeEmptyTag( PAGE_NUMBER_TAG, "" );
775 writeEndTag( BLOCK_TAG );
776 writeEndTag( TABLE_CELL_TAG );
777 writeEndTag( TABLE_ROW_TAG );
778 writeEndTag( TABLE_BODY_TAG );
779 writeEndTag( TABLE_TAG );
780 writeEndTag( STATIC_CONTENT_TAG );
781 }
782
783
784
785
786
787
788 protected void regionAfter( String footerText )
789 {
790 writeStartTag( STATIC_CONTENT_TAG, "flow-name", "xsl-region-after" );
791 writeStartTag( BLOCK_TAG, "footer.style" );
792
793 if ( footerText != null )
794 {
795 write( footerText );
796 }
797
798 writeEndTag( BLOCK_TAG );
799 writeEndTag( STATIC_CONTENT_TAG );
800 }
801
802
803
804
805
806
807 protected void chapterHeading( String headerText, boolean chapterNumber )
808 {
809 writeStartTag( BLOCK_TAG, "" );
810 writeStartTag( LIST_BLOCK_TAG, "" );
811 writeStartTag( LIST_ITEM_TAG, "" );
812 writeln( "<fo:list-item-label end-indent=\"6.375in\" start-indent=\"-1in\">" );
813 writeStartTag( BLOCK_TAG, "outdented.number.style" );
814
815 if ( chapterNumber )
816 {
817 writeStartTag( BLOCK_TAG, "chapter.title" );
818 write( Integer.toString( chapter ) );
819 writeEndTag( BLOCK_TAG );
820 }
821
822 writeEndTag( BLOCK_TAG );
823 writeEndTag( LIST_ITEM_LABEL_TAG );
824 writeln( "<fo:list-item-body end-indent=\"1in\" start-indent=\"0in\">" );
825 writeStartTag( BLOCK_TAG, "chapter.title" );
826
827 if ( headerText == null )
828 {
829 write( docTitle );
830 }
831 else
832 {
833 write( headerText );
834 }
835
836 writeEndTag( BLOCK_TAG );
837 writeEndTag( LIST_ITEM_BODY_TAG );
838 writeEndTag( LIST_ITEM_TAG );
839 writeEndTag( LIST_BLOCK_TAG );
840 writeEndTag( BLOCK_TAG );
841 writeStartTag( BLOCK_TAG, "space-after.optimum", "0em" );
842 writeEmptyTag( LEADER_TAG, "chapter.rule" );
843 writeEndTag( BLOCK_TAG );
844 }
845
846
847
848
849 public void toc()
850 {
851 if ( docModel == null || docModel.getToc() == null || docModel.getToc().getItems() == null
852 || this.tocPosition == TOC_NONE )
853 {
854 return;
855 }
856
857 DocumentTOC toc = docModel.getToc();
858
859 writeln( "<fo:page-sequence master-reference=\"toc\" initial-page-number=\"1\" format=\"i\">" );
860 regionBefore( toc.getName() );
861 regionAfter( getFooterText() );
862 writeStartTag( FLOW_TAG, "flow-name", "xsl-region-body" );
863 writeStartTag( BLOCK_TAG, "id", "./toc" );
864 chapterHeading( toc.getName(), false );
865 writeln( "<fo:table table-layout=\"fixed\" width=\"100%\" >" );
866 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "0.45in" );
867 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "0.4in" );
868 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "0.4in" );
869 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "5in" );
870 writeStartTag( TABLE_BODY_TAG );
871
872 writeTocItems( toc.getItems(), 1 );
873
874 writeEndTag( TABLE_BODY_TAG );
875 writeEndTag( TABLE_TAG );
876 writeEndTag( BLOCK_TAG );
877 writeEndTag( FLOW_TAG );
878 writeEndTag( PAGE_SEQUENCE_TAG );
879 }
880
881 private void writeTocItems( List<DocumentTOCItem> tocItems, int level )
882 {
883 final int maxTocLevel = 4;
884
885 if ( level < 1 || level > maxTocLevel )
886 {
887 return;
888 }
889
890 tocStack.push( new NumberedListItem( NUMBERING_DECIMAL ) );
891
892 for ( DocumentTOCItem tocItem : tocItems )
893 {
894 String ref = getIdName( tocItem.getRef() );
895
896 writeStartTag( TABLE_ROW_TAG, "keep-with-next", "auto" );
897
898 if ( level > 2 )
899 {
900 for ( int i = 0; i < level - 2; i++ )
901 {
902 writeStartTag( TABLE_CELL_TAG );
903 writeSimpleTag( BLOCK_TAG );
904 writeEndTag( TABLE_CELL_TAG );
905 }
906 }
907
908 writeStartTag( TABLE_CELL_TAG, "toc.cell" );
909 writeStartTag( BLOCK_TAG, "toc.number.style" );
910
911 NumberedListItem current = tocStack.peek();
912 current.next();
913 write( currentTocNumber() );
914
915 writeEndTag( BLOCK_TAG );
916 writeEndTag( TABLE_CELL_TAG );
917
918 String span = "3";
919
920 if ( level > 2 )
921 {
922 span = Integer.toString( 5 - level );
923 }
924
925 writeStartTag( TABLE_CELL_TAG, "number-columns-spanned", span, "toc.cell" );
926 MutableAttributeSet atts = getFoConfiguration().getAttributeSet( "toc.h" + level + ".style" );
927 atts.addAttribute( "text-align-last", "justify" );
928 writeStartTag( BLOCK_TAG, atts );
929 writeStartTag( BASIC_LINK_TAG, "internal-destination", ref );
930 write( tocItem.getName() );
931 writeEndTag( BASIC_LINK_TAG );
932 writeEmptyTag( LEADER_TAG, "toc.leader.style" );
933 writeStartTag( INLINE_TAG, "page.number" );
934 writeEmptyTag( PAGE_NUMBER_CITATION_TAG, "ref-id", ref );
935 writeEndTag( INLINE_TAG );
936 writeEndTag( BLOCK_TAG );
937 writeEndTag( TABLE_CELL_TAG );
938 writeEndTag( TABLE_ROW_TAG );
939
940 if ( tocItem.getItems() != null )
941 {
942 writeTocItems( tocItem.getItems(), level + 1 );
943 }
944 }
945
946 tocStack.pop();
947 }
948
949 private String currentTocNumber()
950 {
951 String ch = ( tocStack.get( 0 ) ).getListItemSymbol();
952
953 for ( int i = 1; i < tocStack.size(); i++ )
954 {
955 ch = ch + "." + tocStack.get( i ).getListItemSymbol();
956 }
957
958 return ch;
959 }
960
961
962
963
964
965
966 protected void pdfBookmarks()
967 {
968 if ( docModel == null || docModel.getToc() == null )
969 {
970 return;
971 }
972
973 writeStartTag( BOOKMARK_TREE_TAG );
974
975 renderBookmarkItems( docModel.getToc().getItems() );
976
977 writeEndTag( BOOKMARK_TREE_TAG );
978 }
979
980 private void renderBookmarkItems( List<DocumentTOCItem> items )
981 {
982 for ( DocumentTOCItem tocItem : items )
983 {
984 String ref = getIdName( tocItem.getRef() );
985
986 writeStartTag( BOOKMARK_TAG, "internal-destination", ref );
987 writeStartTag( BOOKMARK_TITLE_TAG );
988 write( tocItem.getName() );
989 writeEndTag( BOOKMARK_TITLE_TAG );
990
991 if ( tocItem.getItems() != null )
992 {
993 renderBookmarkItems( tocItem.getItems() );
994 }
995
996 writeEndTag( BOOKMARK_TAG );
997 }
998 }
999
1000
1001
1002
1003 public void coverPage()
1004 {
1005 if ( this.docModel == null )
1006 {
1007 return;
1008 }
1009
1010 DocumentCover cover = docModel.getCover();
1011 DocumentMeta meta = docModel.getMeta();
1012
1013 if ( cover == null && meta == null )
1014 {
1015 return;
1016 }
1017
1018
1019
1020 writeStartTag( PAGE_SEQUENCE_TAG, "master-reference", "cover-page" );
1021 writeStartTag( FLOW_TAG, "flow-name", "xsl-region-body" );
1022 writeStartTag( BLOCK_TAG, "text-align", "center" );
1023 writeln( "<fo:table table-layout=\"fixed\" width=\"100%\" >" );
1024 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "3.125in" );
1025 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "3.125in" );
1026 writeStartTag( TABLE_BODY_TAG );
1027
1028 writeCoverHead( cover );
1029 writeCoverBody( cover, meta );
1030 writeCoverFooter( cover, meta );
1031
1032 writeEndTag( TABLE_BODY_TAG );
1033 writeEndTag( TABLE_TAG );
1034 writeEndTag( BLOCK_TAG );
1035 writeEndTag( FLOW_TAG );
1036 writeEndTag( PAGE_SEQUENCE_TAG );
1037 }
1038
1039 private void writeCoverHead( DocumentCover cover )
1040 {
1041 if ( cover == null )
1042 {
1043 return;
1044 }
1045
1046 String compLogo = cover.getCompanyLogo();
1047 String projLogo = cover.getProjectLogo();
1048
1049 writeStartTag( TABLE_ROW_TAG, "height", COVER_HEADER_HEIGHT );
1050 writeStartTag( TABLE_CELL_TAG );
1051
1052 if ( StringUtils.isNotEmpty( compLogo ) )
1053 {
1054 SinkEventAttributeSet atts = new SinkEventAttributeSet();
1055 atts.addAttribute( "text-align", "left" );
1056 atts.addAttribute( "vertical-align", "top" );
1057 writeStartTag( BLOCK_TAG, atts );
1058 figureGraphics( compLogo, getGraphicsAttributes( compLogo ) );
1059 writeEndTag( BLOCK_TAG );
1060 }
1061
1062 writeSimpleTag( BLOCK_TAG );
1063 writeEndTag( TABLE_CELL_TAG );
1064 writeStartTag( TABLE_CELL_TAG );
1065
1066 if ( StringUtils.isNotEmpty( projLogo ) )
1067 {
1068 SinkEventAttributeSet atts = new SinkEventAttributeSet();
1069 atts.addAttribute( "text-align", "right" );
1070 atts.addAttribute( "vertical-align", "top" );
1071 writeStartTag( BLOCK_TAG, atts );
1072 figureGraphics( projLogo, getGraphicsAttributes( projLogo ) );
1073 writeEndTag( BLOCK_TAG );
1074 }
1075
1076 writeSimpleTag( BLOCK_TAG );
1077 writeEndTag( TABLE_CELL_TAG );
1078 writeEndTag( TABLE_ROW_TAG );
1079 }
1080
1081 private void writeCoverBody( DocumentCover cover, DocumentMeta meta )
1082 {
1083 if ( cover == null && meta == null )
1084 {
1085 return;
1086 }
1087
1088 String subtitle = null;
1089 String title = null;
1090 String type = null;
1091 String version = null;
1092 if ( cover == null )
1093 {
1094
1095 getLog().debug( "The DocumentCover is not defined, using the DocumentMeta title as cover title." );
1096 title = meta.getTitle();
1097 }
1098 else
1099 {
1100 subtitle = cover.getCoverSubTitle();
1101 title = cover.getCoverTitle();
1102 type = cover.getCoverType();
1103 version = cover.getCoverVersion();
1104 }
1105
1106 writeln( "<fo:table-row keep-with-previous=\"always\" height=\"0.014in\">" );
1107 writeStartTag( TABLE_CELL_TAG, "number-columns-spanned", "2" );
1108 writeStartTag( BLOCK_TAG, "line-height", "0.014in" );
1109 writeEmptyTag( LEADER_TAG, "chapter.rule" );
1110 writeEndTag( BLOCK_TAG );
1111 writeEndTag( TABLE_CELL_TAG );
1112 writeEndTag( TABLE_ROW_TAG );
1113
1114 writeStartTag( TABLE_ROW_TAG, "height", "7.447in" );
1115 writeStartTag( TABLE_CELL_TAG, "number-columns-spanned", "2" );
1116 writeln( "<fo:table table-layout=\"fixed\" width=\"100%\" >" );
1117 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "2.083in" );
1118 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "2.083in" );
1119 writeEmptyTag( TABLE_COLUMN_TAG, "column-width", "2.083in" );
1120
1121 writeStartTag( TABLE_BODY_TAG );
1122
1123 writeStartTag( TABLE_ROW_TAG );
1124 writeStartTag( TABLE_CELL_TAG, "number-columns-spanned", "3" );
1125 writeSimpleTag( BLOCK_TAG );
1126 writeEmptyTag( BLOCK_TAG, "space-before", "3.2235in" );
1127 writeEndTag( TABLE_CELL_TAG );
1128 writeEndTag( TABLE_ROW_TAG );
1129
1130 writeStartTag( TABLE_ROW_TAG );
1131 writeStartTag( TABLE_CELL_TAG );
1132 writeEmptyTag( BLOCK_TAG, "space-after", "0.5in" );
1133 writeEndTag( TABLE_CELL_TAG );
1134
1135 writeStartTag( TABLE_CELL_TAG, "number-columns-spanned", "2", "cover.border.left" );
1136 writeStartTag( BLOCK_TAG, "cover.title" );
1137 write( title == null ? "" : title );
1138 writeEndTag( BLOCK_TAG );
1139 writeEndTag( TABLE_CELL_TAG );
1140 writeEndTag( TABLE_ROW_TAG );
1141
1142 writeStartTag( TABLE_ROW_TAG );
1143 writeStartTag( TABLE_CELL_TAG );
1144 writeSimpleTag( BLOCK_TAG );
1145 writeEndTag( TABLE_CELL_TAG );
1146
1147 writeStartTag( TABLE_CELL_TAG, "number-columns-spanned", "2", "cover.border.left.bottom" );
1148 writeStartTag( BLOCK_TAG, "cover.subtitle" );
1149 write( subtitle == null ? ( version == null ? "" : " v. " + version ) : subtitle );
1150 writeEndTag( BLOCK_TAG );
1151 writeStartTag( BLOCK_TAG, "cover.subtitle" );
1152 write( type == null ? "" : type );
1153 writeEndTag( BLOCK_TAG );
1154 writeEndTag( TABLE_CELL_TAG );
1155 writeEndTag( TABLE_ROW_TAG );
1156
1157 writeEndTag( TABLE_BODY_TAG );
1158 writeEndTag( TABLE_TAG );
1159
1160 writeEndTag( TABLE_CELL_TAG );
1161 writeEndTag( TABLE_ROW_TAG );
1162
1163 writeStartTag( TABLE_ROW_TAG, "height", "0.014in" );
1164 writeStartTag( TABLE_CELL_TAG, "number-columns-spanned", "2" );
1165 writeln( "<fo:block space-after=\"0.2in\" line-height=\"0.014in\">" );
1166 writeEmptyTag( LEADER_TAG, "chapter.rule" );
1167 writeEndTag( BLOCK_TAG );
1168 writeEndTag( TABLE_CELL_TAG );
1169 writeEndTag( TABLE_ROW_TAG );
1170
1171 writeStartTag( TABLE_ROW_TAG );
1172 writeStartTag( TABLE_CELL_TAG, "number-columns-spanned", "2" );
1173 writeSimpleTag( BLOCK_TAG );
1174 writeEmptyTag( BLOCK_TAG, "space-before", "0.2in" );
1175 writeEndTag( TABLE_CELL_TAG );
1176 writeEndTag( TABLE_ROW_TAG );
1177 }
1178
1179 private void writeCoverFooter( DocumentCover cover, DocumentMeta meta )
1180 {
1181 if ( cover == null && meta == null )
1182 {
1183 return;
1184 }
1185
1186 String date = null;
1187 String compName = null;
1188 if ( cover == null )
1189 {
1190
1191 getLog().debug( "The DocumentCover is not defined, using the DocumentMeta author as company name." );
1192 compName = meta.getAuthor();
1193 }
1194 else
1195 {
1196 compName = cover.getCompanyName();
1197
1198 if ( cover.getCoverdate() == null )
1199 {
1200 cover.setCoverDate( new Date() );
1201 date = cover.getCoverdate();
1202 cover.setCoverDate( null );
1203 }
1204 else
1205 {
1206 date = cover.getCoverdate();
1207 }
1208 }
1209
1210 writeStartTag( TABLE_ROW_TAG, "height", "0.3in" );
1211
1212 writeStartTag( TABLE_CELL_TAG );
1213 MutableAttributeSet att = getFoConfiguration().getAttributeSet( "cover.subtitle" );
1214 att.addAttribute( "height", "0.3in" );
1215 att.addAttribute( "text-align", "left" );
1216 writeStartTag( BLOCK_TAG, att );
1217 write( compName == null ? ( cover.getAuthor() == null ? "" : cover.getAuthor() ) : compName );
1218 writeEndTag( BLOCK_TAG );
1219 writeEndTag( TABLE_CELL_TAG );
1220
1221 writeStartTag( TABLE_CELL_TAG );
1222 att = getFoConfiguration().getAttributeSet( "cover.subtitle" );
1223 att.addAttribute( "height", "0.3in" );
1224 att.addAttribute( "text-align", "right" );
1225 writeStartTag( BLOCK_TAG, att );
1226 write( date == null ? "" : date );
1227 writeEndTag( BLOCK_TAG );
1228 writeEndTag( TABLE_CELL_TAG );
1229
1230 writeEndTag( TABLE_ROW_TAG );
1231 }
1232
1233 private ResourceBundle getBundle( Locale locale )
1234 {
1235 return ResourceBundle.getBundle( "doxia-fo", locale, this.getClass().getClassLoader() );
1236 }
1237
1238 private SinkEventAttributeSet getGraphicsAttributes( String logo )
1239 {
1240 MutableAttributeSet atts = null;
1241
1242 try
1243 {
1244 atts = DoxiaUtils.getImageAttributes( logo );
1245 }
1246 catch ( IOException e )
1247 {
1248 getLog().debug( e );
1249 }
1250
1251 if ( atts == null )
1252 {
1253 return new SinkEventAttributeSet( new String[] { SinkEventAttributes.HEIGHT, COVER_HEADER_HEIGHT } );
1254 }
1255
1256
1257
1258 final int maxWidth = 225;
1259
1260 if ( Integer.parseInt( atts.getAttribute( SinkEventAttributes.WIDTH ).toString() ) > maxWidth )
1261 {
1262 atts.addAttribute( "content-width", "3.125in" );
1263 }
1264
1265 return new SinkEventAttributeSet( atts );
1266 }
1267 }