You are viewing a plain text version of this content. The canonical link for it is here.
Posted to doxia-commits@maven.apache.org by vs...@apache.org on 2009/08/21 13:58:39 UTC

svn commit: r806515 - in /maven/doxia/doxia/trunk/doxia-core/src: main/java/org/apache/maven/doxia/sink/XhtmlBaseSink.java test/java/org/apache/maven/doxia/sink/XhtmlBaseSinkTest.java

Author: vsiveton
Date: Fri Aug 21 11:58:39 2009
New Revision: 806515

URL: http://svn.apache.org/viewvc?rev=806515&view=rev
Log:
o be sure that nested tables are correctly handle
o improved also table caption (DOXIA-177)

Modified:
    maven/doxia/doxia/trunk/doxia-core/src/main/java/org/apache/maven/doxia/sink/XhtmlBaseSink.java
    maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/sink/XhtmlBaseSinkTest.java

Modified: maven/doxia/doxia/trunk/doxia-core/src/main/java/org/apache/maven/doxia/sink/XhtmlBaseSink.java
URL: http://svn.apache.org/viewvc/maven/doxia/doxia/trunk/doxia-core/src/main/java/org/apache/maven/doxia/sink/XhtmlBaseSink.java?rev=806515&r1=806514&r2=806515&view=diff
==============================================================================
--- maven/doxia/doxia/trunk/doxia-core/src/main/java/org/apache/maven/doxia/sink/XhtmlBaseSink.java (original)
+++ maven/doxia/doxia/trunk/doxia-core/src/main/java/org/apache/maven/doxia/sink/XhtmlBaseSink.java Fri Aug 21 11:58:39 2009
@@ -25,6 +25,7 @@
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
@@ -39,6 +40,7 @@
 import org.apache.maven.doxia.util.HtmlTools;
 
 import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
 
 /**
  * Abstract base xhtml sink implementation.
@@ -59,10 +61,6 @@
     /** The PrintWriter to write the result. */
     private PrintWriter writer;
 
-    /** The StringWriter to write the result temporary, so we could play with the output and fix XHTML
-     * like DOXIA-177. Calling the method {@link #close()} is needed to perform the changes in the {@link #writer}. */
-    private StringWriter tempWriter;
-
     /** Used to collect text events mainly for the head events. */
     private StringBuffer textBuffer = new StringBuffer();
 
@@ -78,18 +76,28 @@
     /** An indication on if we're in verbatim mode. */
     private boolean verbatimFlag;
 
-    /** Alignment of table cells. */
-    private int[] cellJustif;
+    /** Stack of alignment int[] of table cells. */
+    private final LinkedList cellJustifStack;
 
-    /** Justification of table cells. */
-    private boolean isCellJustif;
+    /** Stack of justification of table cells. */
+    private final LinkedList isCellJustifStack;
 
-    /** Number of cells in a table row. */
-    private int cellCount;
+    /** Stack of current table cell. */
+    private final LinkedList cellCountStack;
 
     /** Used to style successive table rows differently. */
     private boolean evenTableRow = true;
 
+    /** The stack of StringWriter to write the table result temporary, so we could play with the output DOXIA-177. */
+    private final LinkedList tableContentWriterStack;
+
+    private final LinkedList tableCaptionWriterStack;
+
+    private final LinkedList tableCaptionXMLWriterStack;
+
+    /** The stack of table caption */
+    private final LinkedList tableCaptionStack;
+
     /** used to store attributes passed to table(). */
     protected MutableAttributeSet tableAttributes;
 
@@ -133,7 +141,14 @@
     public XhtmlBaseSink( Writer out )
     {
         this.writer = new PrintWriter( out );
-        this.tempWriter = new StringWriter();
+
+        this.cellJustifStack = new LinkedList();
+        this.isCellJustifStack = new LinkedList();
+        this.cellCountStack = new LinkedList();
+        this.tableContentWriterStack = new LinkedList();
+        this.tableCaptionWriterStack = new LinkedList();
+        this.tableCaptionXMLWriterStack = new LinkedList();
+        this.tableCaptionStack = new LinkedList();
     }
 
     // ----------------------------------------------------------------------
@@ -197,8 +212,8 @@
      */
     protected void setCellJustif( int[] justif )
     {
-        this.cellJustif = justif;
-        this.isCellJustif = true;
+        this.cellJustifStack.addLast( justif );
+        this.isCellJustifStack.addLast( Boolean.TRUE );
     }
 
     /**
@@ -208,7 +223,7 @@
      */
     protected int[] getCellJustif()
     {
-        return this.cellJustif ;
+        return (int[])this.cellJustifStack.getLast();
     }
 
     /**
@@ -218,7 +233,7 @@
      */
     protected void setCellCount( int count )
     {
-        this.cellCount = count;
+        this.cellCountStack.addLast( Integer.valueOf( count ) );
     }
 
     /**
@@ -228,7 +243,7 @@
      */
     protected int getCellCount()
     {
-        return this.cellCount ;
+        return Integer.parseInt( this.cellCountStack.getLast().toString() );
     }
 
     /**
@@ -239,9 +254,9 @@
         resetTextBuffer();
         headFlag = false;
         verbatimFlag = false;
-        cellJustif = null;
-        isCellJustif = false;
-        cellCount = 0;
+        cellJustifStack.clear();
+        isCellJustifStack.clear();
+        cellCountStack.clear();
         evenTableRow = true;
     }
 
@@ -1091,6 +1106,7 @@
     /** {@inheritDoc} */
     public void table( SinkEventAttributes attributes )
     {
+        this.tableContentWriterStack.addLast( new StringWriter() );
         this.tableRows = false;
 
         if ( paragraphFlag )
@@ -1102,7 +1118,7 @@
         }
 
         // start table with tableRows
-        if ( attributes == null )
+        if ( this.tableAttributes == null )
         {
             this.tableAttributes = new SinkEventAttributeSet( 0 );
         }
@@ -1123,49 +1139,41 @@
 
         writeEndTag( HtmlMarkup.TABLE );
 
-        String content = tempWriter.toString();
-
-        String startTable =
-            new StringBuffer().append( Markup.LESS_THAN ).append( HtmlMarkup.TABLE.toString() ).toString();
-
-        if ( content.lastIndexOf( startTable ) == -1 )
+        if ( this.tableContentWriterStack.isEmpty() )
         {
-            if ( getLog().isDebugEnabled() )
+            if ( getLog().isWarnEnabled() )
             {
-                getLog().debug( "table() NOT call firstly" );
+                getLog().warn( "No table content." );
             }
             return;
         }
 
-        content = content.substring( content.lastIndexOf( startTable ) );
+        String tableContent = this.tableContentWriterStack.removeLast().toString();
 
-        String startCaption =
-            new StringBuffer().append( Markup.LESS_THAN ).append( HtmlMarkup.CAPTION.toString() )
-                              .append( Markup.GREATER_THAN ).toString();
-        String endCaption =
-            new StringBuffer().append( Markup.LESS_THAN ).append( Markup.SLASH ).append( HtmlMarkup.CAPTION.toString() )
-                              .append( Markup.GREATER_THAN ).toString();
+        String tableCaption = null;
+        if ( !this.tableCaptionStack.isEmpty() && this.tableCaptionStack.getLast() != null )
+        {
+            tableCaption = this.tableCaptionStack.removeLast().toString();
+        }
 
-        if ( content.indexOf( startCaption ) != -1 && content.indexOf( endCaption ) != -1 )
+        if ( tableCaption != null )
         {
             // DOXIA-177
-            int iStartCaption = content.indexOf( startCaption );
-            int iEndCaption = content.indexOf( endCaption ) + endCaption.length();
-
-            String captionTag = content.substring( iStartCaption, iEndCaption );
-            String contentWithoutCaption = StringUtils.replace( content, captionTag, "" );
+            StringBuffer sb = new StringBuffer();
+            sb.append( tableContent.substring( 0, tableContent.indexOf( Markup.GREATER_THAN ) + 1 ) );
+            sb.append( tableCaption );
+            sb.append( tableContent.substring( tableContent.indexOf( Markup.GREATER_THAN ) + 1 ) );
 
-            String startTr =
-                new StringBuffer().append( Markup.LESS_THAN ).append( HtmlMarkup.TR.toString() ).toString();
+            write( sb.toString() );
+        }
+        else
+        {
+            write( tableContent );
+        }
 
-            StringBuffer text = new StringBuffer();
-            text.append( contentWithoutCaption.substring( 0, contentWithoutCaption.indexOf( startTr ) ) );
-            text.append( captionTag );
-            text.append( contentWithoutCaption.substring( contentWithoutCaption.indexOf( startTr ) ) );
-
-            String contentWithCaption = tempWriter.toString();
-            tempWriter = new StringWriter();
-            tempWriter.write( StringUtils.replace( contentWithCaption, content, text.toString() ) );
+        if ( !this.cellCountStack.isEmpty() )
+        {
+            this.cellCountStack.removeLast().toString();
         }
     }
 
@@ -1188,35 +1196,41 @@
         }
 
         MutableAttributeSet att = new SinkEventAttributeSet();
-
-        if ( !tableAttributes.isDefined( Attribute.ALIGN.toString() ) )
+        if ( !this.tableAttributes.isDefined( Attribute.ALIGN.toString() ) )
         {
             att.addAttribute( Attribute.ALIGN, "center" );
         }
 
-        if ( !tableAttributes.isDefined( Attribute.BORDER.toString() ) )
+        if ( !this.tableAttributes.isDefined( Attribute.BORDER.toString() ) )
         {
             att.addAttribute( Attribute.BORDER, ( grid ? "1" : "0" ) );
         }
 
-        if ( !tableAttributes.isDefined( Attribute.CLASS.toString() ) )
+        if ( !this.tableAttributes.isDefined( Attribute.CLASS.toString() ) )
         {
             att.addAttribute( Attribute.CLASS, "bodyTable" );
         }
 
-        att.addAttributes( tableAttributes );
-
-        tableAttributes.removeAttributes( tableAttributes );
+        att.addAttributes( this.tableAttributes );
+        this.tableAttributes.removeAttributes( this.tableAttributes );
 
         writeStartTag( HtmlMarkup.TABLE, att );
+
+        this.cellCountStack.addLast( new Integer( 0 ) );
     }
 
     /** {@inheritDoc} */
     public void tableRows_()
     {
         this.tableRows = false;
-        this.cellJustif = null;
-        this.isCellJustif = false;
+        if ( !this.cellJustifStack.isEmpty() )
+        {
+            this.cellJustifStack.removeLast();
+        }
+        if ( !this.isCellJustifStack.isEmpty() )
+        {
+            this.isCellJustifStack.removeLast();
+        }
 
         this.evenTableRow = true;
     }
@@ -1263,7 +1277,11 @@
 
         evenTableRow = !evenTableRow;
 
-        cellCount = 0;
+        if ( !this.cellCountStack.isEmpty() )
+        {
+            this.cellCountStack.removeLast();
+            this.cellCountStack.addLast( new Integer( 0 ) );
+        }
     }
 
     /**
@@ -1273,8 +1291,6 @@
     public void tableRow_()
     {
         writeEndTag( HtmlMarkup.TR );
-
-        cellCount = 0;
     }
 
     /** {@inheritDoc} */
@@ -1342,19 +1358,25 @@
             justif = attributes.getAttribute( Attribute.ALIGN.toString() ).toString();
         }
 
-        if ( justif == null && cellJustif != null && cellJustif.length > 0 && isCellJustif )
+        if ( !this.cellCountStack.isEmpty() )
         {
-            switch ( cellJustif[Math.min( cellCount, cellJustif.length - 1 )] )
+            int cellCount = Integer.parseInt( this.cellCountStack.getLast().toString() );
+            int[] cellJustif = (int[]) this.cellJustifStack.getLast();
+            if ( justif == null && cellJustif != null && cellJustif.length > 0
+                && this.isCellJustifStack.getLast().equals( Boolean.TRUE ) )
             {
-                case JUSTIFY_LEFT:
-                    justif = "left";
-                    break;
-                case JUSTIFY_RIGHT:
-                    justif = "right";
-                    break;
-                case JUSTIFY_CENTER:
-                default:
-                    justif = "center";
+                switch ( cellJustif[Math.min( cellCount, cellJustif.length - 1 )] )
+                {
+                    case JUSTIFY_LEFT:
+                        justif = "left";
+                        break;
+                    case JUSTIFY_RIGHT:
+                        justif = "right";
+                        break;
+                    case JUSTIFY_CENTER:
+                    default:
+                        justif = "center";
+                }
             }
         }
 
@@ -1394,9 +1416,11 @@
 
         writeEndTag( t );
 
-        if ( isCellJustif )
+        if ( !this.isCellJustifStack.isEmpty() && this.isCellJustifStack.getLast().equals( Boolean.TRUE )
+            && !this.cellCountStack.isEmpty() )
         {
-            ++cellCount;
+            int cellCount = Integer.parseInt( this.cellCountStack.removeLast().toString() );
+            this.cellCountStack.addLast( new Integer( ++cellCount ) );
         }
     }
 
@@ -1415,6 +1439,10 @@
      */
     public void tableCaption( SinkEventAttributes attributes )
     {
+        StringWriter sw = new StringWriter();
+        this.tableCaptionWriterStack.addLast( sw );
+        this.tableCaptionXMLWriterStack.addLast( new PrettyPrintXMLWriter( sw ) );
+
         // TODO: tableCaption should be written before tableRows (DOXIA-177)
         MutableAttributeSet atts = SinkUtils.filterAttributes(
                 attributes, SinkUtils.SINK_SECTION_ATTRIBUTES  );
@@ -1429,6 +1457,12 @@
     public void tableCaption_()
     {
         writeEndTag( HtmlMarkup.CAPTION );
+
+        if ( !this.tableCaptionXMLWriterStack.isEmpty() && this.tableCaptionXMLWriterStack.getLast() != null )
+        {
+            this.tableCaptionStack.addLast( this.tableCaptionWriterStack.removeLast().toString() );
+            this.tableCaptionXMLWriterStack.removeLast();
+        }
     }
 
     /**
@@ -1877,8 +1911,6 @@
     /** {@inheritDoc} */
     public void close()
     {
-        writer.write( tempWriter.toString() );
-        tempWriter = new StringWriter();
         writer.close();
 
         if ( getLog().isWarnEnabled() && this.warnMessages != null )
@@ -1955,7 +1987,62 @@
     /** {@inheritDoc} */
     protected void write( String text )
     {
-        tempWriter.write( unifyEOLs( text ) );
+        if ( !this.tableCaptionXMLWriterStack.isEmpty() && this.tableCaptionXMLWriterStack.getLast() != null )
+        {
+            ( (PrettyPrintXMLWriter) this.tableCaptionXMLWriterStack.getLast() ).writeText( unifyEOLs( text ) );
+        }
+        else if ( !this.tableContentWriterStack.isEmpty() && this.tableContentWriterStack.getLast() != null )
+        {
+            ( (StringWriter) this.tableContentWriterStack.getLast() ).write( unifyEOLs( text ) );
+        }
+        else
+        {
+            writer.write( unifyEOLs( text ) );
+        }
+    }
+
+    /** {@inheritDoc} */
+    protected void writeStartTag( Tag t, MutableAttributeSet att, boolean isSimpleTag )
+    {
+        if ( this.tableCaptionXMLWriterStack.isEmpty() )
+        {
+            super.writeStartTag ( t, att, isSimpleTag );
+        }
+        else
+        {
+            String tag = ( getNameSpace() != null ? getNameSpace() + ":" : "" ) + t.toString();
+            ( (PrettyPrintXMLWriter) this.tableCaptionXMLWriterStack.getLast() ).startElement( tag );
+
+            if ( att != null )
+            {
+                Enumeration names = att.getAttributeNames();
+                while ( names.hasMoreElements() )
+                {
+                    Object key = names.nextElement();
+                    Object value = att.getAttribute( key );
+
+                    ( (PrettyPrintXMLWriter) this.tableCaptionXMLWriterStack.getLast() ).addAttribute( key.toString(), value.toString() );
+                }
+            }
+
+            if ( isSimpleTag )
+            {
+                ( (PrettyPrintXMLWriter) this.tableCaptionXMLWriterStack.getLast() ).endElement();
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    protected void writeEndTag( Tag t )
+    {
+        if ( this.tableCaptionXMLWriterStack.isEmpty() )
+        {
+            super.writeEndTag( t );
+        }
+        else
+        {
+            ( (PrettyPrintXMLWriter) this.tableCaptionXMLWriterStack.getLast() ).endElement();
+        }
     }
 
     /**

Modified: maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/sink/XhtmlBaseSinkTest.java
URL: http://svn.apache.org/viewvc/maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/sink/XhtmlBaseSinkTest.java?rev=806515&r1=806514&r2=806515&view=diff
==============================================================================
--- maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/sink/XhtmlBaseSinkTest.java (original)
+++ maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/sink/XhtmlBaseSinkTest.java Fri Aug 21 11:58:39 2009
@@ -82,28 +82,70 @@
         assertEquals( expected, actual );
     }
 
-    /** @throws Exception */
+    /**
+     * @throws Exception if any
+     */
     public void testNestedTables()
         throws Exception
     {
         // DOXIA-177
-
         try
         {
             sink = new XhtmlBaseSink( writer );
 
             sink.table();
-            sink.tableRows( new int[] {0}, false );
-            sink.tableCaption();
-            sink.text( "caption1" );
-            sink.tableCaption_();
+            sink.tableRows( new int[] { Sink.JUSTIFY_CENTER }, false );
             sink.tableRow();
             sink.tableCell();
-            sink.table();
-            sink.tableRows( new int[] {0}, false );
+            sink.text( "cell11" );
+            sink.tableCell_();
+            sink.tableCell();
+            sink.text( "cell12" );
+            sink.tableCell_();
+            sink.tableRow_();
+
             sink.tableRow();
             sink.tableCell();
-            sink.text( "nestedTableCell" );
+            sink.table( SinkEventAttributeSet.LEFT );
+            sink.tableRows( new int[] { Sink.JUSTIFY_LEFT }, false );
+            sink.tableRow();
+            sink.tableCell();
+            sink.text( "nestedTable1Cell11" );
+            sink.tableCell_();
+            sink.tableCell();
+            sink.text( "nestedTable1Cell12" );
+            sink.tableCell_();
+            sink.tableRow_();
+            sink.tableRow();
+            sink.tableCell();
+
+            sink.table( SinkEventAttributeSet.RIGHT );
+            sink.tableRows( new int[] { Sink.JUSTIFY_RIGHT }, false );
+            sink.tableRow();
+            sink.tableCell();
+            sink.text( "nestedTable2Cell11" );
+            sink.tableCell_();
+            sink.tableCell();
+            sink.text( "nestedTable2Cell12" );
+            sink.tableCell_();
+            sink.tableRow_();
+            sink.tableRow();
+            sink.tableCell();
+            sink.text( "nestedTable2Cell21" );
+            sink.tableCell_();
+            sink.tableCell();
+            sink.text( "nestedTable2Cell22" );
+            sink.tableCell_();
+            sink.tableRow_();
+            sink.tableRows_();
+            sink.tableCaption();
+            sink.text( "caption3" );
+            sink.tableCaption_();
+            sink.table_();
+
+            sink.tableCell_();
+            sink.tableCell();
+            sink.text( "nestedTable1Cell22" );
             sink.tableCell_();
             sink.tableRow_();
             sink.tableRows_();
@@ -111,9 +153,16 @@
             sink.text( "caption2" );
             sink.tableCaption_();
             sink.table_();
+
+            sink.tableCell_();
+            sink.tableCell();
+            sink.text( "cell22" );
             sink.tableCell_();
             sink.tableRow_();
             sink.tableRows_();
+            sink.tableCaption();
+            sink.text( "caption1" );
+            sink.tableCaption_();
             sink.table_();
         }
         finally
@@ -122,9 +171,18 @@
         }
 
         String actual = writer.toString();
-        assertTrue( actual.indexOf( "nestedTableCell" ) != 1 );
-        assertTrue( actual.indexOf( "class=\"bodyTable\"><caption>caption1</caption><tr" ) != 1 );
-        assertTrue( actual.indexOf( "class=\"bodyTable\"><caption>caption2</caption><tr" ) != 1 );
+        assertTrue( actual.indexOf( "<table align=\"center\" border=\"0\" class=\"bodyTable\">"
+            + "<caption>caption1</caption>" ) != 1 );
+        assertTrue( actual.indexOf( "<table border=\"0\" class=\"bodyTable\" align=\"left\">"
+            + "<caption>caption2</caption>" ) != 1 );
+        assertTrue( actual.indexOf( "<table align=\"center\" border=\"0\" class=\"bodyTable\">"
+            + "<caption>caption3</caption>" ) != 1 );
+
+        assertTrue( actual.indexOf( "<td align=\"center\">cell11</td>" ) != 1 );
+        assertTrue( actual.indexOf( "<td align=\"left\">nestedTable1Cell11</td>" ) != 1 );
+        assertTrue( actual.indexOf( "<td align=\"right\">nestedTable2Cell11</td>" ) != 1 );
+        assertTrue( actual.indexOf( "<td align=\"left\">nestedTable1Cell22</td>" ) != 1 );
+        assertTrue( actual.indexOf( "<td align=\"center\">cell22</td>" ) != 1 );
     }
 
     /**
@@ -643,15 +701,21 @@
         {
             sink = new XhtmlBaseSink( writer );
 
+            sink.table();
+            sink.tableRows( null, false );
             sink.tableCaption( attributes );
+            sink.text( "caption" );
             sink.tableCaption_();
+            sink.tableRows_();
+            sink.table_();
         }
         finally
         {
             sink.close();
         }
 
-        assertEquals( "<caption style=\"bold\"></caption>", writer.toString() );
+        assertEquals( "<table align=\"center\" border=\"0\" class=\"bodyTable\">" +
+                "<caption style=\"bold\">caption</caption></table>", writer.toString() );
     }
 
     /**