Fix table processing. Spanned columns / different width / spanned rows are correcly rendered in HTML and FO now

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1149593 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Sergey Vladimirov 2011-07-22 12:49:29 +00:00
parent e86ef4f8bf
commit 7cbdf296fb
3 changed files with 139 additions and 103 deletions

View File

@ -41,6 +41,8 @@ import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.hwpf.usermodel.Range; import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.hwpf.usermodel.Section; import org.apache.poi.hwpf.usermodel.Section;
import org.apache.poi.hwpf.usermodel.Table; import org.apache.poi.hwpf.usermodel.Table;
import org.apache.poi.hwpf.usermodel.TableCell;
import org.apache.poi.hwpf.usermodel.TableRow;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -86,6 +88,68 @@ public abstract class AbstractWordConverter
return fontReplacer; return fontReplacer;
} }
protected int getNumberColumnsSpanned( int[] tableCellEdges,
int currentEdgeIndex, TableCell tableCell )
{
int nextEdgeIndex = currentEdgeIndex;
int colSpan = 0;
int cellRightEdge = tableCell.getLeftEdge() + tableCell.getWidth();
while ( tableCellEdges[nextEdgeIndex] < cellRightEdge )
{
colSpan++;
nextEdgeIndex++;
}
return colSpan;
}
protected int getNumberRowsSpanned( Table table, int currentRowIndex,
int currentColumnIndex, TableCell tableCell )
{
if ( !tableCell.isFirstVerticallyMerged() )
return 1;
final int numRows = table.numRows();
int count = 1;
for ( int r1 = currentRowIndex + 1; r1 < numRows; r1++ )
{
TableRow nextRow = table.getRow( r1 );
if ( nextRow.numCells() < currentColumnIndex )
break;
TableCell nextCell = nextRow.getCell( currentColumnIndex );
if ( !nextCell.isVerticallyMerged()
|| nextCell.isFirstVerticallyMerged() )
break;
count++;
}
return count;
}
protected int getTableCellEdgesIndexSkipCount( Table table, int r,
int[] tableCellEdges, int currentEdgeIndex, int c,
TableCell tableCell )
{
TableCell upperCell = null;
for ( int r1 = r - 1; r1 >= 0; r1-- )
{
final TableCell prevCell = table.getRow( r1 ).getCell( c );
if ( prevCell != null && prevCell.isFirstVerticallyMerged() )
{
upperCell = prevCell;
break;
}
}
if ( upperCell == null )
{
logger.log( POILogger.WARN, "First vertically merged cell for ",
tableCell, " not found" );
return 0;
}
return getNumberColumnsSpanned( tableCellEdges, currentEdgeIndex,
tableCell );
}
protected abstract void outputCharacters( Element block, protected abstract void outputCharacters( Element block,
CharacterRun characterRun, String text ); CharacterRun characterRun, String text );
@ -211,7 +275,7 @@ public abstract class AbstractWordConverter
} }
if ( text.endsWith( "\r" ) if ( text.endsWith( "\r" )
|| ( text.charAt( text.length() - 1 ) == BEL_MARK && currentTableLevel != 0 ) ) || ( text.charAt( text.length() - 1 ) == BEL_MARK && currentTableLevel != Integer.MIN_VALUE ) )
text = text.substring( 0, text.length() - 1 ); text = text.substring( 0, text.length() - 1 );
{ {
@ -239,7 +303,8 @@ public abstract class AbstractWordConverter
// Non-required hyphens to zero-width space // Non-required hyphens to zero-width space
stringBuilder.append( UNICODECHAR_ZERO_WIDTH_SPACE ); stringBuilder.append( UNICODECHAR_ZERO_WIDTH_SPACE );
} }
else else if ( charChar > 0x20 || charChar == 0x09
|| charChar == 0x0A || charChar == 0x0D )
{ {
stringBuilder.append( charChar ); stringBuilder.append( charChar );
} }

View File

@ -54,6 +54,28 @@ import org.w3c.dom.Text;
public class WordToFoConverter extends AbstractWordConverter public class WordToFoConverter extends AbstractWordConverter
{ {
/**
* Holds properties values, applied to current <tt>fo:block</tt> element.
* Those properties shall not be doubled in children <tt>fo:inline</tt>
* elements.
*/
private static class BlockProperies
{
final boolean pBold;
final String pFontName;
final int pFontSize;
final boolean pItalic;
public BlockProperies( String pFontName, int pFontSize, boolean pBold,
boolean pItalic )
{
this.pFontName = pFontName;
this.pFontSize = pFontSize;
this.pBold = pBold;
this.pItalic = pItalic;
}
}
private static final POILogger logger = POILogFactory private static final POILogger logger = POILogFactory
.getLogger( WordToFoConverter.class ); .getLogger( WordToFoConverter.class );
@ -513,26 +535,22 @@ public class WordToFoConverter extends AbstractWordConverter
{ {
TableCell tableCell = tableRow.getCell( c ); TableCell tableCell = tableRow.getCell( c );
if ( tableCell.isMerged() && !tableCell.isFirstMerged() )
continue;
if ( tableCell.isVerticallyMerged() if ( tableCell.isVerticallyMerged()
&& !tableCell.isFirstVerticallyMerged() ) && !tableCell.isFirstVerticallyMerged() )
{
currentEdgeIndex += getTableCellEdgesIndexSkipCount( table,
r, tableCellEdges, currentEdgeIndex, c, tableCell );
continue; continue;
}
Element tableCellElement = foDocumentFacade.createTableCell(); Element tableCellElement = foDocumentFacade.createTableCell();
WordToFoUtils.setTableCellProperties( tableRow, tableCell, WordToFoUtils.setTableCellProperties( tableRow, tableCell,
tableCellElement, r == 0, r == tableRows - 1, c == 0, tableCellElement, r == 0, r == tableRows - 1, c == 0,
c == rowCells - 1 ); c == rowCells - 1 );
int colSpan = 0; int colSpan = getNumberColumnsSpanned( tableCellEdges,
int cellRightEdge = tableCell.getLeftEdge() currentEdgeIndex, tableCell );
+ tableCell.getWidth(); currentEdgeIndex += colSpan;
while ( tableCellEdges[currentEdgeIndex] < cellRightEdge )
{
colSpan++;
currentEdgeIndex++;
}
if ( colSpan == 0 ) if ( colSpan == 0 )
continue; continue;
@ -541,24 +559,11 @@ public class WordToFoConverter extends AbstractWordConverter
tableCellElement.setAttribute( "number-columns-spanned", tableCellElement.setAttribute( "number-columns-spanned",
String.valueOf( colSpan ) ); String.valueOf( colSpan ) );
if ( tableCell.isFirstVerticallyMerged() ) final int rowSpan = getNumberRowsSpanned( table, r, c,
{ tableCell );
int count = 0; if ( rowSpan > 1 )
for ( int r1 = r; r1 < tableRows; r1++ ) tableCellElement.setAttribute( "number-rows-spanned",
{ String.valueOf( rowSpan ) );
TableRow nextRow = table.getRow( r1 );
if ( nextRow.numCells() < c )
break;
TableCell nextCell = nextRow.getCell( c );
if ( nextCell.isVerticallyMerged() )
count++;
if ( !nextCell.isVerticallyMerged() )
break;
}
if ( count > 1 )
tableCellElement.setAttribute( "number-rows-spanned",
String.valueOf( count ) );
}
processParagraphes( wordDocument, tableCellElement, tableCell, processParagraphes( wordDocument, tableCellElement, tableCell,
table.getTableLevel() ); table.getTableLevel() );
@ -572,17 +577,21 @@ public class WordToFoConverter extends AbstractWordConverter
tableRowElement.appendChild( tableCellElement ); tableRowElement.appendChild( tableCellElement );
} }
if ( tableRow.isTableHeader() ) if ( tableRowElement.hasChildNodes() )
{ {
tableHeader.appendChild( tableRowElement ); if ( tableRow.isTableHeader() )
} {
else tableHeader.appendChild( tableRowElement );
{ }
tableBody.appendChild( tableRowElement ); else
{
tableBody.appendChild( tableRowElement );
}
} }
} }
final Element tableElement = foDocumentFacade.createTable(); final Element tableElement = foDocumentFacade.createTable();
tableElement.setAttribute( "table-layout", "fixed" );
if ( tableHeader.hasChildNodes() ) if ( tableHeader.hasChildNodes() )
{ {
tableElement.appendChild( tableHeader ); tableElement.appendChild( tableHeader );
@ -602,26 +611,4 @@ public class WordToFoConverter extends AbstractWordConverter
} }
} }
/**
* Holds properties values, applied to current <tt>fo:block</tt> element.
* Those properties shall not be doubled in children <tt>fo:inline</tt>
* elements.
*/
private static class BlockProperies
{
final boolean pBold;
final String pFontName;
final int pFontSize;
final boolean pItalic;
public BlockProperies( String pFontName, int pFontSize, boolean pBold,
boolean pItalic )
{
this.pFontName = pFontName;
this.pFontSize = pFontSize;
this.pBold = pBold;
this.pItalic = pItalic;
}
}
} }

View File

@ -61,6 +61,22 @@ import static org.apache.poi.hwpf.converter.AbstractWordUtils.TWIPS_PER_INCH;
public class WordToHtmlConverter extends AbstractWordConverter public class WordToHtmlConverter extends AbstractWordConverter
{ {
/**
* Holds properties values, applied to current <tt>p</tt> element. Those
* properties shall not be doubled in children <tt>span</tt> elements.
*/
private static class BlockProperies
{
final String pFontName;
final int pFontSize;
public BlockProperies( String pFontName, int pFontSize )
{
this.pFontName = pFontName;
this.pFontSize = pFontSize;
}
}
private static final POILogger logger = POILogFactory private static final POILogger logger = POILogFactory
.getLogger( WordToHtmlConverter.class ); .getLogger( WordToHtmlConverter.class );
@ -584,7 +600,11 @@ public class WordToHtmlConverter extends AbstractWordConverter
if ( tableCell.isVerticallyMerged() if ( tableCell.isVerticallyMerged()
&& !tableCell.isFirstVerticallyMerged() ) && !tableCell.isFirstVerticallyMerged() )
{
currentEdgeIndex += getTableCellEdgesIndexSkipCount( table,
r, tableCellEdges, currentEdgeIndex, c, tableCell );
continue; continue;
}
Element tableCellElement; Element tableCellElement;
if ( tableRow.isTableHeader() ) if ( tableRow.isTableHeader() )
@ -601,42 +621,22 @@ public class WordToHtmlConverter extends AbstractWordConverter
r == 0, r == tableRows - 1, c == 0, c == rowCells - 1, r == 0, r == tableRows - 1, c == 0, c == rowCells - 1,
tableCellStyle ); tableCellStyle );
int colSpan = 0; int colSpan = getNumberColumnsSpanned( tableCellEdges,
int cellRightEdge = tableCell.getLeftEdge() currentEdgeIndex, tableCell );
+ tableCell.getWidth(); currentEdgeIndex += colSpan;
while ( tableCellEdges[currentEdgeIndex] < cellRightEdge )
{
colSpan++;
currentEdgeIndex++;
}
if ( colSpan == 0 ) if ( colSpan == 0 )
continue; continue;
if ( colSpan != 1 ) if ( colSpan != 1 )
{
tableCellElement.setAttribute( "colspan", tableCellElement.setAttribute( "colspan",
String.valueOf( colSpan ) ); String.valueOf( colSpan ) );
}
if ( tableCell.isFirstVerticallyMerged() ) final int rowSpan = getNumberRowsSpanned( table, r, c,
{ tableCell );
int count = 1; if ( rowSpan > 1 )
for ( int r1 = r + 1; r1 < tableRows; r1++ ) tableCellElement.setAttribute( "rowspan",
{ String.valueOf( rowSpan ) );
TableRow nextRow = table.getRow( r1 );
if ( nextRow.numCells() < c )
break;
TableCell nextCell = nextRow.getCell( c );
if ( !nextCell.isVerticallyMerged()
|| nextCell.isFirstVerticallyMerged() )
break;
count++;
}
if ( count > 1 )
tableCellElement.setAttribute( "rowspan",
String.valueOf( count ) );
}
processParagraphes( hwpfDocument, tableCellElement, tableCell, processParagraphes( hwpfDocument, tableCellElement, tableCell,
table.getTableLevel() ); table.getTableLevel() );
@ -695,20 +695,4 @@ public class WordToHtmlConverter extends AbstractWordConverter
} }
} }
/**
* Holds properties values, applied to current <tt>p</tt> element. Those
* properties shall not be doubled in children <tt>span</tt> elements.
*/
private static class BlockProperies
{
final String pFontName;
final int pFontSize;
public BlockProperies( String pFontName, int pFontSize )
{
this.pFontName = pFontName;
this.pFontSize = pFontSize;
}
}
} }