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;
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
package org.apache.fop.fo.flow;
+import java.util.BitSet;
import java.util.List;
import org.xml.sax.Locator;
/**
* 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;
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;
/** 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;
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();
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);
missingChildElementError(
"(marker*,table-column*,table-header?,table-footer?,table-body+)");
}
-
+ //release reference
+ usedColumnIndices = null;
getFOEventHandler().endTable(this);
}
*/
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")) {
}
}
+ /**
+ * 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);
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);
+ }
}
package org.apache.fop.fo.flow;
// Java
+import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
/**
* 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
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;
}
* @see org.apache.fop.fo.FONode#startOfNode
*/
protected void startOfNode() throws FOPException {
+ initPendingSpans();
getFOEventHandler().startBody(this);
}
if (tableCellsFound) {
convertCellsToRows();
}*/
- savedPropertyList = null; //Release reference
+ //release references
+ savedPropertyList = null;
+ pendingSpans = null;
+ usedColumnIndices = null;
}
/**
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
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);
+ }
}
* 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
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();
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());
+ }
}
/**
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);
}
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" */
/**
* 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;
*/
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, "
return columnWidth;
}
- /**
- * @return true if the "column-number" property was set.
- */
- public boolean hasColumnNumber() {
- return (columnNumber.getValue() >= 1);
- }
-
/**
* @return the "column-number" property.
*/
/** @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());
}
--- /dev/null
+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();
+
+}
* @see org.apache.fop.fo.FONode#startOfNode
*/
protected void startOfNode() throws FOPException {
-// getFOEventHandler().startBody(this);
+ initPendingSpans();
+ //getFOEventHandler().startBody(this);
}
/**
* @see org.apache.fop.fo.FONode#startOfNode
*/
protected void startOfNode() throws FOPException {
-// getFOEventHandler().startHeader(this);
+ initPendingSpans();
+ //getFOEventHandler().startHeader(this);
}
/**
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;
/**
* 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;
// 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
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();
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);
}
/**
* @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);
}
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);
}
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.
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);
+ }
}
--- /dev/null
+/*
+ * 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());
+ }
+ }
+}
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++) {
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;
}
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?
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
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