From 3aedc5332612d5b61cd6ee033bebda8de155ac8e Mon Sep 17 00:00:00 2001 From: "Andreas L. Delmelle" Date: Sat, 17 Sep 2005 23:59:25 +0000 Subject: [PATCH] Implementation for initial values of the column-number property git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@289865 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/fop/fo/FOPropertyMapping.java | 5 +- src/java/org/apache/fop/fo/flow/Table.java | 93 ++++++-- .../org/apache/fop/fo/flow/TableBody.java | 203 ++++++++++++++++-- .../org/apache/fop/fo/flow/TableCell.java | 43 ++-- .../org/apache/fop/fo/flow/TableColumn.java | 46 ++-- .../org/apache/fop/fo/flow/TableFObj.java | 110 ++++++++++ .../org/apache/fop/fo/flow/TableFooter.java | 3 +- .../org/apache/fop/fo/flow/TableHeader.java | 3 +- src/java/org/apache/fop/fo/flow/TableRow.java | 112 +++++++++- .../properties/ColumnNumberPropertyMaker.java | 67 ++++++ .../fop/layoutmgr/table/ColumnSetup.java | 6 +- .../table/TableContentLayoutManager.java | 6 +- .../layoutmgr/table/TableLayoutManager.java | 10 +- .../fop/layoutmgr/table/TableRowIterator.java | 13 +- 14 files changed, 622 insertions(+), 98 deletions(-) create mode 100644 src/java/org/apache/fop/fo/flow/TableFObj.java create mode 100644 src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java index fca91b15b..d03e623e5 100644 --- a/src/java/org/apache/fop/fo/FOPropertyMapping.java +++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java @@ -28,6 +28,7 @@ import org.apache.fop.fo.properties.BorderWidthPropertyMaker; import org.apache.fop.fo.properties.BoxPropShorthandParser; import org.apache.fop.fo.properties.CharacterProperty; import org.apache.fop.fo.properties.ColorTypeProperty; +import org.apache.fop.fo.properties.ColumnNumberPropertyMaker; import org.apache.fop.fo.properties.CondLengthProperty; import org.apache.fop.fo.properties.CorrespondingPropertyMaker; import org.apache.fop.fo.properties.DimensionPropertyMaker; @@ -2386,9 +2387,7 @@ public class FOPropertyMapping implements Constants { addPropertyMaker("caption-side", m); // column-number - m = new NumberProperty.Maker(PR_COLUMN_NUMBER); - m.setInherited(false); - m.setDefault("0"); + m = new ColumnNumberPropertyMaker(PR_COLUMN_NUMBER); addPropertyMaker("column-number", m); // column-width diff --git a/src/java/org/apache/fop/fo/flow/Table.java b/src/java/org/apache/fop/fo/flow/Table.java index e958c3c64..474efc6b7 100644 --- a/src/java/org/apache/fop/fo/flow/Table.java +++ b/src/java/org/apache/fop/fo/flow/Table.java @@ -18,6 +18,7 @@ package org.apache.fop.fo.flow; +import java.util.BitSet; import java.util.List; import org.xml.sax.Locator; @@ -41,7 +42,7 @@ import org.apache.fop.fo.properties.LengthRangeProperty; /** * Class modelling the fo:table object. */ -public class Table extends FObj { +public class Table extends TableFObj { // The value of properties relevant for fo:table. private CommonAccessibility commonAccessibility; private CommonAural commonAural; @@ -49,12 +50,8 @@ public class Table extends FObj { private CommonMarginBlock commonMarginBlock; private CommonRelativePosition commonRelativePosition; private LengthRangeProperty blockProgressionDimension; - private Numeric borderAfterPrecedence; - private Numeric borderBeforePrecedence; private int borderCollapse; - private Numeric borderEndPrecedence; private LengthPairProperty borderSeparation; - private Numeric borderStartPrecedence; private int breakAfter; private int breakBefore; private String id; @@ -75,6 +72,8 @@ public class Table extends FObj { /** collection of columns in this table */ protected List columns = null; + private BitSet usedColumnIndices = new BitSet(); + private int columnIndex = 1; private TableBody tableHeader = null; private TableBody tableFooter = null; @@ -106,12 +105,8 @@ public class Table extends FObj { commonMarginBlock = pList.getMarginBlockProps(); commonRelativePosition = pList.getRelativePositionProps(); blockProgressionDimension = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange(); - borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE).getNumeric(); - borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); borderCollapse = pList.get(PR_BORDER_COLLAPSE).getEnum(); - borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); borderSeparation = pList.get(PR_BORDER_SEPARATION).getLengthPair(); - borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric(); breakAfter = pList.get(PR_BREAK_AFTER).getEnum(); breakBefore = pList.get(PR_BREAK_BEFORE).getEnum(); id = pList.get(PR_ID).getString(); @@ -126,6 +121,7 @@ public class Table extends FObj { tableOmitHeaderAtBreak = pList.get(PR_TABLE_OMIT_HEADER_AT_BREAK).getEnum(); //width = pList.get(PR_WIDTH).getLength(); writingMode = pList.get(PR_WRITING_MODE).getEnum(); + super.bind(pList); //Create default column in case no table-columns will be defined. defaultColumn = new TableColumn(this, true); @@ -213,7 +209,8 @@ public class Table extends FObj { missingChildElementError( "(marker*,table-column*,table-header?,table-footer?,table-body+)"); } - + //release reference + usedColumnIndices = null; getFOEventHandler().endTable(this); } @@ -222,10 +219,7 @@ public class Table extends FObj { */ protected void addChildNode(FONode child) throws FOPException { if (child.getName().equals("fo:table-column")) { - if (columns == null) { - columns = new java.util.ArrayList(); - } - columns.add(((TableColumn)child)); + addColumnNode((TableColumn) child); } else if (child.getName().equals("fo:table-footer")) { tableFooter = (TableBody)child; } else if (child.getName().equals("fo:table-header")) { @@ -236,6 +230,48 @@ public class Table extends FObj { } } + /** + * Adds a column to the columns List, and updates the columnIndex + * used for determining initial values for column-number + * + * @param col the column to add + * @throws FOPException + */ + private void addColumnNode(TableColumn col) throws FOPException { + int colNumber = col.getColumnNumber(); + int colRepeat = col.getNumberColumnsRepeated(); + if (columns == null) { + columns = new java.util.ArrayList(); + } + if( columns.size() < colNumber ) { + //add nulls for non-occupied indices between + //the last column up to and including the current one + while( columns.size() < colNumber ) { + columns.add(null); + } + } + //replace the null-value with the actual column + columns.set(colNumber - 1, col); + if( colRepeat > 1 ) { + //in case column is repeated: + //for the time being, add the same column + //(colRepeat - 1) times to the columns list + //TODO: need to force the column-number + //TODO: need to make sure START/END BorderInfo + // are completely independent instances (clones?) + // = necessary for border-collapse="collapse" + // if collapsing is handled in FOTree + for( int i = colRepeat - 1; --i >= 0; ) { + columns.add(col); + } + } + //flag column indices used by this column + usedColumnIndices.set(colNumber - 1, colNumber - 1 + colRepeat); + //set index for the next column to use + while( usedColumnIndices.get(columnIndex - 1) ) { + columnIndex++; + } + } /** @return true of table-layout="auto" */ public boolean isAutoLayout() { return (tableLayout != EN_FIXED); @@ -376,4 +412,33 @@ public class Table extends FObj { public int getNameId() { return FO_TABLE; } + + /** + * Returns the current column index of the Table + * + * @return the next column number to use + */ + public int getCurrentColumnIndex() { + return columnIndex; + } + + /** + * Sets the current column index of the given Table + * (used by TableColumn.bind() in case the column-number + * was explicitly specified) + * + */ + protected void setCurrentColumnIndex(int newIndex) { + columnIndex = newIndex; + } + + /** + * Checks if a certain column-number is already occupied + * + * @param colNr the column-number to check + * @return true if column-number is already in use + */ + protected boolean isColumnNumberUsed(int colNr) { + return usedColumnIndices.get(colNr - 1); + } } diff --git a/src/java/org/apache/fop/fo/flow/TableBody.java b/src/java/org/apache/fop/fo/flow/TableBody.java index f5d91e6a4..5d44fec47 100644 --- a/src/java/org/apache/fop/fo/flow/TableBody.java +++ b/src/java/org/apache/fop/fo/flow/TableBody.java @@ -19,6 +19,7 @@ package org.apache.fop.fo.flow; // Java +import java.util.BitSet; import java.util.Iterator; import java.util.List; @@ -39,23 +40,24 @@ import org.apache.fop.fo.properties.CommonRelativePosition; /** * Class modelling the fo:table-body object. */ -public class TableBody extends FObj { +public class TableBody extends TableFObj { // The value of properties relevant for fo:table-body. private CommonAccessibility commonAccessibility; private CommonAural commonAural; private CommonBorderPaddingBackground commonBorderPaddingBackground; private CommonRelativePosition commonRelativePosition; - private Numeric borderAfterPrecedence; - private Numeric borderBeforePrecedence; - private Numeric borderEndPrecedence; - private Numeric borderStartPrecedence; private int visibility; // End of property values private PropertyList savedPropertyList; protected boolean tableRowsFound = false; - protected boolean tableCellsFound = false; + protected boolean tableCellsFound = false; + + private int columnIndex = 1; + protected List pendingSpans; + protected BitSet usedColumnIndices = new BitSet(); + private boolean firstRow = true; /** * @param parent FONode that is the parent of the object @@ -72,12 +74,8 @@ public class TableBody extends FObj { commonAural = pList.getAuralProps(); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonRelativePosition = pList.getRelativePositionProps(); - borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE).getNumeric(); - borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); - borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); - borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric(); visibility = pList.get(PR_VISIBILITY).getEnum(); - + super.bind(pList); //Used by convertCellsToRows() savedPropertyList = pList; } @@ -86,6 +84,7 @@ public class TableBody extends FObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { + initPendingSpans(); getFOEventHandler().startBody(this); } @@ -107,7 +106,10 @@ public class TableBody extends FObj { if (tableCellsFound) { convertCellsToRows(); }*/ - savedPropertyList = null; //Release reference + //release references + savedPropertyList = null; + pendingSpans = null; + usedColumnIndices = null; } /** @@ -142,6 +144,78 @@ public class TableBody extends FObj { invalidChildError(loc, nsURI, localName); } } + + /** + * @see org.apache.fop.fo.FONode#addChildNode(FONode) + */ + protected void addChildNode(FONode child) throws FOPException { + if( child.getNameId() == FO_TABLE_CELL ) { + addCellNode( (TableCell) child); + } else { + super.addChildNode(child); + } + } + + /** + * Adds a cell to the list of child nodes, and updates the columnIndex + * used for determining the initial value of column-number + * + * @param cell cell to add + * @throws FOPException + */ + private void addCellNode(TableCell cell) throws FOPException { + //if firstRow flag is still true, the cell starts a row, + //and there was a previous cell that didn't explicitly + //end the previous row => set firstRow flag to false + if( firstRow && cell.startsRow() && !lastCellEndedRow() ) { + firstRow = false; + } + int rowSpan = cell.getNumberRowsSpanned(); + int colSpan = cell.getNumberColumnsSpanned(); + //if there were no explicit columns, pendingSpans + //will not be properly initialized for the first row + if( firstRow && ((Table) parent).columns == null ) { + if( pendingSpans == null ) { + pendingSpans = new java.util.ArrayList(); + } + for( int i = colSpan; --i >= 0; ) { + pendingSpans.add(null); + } + } + //if the current cell spans more than one row, + //update pending span list for the next row + if( rowSpan > 1 ) { + for( int i = colSpan; --i >= 0; ) { + pendingSpans.set(columnIndex - 1 + i, + new PendingSpan(rowSpan)); + } + } + //flag column indices used by this cell, + //take into account that possibly not all column-numbers + //are used by columns in the parent table (if any), + //so a cell spanning three columns, might actually + //take up more than three columnIndices... + int startIndex = columnIndex - 1; + int endIndex = startIndex + colSpan; + if( ((Table) parent).columns != null ) { + List cols = ((Table) parent).columns; + int tmpIndex = endIndex; + for( int i = startIndex; i <= tmpIndex; ++i ) { + if( i < cols.size() && cols.get(i) == null ) { + endIndex++; + } + } + } + usedColumnIndices.set(startIndex, endIndex); + setNextColumnIndex(); + super.addChildNode(cell); + if( cell.endsRow() ) { + if( firstRow ) { + firstRow = false; + } + resetColumnIndex(); + } + } /** * If table-cells are used as direct children of a table-body|header|footer @@ -215,5 +289,110 @@ public class TableBody extends FObj { return (childNodes.size() > 0) && (childNodes.get(childNodes.size() - 1) == obj); } + + /** + * Initializes pending spans list; used for correctly + * assigning initial value for column-number for the + * cells of following rows + * + */ + protected void initPendingSpans() { + if( ((Table) parent).columns != null ) { + List tableCols = ((Table) parent).columns; + pendingSpans = new java.util.ArrayList(tableCols.size()); + for( int i = tableCols.size(); --i >= 0; ) { + pendingSpans.add(null); + } + } + } + + /** + * Returns the current column index of the TableBody + * + * @return the next column number to use + */ + public int getCurrentColumnIndex() { + return columnIndex; + } + + /** + * Sets the current column index to a specific value + * (used by TableCell.bind() in case the column-number + * was explicitly specified) + * + */ + protected void setCurrentColumnIndex(int newIndex) { + columnIndex = newIndex; + } + + /** + * Resets the current column index for the TableBody + * + */ + public void resetColumnIndex() { + columnIndex = 1; + usedColumnIndices.clear(); + PendingSpan pSpan; + for( int i = pendingSpans.size(); --i >= 0; ) { + pSpan = (PendingSpan) pendingSpans.get(i); + if( pSpan != null ) { + pSpan.rowsLeft--; + if( pSpan.rowsLeft == 0 ) { + pendingSpans.set(i, null); + } + } + usedColumnIndices.set(i, pendingSpans.get(i) != null); + } + if( !firstRow ) { + setNextColumnIndex(); + } + } + + /** + * Increases columnIndex to the next available value + * + */ + private void setNextColumnIndex() { + while( usedColumnIndices.get(columnIndex - 1) ) { + //increment columnIndex + columnIndex++; + //if the table has explicit columns, and + //the updated index is not assigned to any + //column, increment further until the next + //index occupied by a column... + if( ((Table) parent).columns != null ) { + while( columnIndex <= ((Table) parent).columns.size() + && !((Table) parent).isColumnNumberUsed(columnIndex) ) { + columnIndex++; + } + } + } + } + + /** + * Checks whether the previous cell had 'ends-row="true"' + * + * @return false only if there was a previous cell, which + * had ends-row="false" (implicit or explicit) + */ + public boolean lastCellEndedRow() { + if( childNodes != null ) { + FONode prevNode = (FONode) childNodes.get(childNodes.size() - 1); + if( prevNode.getNameId() == FO_TABLE_CELL ) { + return ((TableCell) prevNode).endsRow(); + } + } + return true; + } + + /** + * Checks whether a given column-number is already in use + * for the current row (used by TableCell.bind()); + * + * @return true if column-number is already occupied + */ + protected boolean isColumnNumberUsed(int colNr) { + return usedColumnIndices.get(colNr - 1); + } } diff --git a/src/java/org/apache/fop/fo/flow/TableCell.java b/src/java/org/apache/fop/fo/flow/TableCell.java index b3583d37f..216ada8ab 100644 --- a/src/java/org/apache/fop/fo/flow/TableCell.java +++ b/src/java/org/apache/fop/fo/flow/TableCell.java @@ -38,16 +38,12 @@ import org.apache.fop.fo.properties.LengthRangeProperty; * Class modelling the fo:table-cell object. * @todo check need for all instance variables stored here */ -public class TableCell extends FObj { +public class TableCell extends TableFObj { // The value of properties relevant for fo:table-cell. private CommonAccessibility commonAccessibility; private CommonAural commonAural; private CommonBorderPaddingBackground commonBorderPaddingBackground; private CommonRelativePosition commonRelativePosition; - private Numeric borderAfterPrecedence; - private Numeric borderBeforePrecedence; - private Numeric borderEndPrecedence; - private Numeric borderStartPrecedence; private LengthRangeProperty blockProgressionDimension; private int borderCollapse; //inherited from fo:table private LengthPairProperty borderSeparation; //inherited from fo:table @@ -118,10 +114,6 @@ public class TableCell extends FObj { commonAural = pList.getAuralProps(); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonRelativePosition = pList.getRelativePositionProps(); - borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE).getNumeric(); - borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); - borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); - borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric(); blockProgressionDimension = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange(); borderCollapse = pList.get(PR_BORDER_COLLAPSE).getEnum(); borderSeparation = pList.get(PR_BORDER_SEPARATION).getLengthPair(); @@ -137,6 +129,24 @@ public class TableCell extends FObj { numberRowsSpanned = pList.get(PR_NUMBER_ROWS_SPANNED).getNumeric(); startsRow = pList.get(PR_STARTS_ROW).getEnum(); width = pList.get(PR_WIDTH).getLength(); + super.bind(pList); + + //check if any of the column-numbers occupied by this cell + //are already in use in the current row... + for( int i = getColumnNumber(); + ++i <= getColumnNumber() + getNumberColumnsSpanned(); ) { + if( ((TableFObj) parent).isColumnNumberUsed(i - 1) ) { + throw new FOPException("cell overlaps in column " + (i - 1), + locator); + } + } + //if column-number was explicitly specified, force the parent's current + //column index to the specified value, so that the updated index will + //be the correct initial value for the next cell (see Rec 7.26.8) + if( pList.getExplicit(PR_COLUMN_NUMBER) != null ) { + ((TableFObj) parent).setCurrentColumnIndex( + pList.getExplicit(PR_COLUMN_NUMBER).getNumeric().getValue()); + } } /** @@ -156,7 +166,11 @@ public class TableCell extends FObj { if (!blockItemFound) { missingChildElementError("marker* (%block;)+"); } - //TODO Complain about startsRow|endsRow=true if parent is a table-row + if( (startsRow() || endsRow()) + && getParent().getNameId() == FO_TABLE_ROW ) { + getLogger().warn("starts-row/ends-row for fo:table-cells " + + "non-applicable for children of an fo:table-row."); + } getFOEventHandler().endCell(this); } @@ -287,18 +301,11 @@ public class TableCell extends FObj { return commonBorderPaddingBackground; } - /** - * @return true if the "column-number" property was set. - */ - public boolean hasColumnNumber() { - return (columnNumber.getValue() >= 1); - } - /** * @return the "column-number" property. */ public int getColumnNumber() { - return Math.max(columnNumber.getValue(), 0); + return columnNumber.getValue(); } /** @return true if "empty-cells" is "show" */ diff --git a/src/java/org/apache/fop/fo/flow/TableColumn.java b/src/java/org/apache/fop/fo/flow/TableColumn.java index a0aa9d647..107c1df7f 100644 --- a/src/java/org/apache/fop/fo/flow/TableColumn.java +++ b/src/java/org/apache/fop/fo/flow/TableColumn.java @@ -34,13 +34,9 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground; /** * Class modelling the fo:table-column object. */ -public class TableColumn extends FObj { +public class TableColumn extends TableFObj { // The value of properties relevant for fo:table-column. private CommonBorderPaddingBackground commonBorderPaddingBackground; - private Numeric borderAfterPrecedence; - private Numeric borderBeforePrecedence; - private Numeric borderEndPrecedence; - private Numeric borderStartPrecedence; private Numeric columnNumber; private Length columnWidth; private Numeric numberColumnsRepeated; @@ -72,21 +68,32 @@ public class TableColumn extends FObj { */ public void bind(PropertyList pList) throws FOPException { commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); - borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE).getNumeric(); - borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); - borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); - borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric(); columnNumber = pList.get(PR_COLUMN_NUMBER).getNumeric(); columnWidth = pList.get(PR_COLUMN_WIDTH).getLength(); numberColumnsRepeated = pList.get(PR_NUMBER_COLUMNS_REPEATED).getNumeric(); numberColumnsSpanned = pList.get(PR_NUMBER_COLUMNS_SPANNED).getNumeric(); visibility = pList.get(PR_VISIBILITY).getEnum(); + super.bind(pList); - if (columnNumber.getValue() < 0) { - //not catching 0 here because it is the indication that no - //column-number has been specified - throw new PropertyException("column-number must be 1 or bigger, " - + "but got " + columnNumber.getValue()); + if( pList.getExplicit(PR_COLUMN_NUMBER) != null ) { + if (columnNumber.getValue() <= 0) { + //TODO: This is actually a non-fatal error. See Rec 7.26.8: + //"A positive integer. If a negative or non-integer value + // is provided, the value will be rounded to the + // nearest integer value greater than or equal to 1." + throw new PropertyException("column-number must be 1 or bigger, " + + "but got " + columnNumber); + } else if( ((Table) parent).isColumnNumberUsed(columnNumber.getValue()) ) { + throw new PropertyException("specified column-number \"" + + columnNumber + + "\" has already been assigned to a previous column"); + } else { + //force parent table's current column index + //to the specified value, so that the updated index + //will be the correct initial value for the next column + //(see Rec 7.26.8) + ((Table) parent).setCurrentColumnIndex(columnNumber.getValue()); + } } if (numberColumnsRepeated.getValue() <= 0) { throw new PropertyException("number-columns-repeated must be 1 or bigger, " @@ -135,13 +142,6 @@ public class TableColumn extends FObj { return columnWidth; } - /** - * @return true if the "column-number" property was set. - */ - public boolean hasColumnNumber() { - return (columnNumber.getValue() >= 1); - } - /** * @return the "column-number" property. */ @@ -182,9 +182,7 @@ public class TableColumn extends FObj { /** @see java.lang.Object#toString() */ public String toString() { StringBuffer sb = new StringBuffer("fo:table-column"); - if (hasColumnNumber()) { - sb.append(" column-number=").append(getColumnNumber()); - } + sb.append(" column-number=").append(getColumnNumber()); if (getNumberColumnsRepeated() > 1) { sb.append(" number-columns-repeated=").append(getNumberColumnsRepeated()); } diff --git a/src/java/org/apache/fop/fo/flow/TableFObj.java b/src/java/org/apache/fop/fo/flow/TableFObj.java new file mode 100644 index 000000000..3592c006a --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/TableFObj.java @@ -0,0 +1,110 @@ +package org.apache.fop.fo.flow; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.datatypes.Numeric; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FObj; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.properties.CommonBorderPaddingBackground; + + +public abstract class TableFObj extends FObj { + + private Numeric borderAfterPrecedence; + private Numeric borderBeforePrecedence; + private Numeric borderEndPrecedence; + private Numeric borderStartPrecedence; + + protected static class PendingSpan { + protected int rowsLeft; + + public PendingSpan( int rows ) { + rowsLeft = rows; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("pending span: rowsLeft=").append(rowsLeft); + return sb.toString(); + } + } + + public TableFObj(FONode parent) { + super(parent); + } + + public void bind(PropertyList pList) throws FOPException { + borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE).getNumeric(); + borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); + borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); + borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric(); + } + + /** + * + * @param side the side for which to return the border precedence + * @return the "border-precedence" value for the given side + */ + public Numeric getBorderPrecedence(int side) { + switch( side ) { + case CommonBorderPaddingBackground.BEFORE: + return borderBeforePrecedence; + case CommonBorderPaddingBackground.AFTER: + return borderAfterPrecedence; + case CommonBorderPaddingBackground.START: + return borderStartPrecedence; + case CommonBorderPaddingBackground.END: + return borderEndPrecedence; + default: + return null; + } + } + + protected void setBorderPrecedence(int side, Numeric newPrecedence) { + switch( side ) { + case CommonBorderPaddingBackground.BEFORE: + borderBeforePrecedence = newPrecedence; + case CommonBorderPaddingBackground.AFTER: + borderAfterPrecedence = newPrecedence; + case CommonBorderPaddingBackground.START: + borderStartPrecedence = newPrecedence; + case CommonBorderPaddingBackground.END: + borderEndPrecedence = newPrecedence; + } + } + + /** + * Returns the current column index of the given TableFObj + * (overridden for Table, TableBody, TableRow) + * + * @return the next column number to use + */ + public int getCurrentColumnIndex() { + return 0; + } + + /** + * Sets the current column index of the given TableFObj + * (overridden for Table, TableBody, TableRow) + */ + protected void setCurrentColumnIndex(int newIndex) { + //do nothing by default + } + + /** + * Checks if a certain column-number is already occupied + * (overridden for Table, TableBody, TableRow) + * + * @param colNr the column-number to check + * @return true if column-number is already in use + */ + protected boolean isColumnNumberUsed(int colNr) { + return false; + } + + /** + * @return the Common Border, Padding, and Background Properties. + */ + public abstract CommonBorderPaddingBackground getCommonBorderPaddingBackground(); + +} diff --git a/src/java/org/apache/fop/fo/flow/TableFooter.java b/src/java/org/apache/fop/fo/flow/TableFooter.java index 09cba1cc3..d0ec6de66 100644 --- a/src/java/org/apache/fop/fo/flow/TableFooter.java +++ b/src/java/org/apache/fop/fo/flow/TableFooter.java @@ -39,7 +39,8 @@ public class TableFooter extends TableBody { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { -// getFOEventHandler().startBody(this); + initPendingSpans(); + //getFOEventHandler().startBody(this); } /** diff --git a/src/java/org/apache/fop/fo/flow/TableHeader.java b/src/java/org/apache/fop/fo/flow/TableHeader.java index 41187b060..4745daf98 100644 --- a/src/java/org/apache/fop/fo/flow/TableHeader.java +++ b/src/java/org/apache/fop/fo/flow/TableHeader.java @@ -39,7 +39,8 @@ public class TableHeader extends TableBody { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { -// getFOEventHandler().startHeader(this); + initPendingSpans(); + //getFOEventHandler().startHeader(this); } /** diff --git a/src/java/org/apache/fop/fo/flow/TableRow.java b/src/java/org/apache/fop/fo/flow/TableRow.java index 516be056e..18baabf2c 100644 --- a/src/java/org/apache/fop/fo/flow/TableRow.java +++ b/src/java/org/apache/fop/fo/flow/TableRow.java @@ -18,6 +18,9 @@ package org.apache.fop.fo.flow; +import java.util.BitSet; +import java.util.List; + import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; @@ -37,17 +40,13 @@ import org.apache.fop.fo.properties.LengthRangeProperty; /** * Class modelling the fo:table-row object. */ -public class TableRow extends FObj { +public class TableRow extends TableFObj { // The value of properties relevant for fo:table-row. private CommonAccessibility commonAccessibility; private LengthRangeProperty blockProgressionDimension; private CommonAural commonAural; private CommonBorderPaddingBackground commonBorderPaddingBackground; private CommonRelativePosition commonRelativePosition; - private Numeric borderAfterPrecedence; - private Numeric borderBeforePrecedence; - private Numeric borderEndPrecedence; - private Numeric borderStartPrecedence; private int breakAfter; private int breakBefore; private Length height; @@ -59,6 +58,10 @@ public class TableRow extends FObj { // End of property values private boolean setup = false; + + private List pendingSpans; + private BitSet usedColumnIndices; + private int columnIndex = 1; /** * @param parent FONode that is the parent of this object @@ -76,10 +79,6 @@ public class TableRow extends FObj { commonAural = pList.getAuralProps(); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonRelativePosition = pList.getRelativePositionProps(); - borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE).getNumeric(); - borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); - borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); - borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric(); breakAfter = pList.get(PR_BREAK_AFTER).getEnum(); breakBefore = pList.get(PR_BREAK_BEFORE).getEnum(); id = pList.get(PR_ID).getString(); @@ -88,6 +87,7 @@ public class TableRow extends FObj { keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep(); keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep(); visibility = pList.get(PR_VISIBILITY).getEnum(); + super.bind(pList); } /** @@ -107,6 +107,12 @@ public class TableRow extends FObj { * @see org.apache.fop.fo.FONode#startOfNode */ protected void startOfNode() throws FOPException { + pendingSpans = ((TableBody) parent).pendingSpans; + usedColumnIndices = ((TableBody) parent).usedColumnIndices; + while( usedColumnIndices.get(columnIndex - 1) ) { + columnIndex++; + } + checkId(id); getFOEventHandler().startRow(this); } @@ -118,6 +124,16 @@ public class TableRow extends FObj { if (childNodes == null) { missingChildElementError("(table-cell+)"); } + if( ((TableBody) parent).isFirst(this) + && ((Table) parent.getParent()).columns == null ) { + //force parent body's pendingSpans + //to the one accumulated after processing this row + ((TableBody) parent).pendingSpans = pendingSpans; + } + ((TableBody) parent).resetColumnIndex(); + //release references + pendingSpans = null; + usedColumnIndices = null; getFOEventHandler().endRow(this); } @@ -131,6 +147,55 @@ public class TableRow extends FObj { invalidChildError(loc, nsURI, localName); } } + + /** + * @see org.apache.fop.fo.FONode#addChildNode(FONode) + */ + protected void addChildNode(FONode child) throws FOPException { + TableCell cell = (TableCell) child; + int rowSpan = cell.getNumberRowsSpanned(); + int colSpan = cell.getNumberColumnsSpanned(); + if( ((TableBody) parent).isFirst(this) + && ((Table) parent.getParent()).columns == null ) { + if( pendingSpans == null ) { + pendingSpans = new java.util.ArrayList(); + } + pendingSpans.add(null); + if( usedColumnIndices == null ) { + usedColumnIndices = new BitSet(); + } + } + //if the current cell spans more than one row, + //update pending span list for the next row + if( rowSpan > 1 ) { + for( int i = colSpan; --i >= 0; ) { + pendingSpans.set(columnIndex - 1 + i, + new PendingSpan(rowSpan)); + } + } + //flag column indices used by this cell, + //take into account that possibly not all column-numbers + //are used by columns in the parent table (if any), + //so a cell spanning three columns, might actually + //take up more than three columnIndices... + int startIndex = columnIndex - 1; + int endIndex = startIndex + colSpan; + if( ((Table) parent.getParent()).columns != null ) { + List cols = ((Table) parent.getParent()).columns; + int tmpIndex = endIndex; + for( int i = startIndex; i <= tmpIndex; ++i ) { + if( i < cols.size() && cols.get(i) == null ) { + endIndex++; + } + } + } + usedColumnIndices.set(startIndex, endIndex); + //update columnIndex for the next cell + while( usedColumnIndices.get(columnIndex - 1) ) { + columnIndex++; + } + super.addChildNode(cell); + } /** * @return the "id" property. @@ -221,4 +286,33 @@ public class TableRow extends FObj { public int getNameId() { return FO_TABLE_ROW; } + + /** + * Returns the current column index of the TableRow + * + * @return the next column number to use + */ + public int getCurrentColumnIndex() { + return columnIndex; + } + + /** + * Sets the current column index to a specific value + * in case a column-number was explicitly specified + * (used by TableCell.bind()) + * + */ + protected void setCurrentColumnIndex(int newIndex) { + columnIndex = newIndex; + } + + /** + * Checks whether a given column-number is already in use + * for the current row (used by TableCell.bind()); + * + * @return true if column-number is already occupied + */ + protected boolean isColumnNumberUsed(int colNr) { + return usedColumnIndices.get(colNr - 1); + } } diff --git a/src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java b/src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java new file mode 100644 index 000000000..f4ab5c6cf --- /dev/null +++ b/src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java @@ -0,0 +1,67 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.properties; + +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.FObj; +import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.expr.PropertyException; +import org.apache.fop.fo.flow.TableFObj; +import org.apache.fop.fo.flow.TableBody; + +public class ColumnNumberPropertyMaker extends NumberProperty.Maker { + + public ColumnNumberPropertyMaker(int propId) { + super(propId); + } + + /** + * Set default column-number from parent's currentColumnIndex + * + * @return the default value for column-number + */ + public Property make(PropertyList propertyList) throws PropertyException { + FObj fo = propertyList.getFObj(); + + if( fo.getNameId() == Constants.FO_TABLE_CELL + || fo.getNameId() == Constants.FO_TABLE_COLUMN ) { + TableFObj parent = (TableFObj) propertyList.getParentFObj(); + int columnIndex = parent.getCurrentColumnIndex(); + if( fo.getNameId() == Constants.FO_TABLE_CELL + && parent.getNameId() == Constants.FO_TABLE_BODY ) { + boolean startsRow = propertyList.get(Constants.PR_STARTS_ROW) + .getEnum() == Constants.EN_TRUE; + + //cell w/ starts-row="true", but previous cell + //didn't have ends-row="true", so index has still has + //to be reset (for other cases this already happened in + //body.addChildNode()) + if( startsRow && !((TableBody) parent).lastCellEndedRow() ) { + //reset column index, and reassign... + ((TableBody) parent).resetColumnIndex(); + columnIndex = parent.getCurrentColumnIndex(); + } + } + return new NumberProperty(columnIndex); + } else { + throw new PropertyException("column-number property is only allowed on " + + "fo:table-cell or fo:table-column, not on " + fo.getName()); + } + } +} diff --git a/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java b/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java index 8df556afc..cf3a6af05 100644 --- a/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java +++ b/src/java/org/apache/fop/layoutmgr/table/ColumnSetup.java @@ -60,7 +60,7 @@ public class ColumnSetup { ListIterator iter = rawCols.listIterator(); while (iter.hasNext()) { TableColumn col = (TableColumn)iter.next(); - if (col.hasColumnNumber()) { + if( col != null ) { colnum = col.getColumnNumber(); } for (int i = 0; i < col.getNumberColumnsRepeated(); i++) { @@ -151,7 +151,9 @@ public class ColumnSetup { public int getXOffset(int col, PercentBaseContext context) { int xoffset = 0; for (int i = 1; i < col; i++) { - xoffset += getColumn(i).getColumnWidth().getValue(context); + if( getColumn(i) != null ) { + xoffset += getColumn(i).getColumnWidth().getValue(context); + } } return xoffset; } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index bb4112483..cbaf1a8f3 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -439,8 +439,10 @@ public class TableContentLayoutManager implements PercentBaseContext { i < primary.getStartCol() + primary.getCell().getNumberColumnsSpanned(); i++) { - spanWidth += getTableLM().getColumns().getColumn(i + 1) - .getColumnWidth().getValue(getTableLM()); + if( getTableLM().getColumns().getColumn(i + 1) != null ) { + spanWidth += getTableLM().getColumns().getColumn(i + 1) + .getColumnWidth().getValue(getTableLM()); + } } LayoutContext childLC = new LayoutContext(0); childLC.setStackLimit(context.getStackLimit()); //necessary? diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java index 1a5bf7fa5..5b1576c97 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java @@ -156,10 +156,12 @@ public class TableLayoutManager extends BlockStackingLayoutManager float factors = 0; for (Iterator i = columns.iterator(); i.hasNext();) { TableColumn column = (TableColumn) i.next(); - Length width = column.getColumnWidth(); - sumCols += width.getValue(this); - if (width instanceof TableColLength) { - factors += ((TableColLength) width).getTableUnits(); + if( column != null ) { + Length width = column.getColumnWidth(); + sumCols += width.getValue(this); + if (width instanceof TableColLength) { + factors += ((TableColLength) width).getTableUnits(); + } } } // sets TABLE_UNITS in case where one or more oldColumns is defined using diff --git a/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java b/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java index e6d6ff330..0781d4ee6 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java @@ -362,15 +362,12 @@ public class TableRowIterator { while (iter.hasNext()) { TableCell cell = (TableCell)iter.next(); - if (cell.hasColumnNumber()) { - colnum = cell.getColumnNumber(); - } else { - //Skip columns with spanning grid units - while (safelyGetListItem(gridUnits, colnum - 1) != null) { - colnum++; - } - } + colnum = cell.getColumnNumber(); + //TODO: remove the check below??? + //shouldn't happen here, since + //overlapping cells already caught in + //fo.flow.TableCell.bind()... if (safelyGetListItem(gridUnits, colnum - 1) != null) { log.error("Overlapping cell at position " + colnum); //TODO throw layout exception -- 2.39.5