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() ); } /**