View Javadoc

1   package org.apache.maven.doxia.module.twiki;
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 java.io.PrintWriter;
23  import java.io.StringWriter;
24  import java.io.Writer;
25  import java.util.Stack;
26  
27  import javax.swing.text.MutableAttributeSet;
28  import javax.swing.text.html.HTML.Attribute;
29  import javax.swing.text.html.HTML.Tag;
30  
31  import org.apache.maven.doxia.sink.AbstractTextSink;
32  import org.apache.maven.doxia.sink.SinkEventAttributeSet;
33  import org.apache.maven.doxia.sink.SinkEventAttributes;
34  import org.apache.maven.doxia.sink.SinkUtils;
35  import org.apache.maven.doxia.util.HtmlTools;
36  import org.codehaus.plexus.util.StringUtils;
37  
38  /**
39   * TWiki Sink implementation.
40   * <br/>
41   * <b>Note</b>: The encoding used is UTF-8.
42   *
43   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
44   * @version $Id: TWikiSink.java 1090706 2011-04-09 23:15:28Z hboutemy $
45   * @since 1.0
46   */
47  public class TWikiSink
48      extends AbstractTextSink
49      implements TWikiMarkup
50  {
51      /**  The writer to use. */
52      private final PrintWriter out;
53  
54      /**  The writer to use. */
55      private StringWriter writer;
56  
57      /** An indication on if we're in bold mode. */
58      private boolean boldFlag;
59  
60      /** An indication on if we're in bold italic or monospaced mode. */
61      private boolean boldItalicOrMonodpacedFlag;
62  
63      /** An indication on if we're in head mode. */
64      private boolean headFlag;
65  
66      private int levelList = 0;
67  
68      /**  listStyles. */
69      private final Stack<String> listStyles;
70  
71      /**
72       * Constructor, initialize the Writer and the variables.
73       *
74       * @param writer not null writer to write the result. <b>Should</b> be an UTF-8 Writer.
75       * You could use <code>newWriter</code> methods from {@link org.codehaus.plexus.util.WriterFactory}.
76       */
77      protected TWikiSink( Writer writer )
78      {
79          this.out = new PrintWriter( writer );
80          this.listStyles = new Stack<String>();
81  
82          init();
83      }
84  
85      /** {@inheritDoc} */
86      public void anchor( String name )
87      {
88          write( EOL );
89          write( ANCHOR_MARKUP + name );
90      }
91  
92      /** {@inheritDoc} */
93      public void anchor( String name, SinkEventAttributes attributes )
94      {
95          anchor( name );
96      }
97  
98      /**
99       * Not used.
100      * {@inheritDoc}
101      */
102     public void anchor_()
103     {
104         // nop
105     }
106 
107     /**
108      * Not used.
109      * {@inheritDoc}
110      */
111     public void author()
112     {
113         // nop
114     }
115 
116     /** {@inheritDoc} */
117     public void author( SinkEventAttributes attributes )
118     {
119         author();
120     }
121 
122     /**
123      * Not used.
124      * {@inheritDoc}
125      */
126     public void author_()
127     {
128         // nop
129     }
130 
131     /**
132      * Not used.
133      * {@inheritDoc}
134      */
135     public void body()
136     {
137         // nop
138     }
139 
140     /** {@inheritDoc} */
141     public void body( SinkEventAttributes attributes )
142     {
143         body();
144     }
145 
146     /**
147      * Not used.
148      * {@inheritDoc}
149      */
150     public void body_()
151     {
152         // nop
153     }
154 
155     /** {@inheritDoc} */
156     public void bold()
157     {
158         boldFlag = true;
159         write( BOLD_START_MARKUP );
160     }
161 
162     /** {@inheritDoc} */
163     public void bold_()
164     {
165         boldFlag = false;
166         if ( !boldItalicOrMonodpacedFlag )
167         {
168             write( BOLD_END_MARKUP );
169         }
170         boldItalicOrMonodpacedFlag = false;
171     }
172 
173     /**
174      * Not used.
175      * {@inheritDoc}
176      */
177     public void comment( String comment )
178     {
179         // nop
180     }
181 
182     /** {@inheritDoc} */
183     public void close()
184     {
185         out.write( writer.toString() );
186         out.close();
187 
188         init();
189     }
190 
191     /**
192      * Not used.
193      * {@inheritDoc}
194      */
195     public void date()
196     {
197         // nop
198     }
199 
200     /** {@inheritDoc} */
201     public void date( SinkEventAttributes attributes )
202     {
203         date();
204     }
205 
206     /**
207      * Not used.
208      * {@inheritDoc}
209      */
210     public void date_()
211     {
212         // nop
213     }
214 
215     /**
216      * Not used.
217      * {@inheritDoc}
218      */
219     public void definedTerm()
220     {
221         // nop
222     }
223 
224     /** {@inheritDoc} */
225     public void definedTerm( SinkEventAttributes attributes )
226     {
227         definedTerm();
228     }
229 
230     /**
231      * Not used.
232      * {@inheritDoc}
233      */
234     public void definedTerm_()
235     {
236         // nop
237     }
238 
239     /** {@inheritDoc} */
240     public void definition()
241     {
242         write( DEFINITION_LIST_DEFINITION_MARKUP );
243     }
244 
245     /** {@inheritDoc} */
246     public void definition( SinkEventAttributes attributes )
247     {
248         definition();
249     }
250 
251     /** {@inheritDoc} */
252     public void definition_()
253     {
254         writeEOL();
255     }
256 
257     /**
258      * Not used.
259      * {@inheritDoc}
260      */
261     public void definitionList()
262     {
263         // nop
264     }
265 
266     /** {@inheritDoc} */
267     public void definitionList( SinkEventAttributes attributes )
268     {
269         definitionList();
270     }
271 
272     /**
273      * Not used.
274      * {@inheritDoc}
275      */
276     public void definitionList_()
277     {
278         // nop
279     }
280 
281     /** {@inheritDoc} */
282     public void definitionListItem()
283     {
284         write( DEFINITION_LIST_ITEM_MARKUP );
285     }
286 
287     /** {@inheritDoc} */
288     public void definitionListItem( SinkEventAttributes attributes )
289     {
290         definitionListItem();
291     }
292 
293     /**
294      * Not used.
295      * {@inheritDoc}
296      */
297     public void definitionListItem_()
298     {
299         // nop
300     }
301 
302     /** {@inheritDoc} */
303     public void figure()
304     {
305         write( String.valueOf( LESS_THAN ) + Tag.IMG.toString() + SPACE );
306     }
307 
308     /** {@inheritDoc} */
309     public void figure( SinkEventAttributes attributes )
310     {
311         figure();
312     }
313 
314     /**
315      * Not used.
316      * {@inheritDoc}
317      */
318     public void figure_()
319     {
320         write( SLASH + String.valueOf( GREATER_THAN ) );
321     }
322 
323     /**
324      * Not used.
325      * {@inheritDoc}
326      */
327     public void figureCaption()
328     {
329         write( Attribute.ALT.toString() + EQUAL + QUOTE );
330     }
331 
332     /** {@inheritDoc} */
333     public void figureCaption( SinkEventAttributes attributes )
334     {
335         figureCaption();
336     }
337 
338     /**
339      * Not used.
340      * {@inheritDoc}
341      */
342     public void figureCaption_()
343     {
344         write( QUOTE + String.valueOf( SPACE ) );
345     }
346 
347     /** {@inheritDoc} */
348     public void figureGraphics( String name )
349     {
350         write( Attribute.SRC.toString() + EQUAL + QUOTE + name + QUOTE + String.valueOf( SPACE ) );
351     }
352 
353     /** {@inheritDoc} */
354     public void figureGraphics( String src, SinkEventAttributes attributes )
355     {
356         figureGraphics( src );
357     }
358 
359     /** {@inheritDoc} */
360     public void flush()
361     {
362         close();
363         writer.flush();
364     }
365 
366     /** {@inheritDoc} */
367     public void head()
368     {
369         init();
370 
371         headFlag = true;
372     }
373 
374     /** {@inheritDoc} */
375     public void head( SinkEventAttributes attributes )
376     {
377         head();
378     }
379 
380     /** {@inheritDoc} */
381     public void head_()
382     {
383         headFlag = false;
384     }
385 
386     /** {@inheritDoc} */
387     public void horizontalRule()
388     {
389         writeEOL( true );
390         write( HORIZONTAL_RULE_MARKUP );
391         writeEOL( true );
392     }
393 
394     /** {@inheritDoc} */
395     public void horizontalRule( SinkEventAttributes attributes )
396     {
397         horizontalRule();
398     }
399 
400     /** {@inheritDoc} */
401     public void italic()
402     {
403         if ( boldFlag )
404         {
405             boldItalicOrMonodpacedFlag = true;
406 
407             String tmp = writer.toString();
408             writer = new StringWriter();
409             writer.write( tmp.substring( 0, tmp.length() - 1 ) );
410             write( BOLD_ITALIC_START_MARKUP );
411         }
412         else
413         {
414             write( ITALIC_START_MARKUP );
415         }
416     }
417 
418     /** {@inheritDoc} */
419     public void italic_()
420     {
421         if ( boldFlag )
422         {
423             write( BOLD_ITALIC_END_MARKUP );
424         }
425         else
426         {
427             write( ITALIC_END_MARKUP );
428         }
429     }
430 
431     /**
432      * Not used.
433      * {@inheritDoc}
434      */
435     public void lineBreak()
436     {
437         // nop
438     }
439 
440     /** {@inheritDoc} */
441     public void lineBreak( SinkEventAttributes attributes )
442     {
443         lineBreak();
444     }
445 
446     /** {@inheritDoc} */
447     public void link( String name )
448     {
449         write( LINK_START_MARKUP + name + LINK_MIDDLE_MARKUP );
450     }
451 
452     /** {@inheritDoc} */
453     public void link( String name, SinkEventAttributes attributes )
454     {
455         link( name );
456     }
457 
458     /** {@inheritDoc} */
459     public void link_()
460     {
461         write( LINK_END_MARKUP );
462     }
463 
464     /** {@inheritDoc} */
465     public void list()
466     {
467         if ( !writer.toString().endsWith( EOL + EOL ) )
468         {
469             writeEOL( true );
470         }
471 
472         levelList++;
473     }
474 
475     /** {@inheritDoc} */
476     public void list( SinkEventAttributes attributes )
477     {
478         list();
479     }
480 
481     /** {@inheritDoc} */
482     public void list_()
483     {
484         levelList--;
485     }
486 
487     /** {@inheritDoc} */
488     public void listItem()
489     {
490         String indent = StringUtils.repeat( THREE_SPACES_MARKUP, levelList );
491         write( indent + LIST_ITEM_MARKUP );
492     }
493 
494     /** {@inheritDoc} */
495     public void listItem( SinkEventAttributes attributes )
496     {
497         listItem();
498     }
499 
500     /** {@inheritDoc} */
501     public void listItem_()
502     {
503         writeEOL( true );
504     }
505 
506     /** {@inheritDoc} */
507     public void monospaced()
508     {
509         if ( boldFlag )
510         {
511             boldItalicOrMonodpacedFlag = true;
512 
513             String tmp = writer.toString();
514             writer = new StringWriter();
515             writer.write( tmp.substring( 0, tmp.length() - 1 ) );
516             write( BOLD_MONOSPACED_START_MARKUP );
517         }
518         else
519         {
520             write( MONOSPACED_START_MARKUP );
521         }
522     }
523 
524     /** {@inheritDoc} */
525     public void monospaced_()
526     {
527         if ( boldFlag )
528         {
529             write( BOLD_MONOSPACED_END_MARKUP );
530         }
531         else
532         {
533             write( MONOSPACED_END_MARKUP );
534         }
535     }
536 
537     /**
538      * Not used.
539      * {@inheritDoc}
540      */
541     public void nonBreakingSpace()
542     {
543         // nop
544     }
545 
546     /** {@inheritDoc} */
547     public void numberedList( int numbering )
548     {
549         levelList++;
550 
551         String style;
552         switch ( numbering )
553         {
554             case NUMBERING_UPPER_ALPHA:
555                 style = NUMBERING_UPPER_ALPHA_MARKUP;
556                 break;
557             case NUMBERING_LOWER_ALPHA:
558                 style = NUMBERING_LOWER_ALPHA_MARKUP;
559                 break;
560             case NUMBERING_UPPER_ROMAN:
561                 style = NUMBERING_UPPER_ROMAN_MARKUP;
562                 break;
563             case NUMBERING_LOWER_ROMAN:
564                 style = NUMBERING_LOWER_ROMAN_MARKUP;
565                 break;
566             case NUMBERING_DECIMAL:
567             default:
568                 style = NUMBERING_MARKUP;
569         }
570 
571         listStyles.push( style );
572     }
573 
574     /** {@inheritDoc} */
575     public void numberedList( int numbering, SinkEventAttributes attributes )
576     {
577         numberedList( numbering );
578     }
579 
580     /** {@inheritDoc} */
581     public void numberedList_()
582     {
583         levelList--;
584         listStyles.pop();
585     }
586 
587     /** {@inheritDoc} */
588     public void numberedListItem()
589     {
590         writeEOL( true );
591         String style = (String) listStyles.peek();
592         String indent = StringUtils.repeat( THREE_SPACES_MARKUP, levelList );
593         write( indent + style + SPACE );
594     }
595 
596     /** {@inheritDoc} */
597     public void numberedListItem( SinkEventAttributes attributes )
598     {
599         numberedListItem();
600     }
601 
602     /** {@inheritDoc} */
603     public void numberedListItem_()
604     {
605         writeEOL( true );
606     }
607 
608     /**
609      * Not used.
610      * {@inheritDoc}
611      */
612     public void pageBreak()
613     {
614         // nop
615     }
616 
617     /**
618      * Not used.
619      * {@inheritDoc}
620      */
621     public void paragraph()
622     {
623         // nop
624     }
625 
626     /** {@inheritDoc} */
627     public void paragraph( SinkEventAttributes attributes )
628     {
629         paragraph();
630     }
631 
632     /** {@inheritDoc} */
633     public void paragraph_()
634     {
635         writeEOL( true );
636         writeEOL();
637     }
638 
639     /**
640      * Not used.
641      * {@inheritDoc}
642      */
643     public void rawText( String text )
644     {
645         // nop
646     }
647 
648     /**
649      * Not used.
650      * {@inheritDoc}
651      */
652     public void section( int level, SinkEventAttributes attributes )
653     {
654         // nop
655     }
656 
657     /**
658      * Not used.
659      * {@inheritDoc}
660      */
661     public void section1()
662     {
663         // nop
664     }
665 
666     /**
667      * Not used.
668      * {@inheritDoc}
669      */
670     public void section1_()
671     {
672         // nop
673     }
674 
675     /**
676      * Not used.
677      * {@inheritDoc}
678      */
679     public void section2()
680     {
681         // nop
682     }
683 
684     /**
685      * Not used.
686      * {@inheritDoc}
687      */
688     public void section2_()
689     {
690         // nop
691     }
692 
693     /**
694      * Not used.
695      * {@inheritDoc}
696      */
697     public void section3()
698     {
699         // nop
700     }
701 
702     /**
703      * Not used.
704      * {@inheritDoc}
705      */
706     public void section3_()
707     {
708         // nop
709     }
710 
711     /**
712      * Not used.
713      * {@inheritDoc}
714      */
715     public void section4()
716     {
717         // nop
718     }
719 
720     /**
721      * Not used.
722      * {@inheritDoc}
723      */
724     public void section4_()
725     {
726         // nop
727     }
728 
729     /**
730      * Not used.
731      * {@inheritDoc}
732      */
733     public void section5()
734     {
735         // nop
736     }
737 
738     /**
739      * Not used.
740      * {@inheritDoc}
741      */
742     public void section5_()
743     {
744         // nop
745     }
746 
747     /**
748      * Not used.
749      * {@inheritDoc}
750      */
751     public void section_( int level )
752     {
753         // nop
754     }
755 
756     /**
757      * Not used.
758      * {@inheritDoc}
759      */
760     public void sectionTitle()
761     {
762         // nop
763     }
764 
765     /** {@inheritDoc} */
766     public void sectionTitle( int level, SinkEventAttributes attributes )
767     {
768         if ( level > 0 && level < 6 )
769         {
770             write( StringUtils.repeat( "-", 3 ) + StringUtils.repeat( "+", level ) );
771         }
772     }
773 
774     /** {@inheritDoc} */
775     public void sectionTitle1()
776     {
777         sectionTitle( 1, null );
778     }
779 
780     /** {@inheritDoc} */
781     public void sectionTitle1_()
782     {
783         sectionTitle_( 1 );
784     }
785 
786     /** {@inheritDoc} */
787     public void sectionTitle2()
788     {
789         sectionTitle( 2, null );
790     }
791 
792     /** {@inheritDoc} */
793     public void sectionTitle2_()
794     {
795         sectionTitle_( 2 );
796     }
797 
798     /** {@inheritDoc} */
799     public void sectionTitle3()
800     {
801         sectionTitle( 3, null );
802     }
803 
804     /** {@inheritDoc} */
805     public void sectionTitle3_()
806     {
807         sectionTitle_( 3 );
808     }
809 
810     /** {@inheritDoc} */
811     public void sectionTitle4()
812     {
813         sectionTitle( 4, null );
814     }
815 
816     /** {@inheritDoc} */
817     public void sectionTitle4_()
818     {
819         sectionTitle_( 4 );
820     }
821 
822     /** {@inheritDoc} */
823     public void sectionTitle5()
824     {
825         sectionTitle( 5, null );
826     }
827 
828     /** {@inheritDoc} */
829     public void sectionTitle5_()
830     {
831         sectionTitle_( 5 );
832     }
833 
834     /**
835      * Not used.
836      * {@inheritDoc}
837      */
838     public void sectionTitle_()
839     {
840         // nop
841     }
842 
843     /** {@inheritDoc} */
844     public void sectionTitle_( int level )
845     {
846         writeEOL( true );
847         writeEOL();
848     }
849 
850     /**
851      * Not used.
852      * {@inheritDoc}
853      */
854     public void table()
855     {
856         // nop
857     }
858 
859     /** {@inheritDoc} */
860     public void table( SinkEventAttributes attributes )
861     {
862         table();
863     }
864 
865     /**
866      * Not used.
867      * {@inheritDoc}
868      */
869     public void table_()
870     {
871         // nop
872     }
873 
874     /**
875      * Not used.
876      * {@inheritDoc}
877      */
878     public void tableCaption()
879     {
880         // nop
881     }
882 
883     /** {@inheritDoc} */
884     public void tableCaption( SinkEventAttributes attributes )
885     {
886         tableCaption();
887     }
888 
889     /**
890      * Not used.
891      * {@inheritDoc}
892      */
893     public void tableCaption_()
894     {
895         // nop
896     }
897 
898     /** {@inheritDoc} */
899     public void tableCell()
900     {
901         write( " " );
902     }
903 
904     /** {@inheritDoc} */
905     public void tableCell( SinkEventAttributes attributes )
906     {
907         tableCell();
908     }
909 
910     /** {@inheritDoc} */
911     public void tableCell( String width )
912     {
913         tableCell();
914     }
915 
916     /** {@inheritDoc} */
917     public void tableCell_()
918     {
919         write( TABLE_CELL_MARKUP );
920     }
921 
922     /** {@inheritDoc} */
923     public void tableHeaderCell()
924     {
925         write( TABLE_CELL_HEADER_START_MARKUP );
926     }
927 
928     /** {@inheritDoc} */
929     public void tableHeaderCell( SinkEventAttributes attributes )
930     {
931         tableHeaderCell();
932     }
933 
934     /** {@inheritDoc} */
935     public void tableHeaderCell( String width )
936     {
937         tableHeaderCell();
938     }
939 
940     /** {@inheritDoc} */
941     public void tableHeaderCell_()
942     {
943         write( TABLE_CELL_HEADER_END_MARKUP );
944     }
945 
946     /** {@inheritDoc} */
947     public void tableRow()
948     {
949         write( TABLE_ROW_MARKUP );
950     }
951 
952     /** {@inheritDoc} */
953     public void tableRow( SinkEventAttributes attributes )
954     {
955         tableRow();
956     }
957 
958     /** {@inheritDoc} */
959     public void tableRow_()
960     {
961         writeEOL( true );
962     }
963 
964     /**
965      * Not used.
966      * {@inheritDoc}
967      */
968     public void tableRows( int[] justification, boolean grid )
969     {
970         // nop
971     }
972 
973     /**
974      * Not used.
975      * {@inheritDoc}
976      */
977     public void tableRows_()
978     {
979         // nop
980     }
981 
982     /** {@inheritDoc} */
983     public void text( String text )
984     {
985         if ( headFlag )
986         {
987             return;
988         }
989 
990         content( text );
991     }
992 
993     /** {@inheritDoc} */
994     public void text( String text, SinkEventAttributes attributes )
995     {
996         if ( attributes == null )
997         {
998             text( text );
999         }
1000         else
1001         {
1002             if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) )
1003             {
1004                 writeStartTag( Tag.U );
1005             }
1006             if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) )
1007             {
1008                 writeStartTag( Tag.S );
1009             }
1010             if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) )
1011             {
1012                 writeStartTag( Tag.SUB );
1013             }
1014             if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) )
1015             {
1016                 writeStartTag( Tag.SUP );
1017             }
1018 
1019             text( text );
1020 
1021             if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) )
1022             {
1023                 writeEndTag( Tag.SUP );
1024             }
1025             if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) )
1026             {
1027                 writeEndTag( Tag.SUB );
1028             }
1029             if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) )
1030             {
1031                 writeEndTag( Tag.S );
1032             }
1033             if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) )
1034             {
1035                 writeEndTag( Tag.U );
1036             }
1037         }
1038     }
1039 
1040     /**
1041      * Not used.
1042      * {@inheritDoc}
1043      */
1044     public void title()
1045     {
1046         // nop
1047     }
1048 
1049     /** {@inheritDoc} */
1050     public void title( SinkEventAttributes attributes )
1051     {
1052         title();
1053     }
1054 
1055     /**
1056      * Not used.
1057      * {@inheritDoc}
1058      */
1059     public void title_()
1060     {
1061         // nop
1062     }
1063 
1064     /**
1065      * Not used.
1066      * {@inheritDoc}
1067      */
1068     public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes )
1069     {
1070         // nop
1071     }
1072 
1073     /** {@inheritDoc} */
1074     public void verbatim( boolean boxed )
1075     {
1076         SinkEventAttributeSet att = new SinkEventAttributeSet();
1077 
1078         if ( boxed )
1079         {
1080             att.addAttribute( SinkEventAttributes.DECORATION, "boxed" );
1081         }
1082 
1083         verbatim( att );
1084     }
1085 
1086     /** {@inheritDoc} */
1087     public void verbatim( SinkEventAttributes attributes )
1088     {
1089         MutableAttributeSet atts = SinkUtils.filterAttributes( attributes, SinkUtils.SINK_VERBATIM_ATTRIBUTES );
1090 
1091         if ( atts == null )
1092         {
1093             atts = new SinkEventAttributeSet();
1094         }
1095 
1096         boolean boxed = false;
1097 
1098         if ( atts.isDefined( SinkEventAttributes.DECORATION ) )
1099         {
1100             boxed = "boxed".equals( atts.getAttribute( SinkEventAttributes.DECORATION ).toString() );
1101         }
1102 
1103         if ( boxed )
1104         {
1105             atts.addAttribute( Attribute.CLASS, "source" );
1106         }
1107 
1108         atts.removeAttribute( SinkEventAttributes.DECORATION );
1109 
1110         String width = (String) atts.getAttribute( Attribute.WIDTH.toString() );
1111         atts.removeAttribute( Attribute.WIDTH.toString() );
1112 
1113         writeStartTag( Tag.DIV, atts );
1114         writeEOL( true );
1115 
1116         if ( width != null )
1117         {
1118             atts.addAttribute( Attribute.WIDTH.toString(), width );
1119         }
1120 
1121         atts.removeAttribute( Attribute.ALIGN.toString() );
1122         atts.removeAttribute( Attribute.CLASS.toString() );
1123 
1124         writeStartTag( VERBATIM_TAG, atts );
1125     }
1126 
1127     /** {@inheritDoc} */
1128     public void verbatim_()
1129     {
1130         writeEndTag( VERBATIM_TAG );
1131         writeEOL( true );
1132         writeEndTag( Tag.DIV );
1133         writeEOL( true );
1134     }
1135 
1136     // ----------------------------------------------------------------------
1137     // Private methods
1138     // ----------------------------------------------------------------------
1139 
1140     private void write( String text )
1141     {
1142         writer.write( unifyEOLs( text ) );
1143     }
1144 
1145     /**
1146      * Starts a Tag. For instance:
1147      * <pre>
1148      * &lt;tag&gt;
1149      * </pre>
1150      * <br/>
1151      * <b>Note</b>: Copy from {@link AbstractXmlSink#writeStartTag(javax.swing.text.html.HTML.Tag)}
1152      *
1153      * @param t a non null tag
1154      * @see #writeStartTag(javax.swing.text.html.HTML.Tag)
1155      */
1156     private void writeStartTag( Tag t )
1157     {
1158         writeStartTag( t, null );
1159     }
1160 
1161     /**
1162      * Starts a Tag with attributes. For instance:
1163      * <pre>
1164      * &lt;tag attName="attValue"&gt;
1165      * </pre>
1166      * <br/>
1167      * <b>Note</b>: Copy from {@link AbstractXmlSink#writeStartTag(javax.swing.text.html.HTML.Tag,
1168      *      javax.swing.text.MutableAttributeSet)}
1169      *
1170      * @param t a non null tag
1171      * @param att a set of attributes
1172      * @see #writeStartTag(javax.swing.text.html.HTML.Tag, javax.swing.text.MutableAttributeSet, boolean)
1173      */
1174     private void writeStartTag( Tag t, MutableAttributeSet att )
1175     {
1176         writeStartTag( t, att, false );
1177     }
1178 
1179     /**
1180      * Starts a Tag with attributes. For instance:
1181      * <pre>
1182      * &lt;tag attName="attValue"&gt;
1183      * </pre>
1184      * <br/>
1185      * <b>Note</b>: Copy from {@link AbstractXmlSink#writeStartTag(javax.swing.text.html.HTML.Tag,
1186      *      javax.swing.text.MutableAttributeSet, boolean)}
1187      *
1188      * @param t a non null tag
1189      * @param att a set of attributes
1190      * @param isSimpleTag boolean to write as a simple tag
1191      */
1192     private void writeStartTag( Tag t, MutableAttributeSet att, boolean isSimpleTag )
1193     {
1194         if ( t == null )
1195         {
1196             throw new IllegalArgumentException( "A tag is required" );
1197         }
1198 
1199         StringBuffer sb = new StringBuffer();
1200         sb.append( LESS_THAN );
1201 
1202         sb.append( t.toString() );
1203 
1204         sb.append( SinkUtils.getAttributeString( att ) );
1205 
1206         if ( isSimpleTag )
1207         {
1208             sb.append( SPACE ).append( SLASH );
1209         }
1210 
1211         sb.append( GREATER_THAN );
1212 
1213         write( sb.toString() );
1214     }
1215 
1216     /**
1217      * Writes a system EOL.
1218      */
1219     private void writeEOL()
1220     {
1221         write( EOL );
1222     }
1223 
1224     /**
1225      * Writes a system EOL, with or without trim.
1226      */
1227     private void writeEOL( boolean trim )
1228     {
1229         if ( !trim )
1230         {
1231             writeEOL();
1232             return;
1233         }
1234 
1235         String tmp = writer.toString().trim();
1236         writer = new StringWriter();
1237         writer.write( tmp );
1238         write( EOL );
1239     }
1240 
1241     /**
1242      * Ends a Tag without writing an EOL. For instance: <pre>&lt;/tag&gt;</pre>.
1243      * <br/>
1244      * <b>Note</b>: Copy from {@link AbstractXmlSink#writeEndTag(javax.swing.text.html.HTML.Tag)}
1245      *
1246      * @param t a tag.
1247      */
1248     private void writeEndTag( Tag t )
1249     {
1250         StringBuffer sb = new StringBuffer();
1251         sb.append( LESS_THAN );
1252         sb.append( SLASH );
1253 
1254         sb.append( t.toString() );
1255         sb.append( GREATER_THAN );
1256 
1257         write( sb.toString() );
1258     }
1259 
1260     /**
1261      * Write HTML escaped text to output.
1262      *
1263      * @param text The text to write.
1264      */
1265     protected void content( String text )
1266     {
1267         write( escapeHTML( text ) );
1268     }
1269 
1270     /** {@inheritDoc} */
1271     protected void init()
1272     {
1273         super.init();
1274 
1275         this.writer = new StringWriter();
1276         this.headFlag = false;
1277         this.levelList = 0;
1278         this.listStyles.clear();
1279         this.boldFlag = false;
1280         this.boldItalicOrMonodpacedFlag = false;
1281     }
1282 
1283     /**
1284      * Forward to HtmlTools.escapeHTML( text ).
1285      *
1286      * @param text the String to escape, may be null
1287      * @return the text escaped, "" if null String input
1288      * @see org.apache.maven.doxia.util.HtmlTools#escapeHTML(String)
1289      */
1290     protected static String escapeHTML( String text )
1291     {
1292         return HtmlTools.escapeHTML( text );
1293     }
1294 }