diff options
Diffstat (limited to 'src/java/org/apache/fop/fo/flow/table')
16 files changed, 772 insertions, 159 deletions
diff --git a/src/java/org/apache/fop/fo/flow/table/BorderResolver.java b/src/java/org/apache/fop/fo/flow/table/BorderResolver.java new file mode 100644 index 000000000..0a8f3d39e --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/table/BorderResolver.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.flow.table; + +import java.util.List; + +/** + * A class dedicated to the resolution of borders in tables. It receives a series of + * events as the table is parsed and performs border resolution accordingly. + */ +interface BorderResolver { + + /** + * Receives notification of the end of a row. + * + * @param row the row that has just been finished + * @param container the FO element holding the given row + */ + void endRow(List/*<GridUnit>*/ row, TableCellContainer container); + + /** + * Receives notification of the start of a table-header/footer/body. + * + * @param part the part that has started + */ + void startPart(TableBody part); + + /** + * Receives notification of the end of a table-header/footer/body. + * + * @param part the part that has ended + */ + void endPart(TableBody part); + + /** + * Receives notification of the end of the table. + */ + void endTable(); +} diff --git a/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java b/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java new file mode 100644 index 000000000..214f9be07 --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.flow.table; + +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; + +/** + * A border's informations, along with the FO element which declared it. Used for border + * resolution in the collapsing-border model. + */ +public/*TODO*/ class BorderSpecification { + + private BorderInfo borderInfo; + + private int holder; + + /** + * Creates a new border specification. + * + * @param borderInfo the border's informations + * @param holder the FO element declaring this border + */ + public/*TODO*/ BorderSpecification(BorderInfo borderInfo, int holder) { + this.borderInfo = borderInfo; + this.holder = holder; + } + + /** + * Returns this border's informations. + * + * @return this border's informations + */ + public/*TODO*/ BorderInfo getBorderInfo() { + return borderInfo; + } + + /** + * Returns the FO element declaring this border. + * + * @return one of {@link Constants#FO_TABLE}, {@link Constants#FO_TABLE_COLUMN}, + * {@link Constants#FO_TABLE_HEADER}, {@link Constants#FO_TABLE_FOOTER}, + * {@link Constants#FO_TABLE_BODY}, {@link Constants#FO_TABLE_ROW}, + * {@link Constants#FO_TABLE_CELL} + */ + public/*TODO*/ int getHolder() { + return holder; + } + + /** {@inheritDoc} */ + public String toString() { + return "{" + borderInfo + ", " + holder + "}"; + } +} diff --git a/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java b/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java new file mode 100644 index 000000000..732acb6be --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.flow.table; + +import java.util.Iterator; +import java.util.List; + +import org.apache.fop.fo.properties.CommonBorderPaddingBackground; +import org.apache.fop.layoutmgr.table.GridUnit; + +/** + * A class that implements the border-collapsing model. + */ +class CollapsingBorderResolver implements BorderResolver { + + private Table table; + + private List previousRow; + + /** + * The flow of rows is interrupted by the table-footer. Save the header's last row (if + * any) for resolution between it and the body's first row. + */ + private List previousRowSave; + + private TableBody currentTablePart; + + private boolean firstInTable; + + private boolean firstInPart; + + private List footerFirstRow; + + private List footerLastRow; + + private boolean inFooter; + + CollapsingBorderResolver(Table table) { + this.table = table; + firstInTable = true; + } + + /** {@inheritDoc} */ + public void endRow(List row, TableCellContainer container) { + // Resolve before- and after-borders for the table-row + if (container instanceof TableRow) { + TableRow tableRow = (TableRow) container; + for (Iterator iter = row.iterator(); iter.hasNext();) { + GridUnit gu = (GridUnit) iter.next(); + if (gu.getRowSpanIndex() == 0) { + gu.resolveBorder(CommonBorderPaddingBackground.BEFORE, tableRow); + } + if (gu.isLastGridUnitRowSpan()) { + gu.resolveBorder(CommonBorderPaddingBackground.AFTER, tableRow); + } + } + } + if (inFooter) { + if (footerFirstRow == null) { + footerFirstRow = row; + } + footerLastRow = row; + } else if (firstInTable) { + // Resolve border-before for the first row in the table + for (int i = 0; i < row.size(); i++) { + TableColumn column = table.getColumn(i); + ((GridUnit) row.get(i)).resolveBorder(CommonBorderPaddingBackground.BEFORE, column); + } + firstInTable = false; + } + if (firstInPart) { + // Resolve border-before for the first row in the part + for (int i = 0; i < row.size(); i++) { + ((GridUnit) row.get(i)).resolveBorder(CommonBorderPaddingBackground.BEFORE, + currentTablePart); + } + firstInPart = false; + } + if (previousRow != null) { + // Resolve after/before borders between rows + for (int i = 0; i < row.size(); i++) { + GridUnit gu = (GridUnit) row.get(i); + if (gu.getRowSpanIndex() == 0) { + GridUnit beforeGU = (GridUnit) previousRow.get(i); + gu.resolveBorder(beforeGU, CommonBorderPaddingBackground.BEFORE); + } + } + } + // Resolve start/end borders in the row + Iterator guIter = row.iterator(); + GridUnit gu = (GridUnit) guIter.next(); + gu.resolveBorder(CommonBorderPaddingBackground.START, container); + while (guIter.hasNext()) { + GridUnit guEnd = (GridUnit) guIter.next(); + if (gu.isLastGridUnitColSpan()) { + gu.resolveBorder(guEnd, CommonBorderPaddingBackground.END); + } + gu = guEnd; + } + gu.resolveBorder(CommonBorderPaddingBackground.END, container); + + previousRow = row; + } + + /** {@inheritDoc} */ + public void startPart(TableBody part) { + firstInPart = true; + currentTablePart = part; + if (part.isTableFooter()) { + inFooter = true; + previousRowSave = previousRow; + previousRow = null; + } + } + + /** {@inheritDoc} */ + public void endPart(TableBody part) { + // Resolve border-after for the last row in the part + for (int i = 0; i < previousRow.size(); i++) { + ((GridUnit) previousRow.get(i)) + .resolveBorder(CommonBorderPaddingBackground.AFTER, part); + } + if (inFooter) { + inFooter = false; + previousRow = previousRowSave; + } + } + + /** {@inheritDoc} */ + public void endTable() { + if (footerFirstRow != null) { + // Resolve after/before border between the last row of table-body and the + // first row of table-footer + for (int i = 0; i < footerFirstRow.size(); i++) { + GridUnit gu = (GridUnit) footerFirstRow.get(i); + GridUnit beforeGU = (GridUnit) previousRow.get(i); + gu.resolveBorder(beforeGU, CommonBorderPaddingBackground.BEFORE); + } + } + List lastRow; + if (footerLastRow != null) { + lastRow = footerLastRow; + } else { + lastRow = previousRow; + } + // Resolve border-after for the last row of the table + for (int i = 0; i < lastRow.size(); i++) { + TableColumn column = table.getColumn(i); + ((GridUnit) lastRow.get(i)).resolveBorder(CommonBorderPaddingBackground.AFTER, column); + } + } +} diff --git a/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java index 22e5c02b8..602ae84a6 100644 --- a/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java @@ -19,6 +19,15 @@ package org.apache.fop.fo.flow.table; +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +import org.apache.fop.fo.ValidationException; +import org.apache.fop.layoutmgr.table.EmptyGridUnit; +import org.apache.fop.layoutmgr.table.GridUnit; +import org.apache.fop.layoutmgr.table.PrimaryGridUnit; + /** * A row group builder optimised for a fixed number of columns, known before the parsing @@ -26,10 +35,149 @@ package org.apache.fop.fo.flow.table; */ class FixedColRowGroupBuilder extends RowGroupBuilder { + /** Number of columns in the corresponding table. */ + private int numberOfColumns; + + /** 0-based, index in the row group. */ + private int currentRowIndex; + + /** The rows belonging to this row group. List of List of {@link GridUnit}s. */ + private List/*<List<GridUnit>>*/ rows; + + private boolean firstInTable = true; + + private boolean firstInPart = true; + + /** The last encountered row. This is the last row of the table if it has no footer. */ + private List lastRow; + + private BorderResolver borderResolver; + + private boolean inFooter; + + private List lastFooterRow; FixedColRowGroupBuilder(Table t) { super(t); numberOfColumns = t.getNumberOfColumns(); + if (t.isSeparateBorderModel()) { + borderResolver = new SeparateBorderResolver(); + } else { + borderResolver = new CollapsingBorderResolver(t); + } + initialize(); + } + + /** + * Prepares this builder for creating a new row group. + */ + private void initialize() { + rows = new ArrayList(); + currentRowIndex = 0; } + /** {@inheritDoc} */ + void addTableCell(TableCell cell) { + for (int i = rows.size(); i < currentRowIndex + cell.getNumberRowsSpanned(); i++) { + List effRow = new ArrayList(numberOfColumns); + for (int j = 0; j < numberOfColumns; j++) { + effRow.add(null); + } + rows.add(effRow); + } + int columnIndex = cell.getColumnNumber() - 1; + PrimaryGridUnit pgu = new PrimaryGridUnit(cell, table.getColumn(columnIndex), columnIndex, + currentRowIndex); + List row = (List) rows.get(currentRowIndex); + row.set(columnIndex, pgu); + // TODO + GridUnit[] cellRow = new GridUnit[cell.getNumberColumnsSpanned()]; + cellRow[0] = pgu; + for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) { + GridUnit gu = new GridUnit(pgu, table.getColumn(columnIndex + j), + columnIndex + j, j, 0); + row.set(columnIndex + j, gu); + cellRow[j] = gu; + } + pgu.addRow(cellRow); + for (int i = 1; i < cell.getNumberRowsSpanned(); i++) { + row = (List) rows.get(currentRowIndex + i); + cellRow = new GridUnit[cell.getNumberColumnsSpanned()]; + for (int j = 0; j < cell.getNumberColumnsSpanned(); j++) { + GridUnit gu = new GridUnit(pgu, table.getColumn(columnIndex + j), + columnIndex + j, j, i); + row.set(columnIndex + j, gu); + cellRow[j] = gu; + } + pgu.addRow(cellRow); + } + } + + private static void setFlagForCols(int flag, List row) { + for (ListIterator iter = row.listIterator(); iter.hasNext();) { + ((GridUnit) iter.next()).setFlag(flag); + } + } + + /** {@inheritDoc} */ + void endRow(TableCellContainer container) { + List currentRow = (List) rows.get(currentRowIndex); + lastRow = currentRow; + // Fill gaps with empty grid units + for (int i = 0; i < numberOfColumns; i++) { + if (currentRow.get(i) == null) { + currentRow.set(i, new EmptyGridUnit(table, currentRowIndex, i)); + } + } + borderResolver.endRow(currentRow, container); + ((GridUnit) currentRow.get(0)).setFlag(GridUnit.IN_FIRST_COLUMN); + ((GridUnit) currentRow.get(numberOfColumns - 1)).setFlag(GridUnit.IN_LAST_COLUMN); + if (inFooter) { + lastFooterRow = currentRow; + } else if (firstInTable) { + setFlagForCols(GridUnit.FIRST_IN_TABLE, currentRow); + firstInTable = false; + } + if (firstInPart) { + setFlagForCols(GridUnit.FIRST_IN_PART, currentRow); + firstInPart = false; + } + if (currentRowIndex == rows.size() - 1) { + // Means that the current row has no cell spanning over following rows + container.getTablePart().addRowGroup(rows); + initialize(); + } else { + currentRowIndex++; + } + } + + /** {@inheritDoc} */ + void startTablePart(TableBody part) { + firstInPart = true; + inFooter = part.isTableFooter(); + borderResolver.startPart(part); + } + + /** {@inheritDoc} */ + void endTablePart(TableBody tableBody) throws ValidationException { + if (rows.size() > 0) { + throw new ValidationException( + "A table-cell is spanning more rows than available in its parent element."); + } + setFlagForCols(GridUnit.LAST_IN_PART, lastRow); + borderResolver.endPart(tableBody); + inFooter = false; + } + + /** {@inheritDoc} */ + void endTable(TableBody lastTablePart) { + List lastTableRow; + if (lastFooterRow != null) { + lastTableRow = lastFooterRow; + } else { + lastTableRow = lastRow; + } + setFlagForCols(GridUnit.LAST_IN_TABLE, lastTableRow); + borderResolver.endTable(); + } } diff --git a/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java index 2f9a009c2..7f09f7d46 100644 --- a/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java @@ -19,12 +19,8 @@ package org.apache.fop.fo.flow.table; -import java.util.ArrayList; -import java.util.List; - import org.apache.fop.fo.ValidationException; import org.apache.fop.layoutmgr.table.GridUnit; -import org.apache.fop.layoutmgr.table.PrimaryGridUnit; /** * A class that creates groups of rows belonging to a same set of spans. The first row of @@ -34,16 +30,7 @@ import org.apache.fop.layoutmgr.table.PrimaryGridUnit; */ abstract class RowGroupBuilder { - /** Number of columns in the corresponding table. */ - protected int numberOfColumns; - - /** 0-based, index in the row group. */ - private int currentRowIndex; - - private Table table; - - /** The rows belonging to this row group. List of List of {@link GridUnit}s. */ - protected List rows; + protected Table table; /** * Creates and initialises a new builder for the given table. @@ -52,81 +39,48 @@ abstract class RowGroupBuilder { */ protected RowGroupBuilder(Table t) { table = t; - initialize(); } + /** - * Prepares this builder for creating a new row group. + * Adds a table-cell to the current row-group, creating {@link GridUnit}s accordingly. + * + * @param cell the cell to add */ - private void initialize() { - rows = new ArrayList(); - currentRowIndex = 0; - } + abstract void addTableCell(TableCell cell); /** - * Adds a table-cell to the row-group, creating {@link GridUnit}s accordingly. + * Receives notification of the end of the current row. If the current row finishes + * the row group, the {@link TableBody#addRowGroup(List)} method of the parent table + * part (i.e., the given container itself or its parent if this is a table-row) will + * be called * - * @param cell + * @param container the parent element of the current row */ - void addTableCell(TableCell cell) { - for (int i = rows.size(); i < currentRowIndex + cell.getNumberRowsSpanned(); i++) { - List effRow = new ArrayList(numberOfColumns); - for (int j = 0; j < numberOfColumns; j++) { - effRow.add(null); - } - rows.add(effRow); - } - int columnIndex = cell.getColumnNumber() - 1; - PrimaryGridUnit pgu = new PrimaryGridUnit(cell, table.getColumn(columnIndex), columnIndex, - currentRowIndex); - List row = (List) rows.get(currentRowIndex); - row.set(columnIndex, pgu); - for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) { - row.set(j + columnIndex, - new GridUnit(pgu, table.getColumn(columnIndex + j), columnIndex + j, j)); - } - for (int i = 1; i < cell.getNumberRowsSpanned(); i++) { - row = (List) rows.get(currentRowIndex + i); - for (int j = 0; j < cell.getNumberColumnsSpanned(); j++) { - row.set(j + columnIndex, - new GridUnit(pgu, table.getColumn(columnIndex + j), columnIndex + j, j)); - } - } - - } + abstract void endRow(TableCellContainer container); /** - * Signals that a table row has just ended, potentially finishing the current row - * group. + * Receives notification of the start of a table-header/footer/body. * - * @param body the table-body containing the row. Its - * {@link TableBody#addRowGroup(List)} method will be called if the current row group - * is finished. + * @param part the part being started */ - void signalRowEnd(TableBody body) { - if (currentRowIndex == rows.size() - 1) { - // Means that the current row has no cell spanning over following rows - body.addRowGroup(rows); - initialize(); - } else { - currentRowIndex++; - } - } + abstract void startTablePart(TableBody part); /** - * Signals that the end of a table-header/footer/body has been reached. The current + * Receives notification of the end of a table-header/footer/body. The current * row-group is checked for emptiness. This row group builder is reset for handling * further possible table parts. * - * @param tableBody the table part being finished - * @throws ValidationException if a cell is spanning further than the given table part + * @param tableBody the table part being ended + * @throws ValidationException if a row-spanning cell overflows the given table part */ - void signalEndOfPart(TableBody tableBody) throws ValidationException { - if (rows.size() > 0) { - throw new ValidationException( - "A table-cell is spanning more rows than available in its parent element."); - } - initialize(); - } + abstract void endTablePart(TableBody tableBody) throws ValidationException; + /** + * Receives notification of the end of the table. + * + * @param lastTablePart the last part of the table + * @throws ValidationException if a row-spanning cell overflows one of the table's parts + */ + abstract void endTable(TableBody lastTablePart) throws ValidationException; } diff --git a/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java b/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java new file mode 100644 index 000000000..37e3cb6e8 --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/table/SeparateBorderResolver.java @@ -0,0 +1,44 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.flow.table; + +import java.util.List; + +/** + * A resolver for the separate-border model. Basically this class does nothing. + */ +class SeparateBorderResolver implements BorderResolver { + + /** {@inheritDoc} */ + public void endRow(List row, TableCellContainer container) { + } + + /** {@inheritDoc} */ + public void startPart(TableBody part) { + } + + /** {@inheritDoc} */ + public void endPart(TableBody part) { + } + + /** {@inheritDoc} */ + public void endTable() { + } +} diff --git a/src/java/org/apache/fop/fo/flow/table/Table.java b/src/java/org/apache/fop/fo/flow/table/Table.java index 07fc95f7e..b2f240c72 100644 --- a/src/java/org/apache/fop/fo/flow/table/Table.java +++ b/src/java/org/apache/fop/fo/flow/table/Table.java @@ -20,7 +20,6 @@ package org.apache.fop.fo.flow.table; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import org.apache.fop.apps.FOPException; @@ -154,7 +153,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startTable(this); } @@ -211,7 +210,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { if (!tableBodyFound) { missingChildElementError( @@ -219,6 +218,11 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { + ",table-body+)"); } if (!inMarker()) { + if (tableFooter != null) { + rowGroupBuilder.endTable(tableFooter); + } else { + rowGroupBuilder.endTable((TableBody) getChildNodes().lastNode()); + } /* clean up */ for (int i = columns.size(); --i >= 0;) { TableColumn col = (TableColumn) columns.get(i); @@ -278,6 +282,13 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { } } + protected void setCollapsedBorders() { + createBorder(CommonBorderPaddingBackground.START); + createBorder(CommonBorderPaddingBackground.END); + createBorder(CommonBorderPaddingBackground.BEFORE); + createBorder(CommonBorderPaddingBackground.AFTER); + } + private void finalizeColumns() throws FOPException { for (int i = 0; i < columns.size(); i++) { if (columns.get(i) == null) { @@ -305,32 +316,6 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { for (int i = columns.size() + 1; i <= columnNumber; i++) { columns.add(createImplicitColumn(i)); } - ((VariableColRowGroupBuilder) rowGroupBuilder).ensureNumberOfColumns(columnNumber); - if (tableHeader != null) { - for (Iterator iter = tableHeader.getRowGroups().iterator(); iter.hasNext();) { - VariableColRowGroupBuilder.fillWithEmptyGridUnits((List) iter.next(), - columnNumber); - } - } - if (tableFooter != null) { - for (Iterator iter = tableFooter.getRowGroups().iterator(); iter.hasNext();) { - VariableColRowGroupBuilder.fillWithEmptyGridUnits((List) iter.next(), - columnNumber); - } - } - FONodeIterator bodyIter = getChildNodes(); - if (bodyIter != null) { - while (bodyIter.hasNext()) { - FONode node = bodyIter.nextNode(); - if (node instanceof TableBody) { // AFAIK, may be a marker - for (Iterator iter = ((TableBody) node).getRowGroups().iterator(); - iter.hasNext();) { - VariableColRowGroupBuilder.fillWithEmptyGridUnits((List) iter.next(), - columnNumber); - } - } - } - } } private TableColumn createImplicitColumn(int colNumber) @@ -342,6 +327,9 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { implicitColumn.bind(pList); implicitColumn.setColumnWidth(new TableColLength(1.0, implicitColumn)); implicitColumn.setColumnNumber(colNumber); + if (!isSeparateBorderModel()) { + implicitColumn.setCollapsedBorders(collapsingBorderModel); // TODO + } return implicitColumn; } @@ -399,7 +387,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { * @param index index of the column to be retrieved, 0-based * @return the corresponding column (may be an implicitly created column) */ - TableColumn getColumn(int index) { + public/*TODO*/ TableColumn getColumn(int index) { return (TableColumn) columns.get(index); } diff --git a/src/java/org/apache/fop/fo/flow/table/TableBody.java b/src/java/org/apache/fop/fo/flow/table/TableBody.java index 7e4ee2fb0..ece1f0049 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableBody.java +++ b/src/java/org/apache/fop/fo/flow/table/TableBody.java @@ -50,15 +50,15 @@ public class TableBody extends TableCellContainer { protected boolean tableRowsFound = false; protected boolean tableCellsFound = false; - /** - * used for initial values of column-number property - */ private boolean firstRow = true; private boolean rowsStarted = false; private boolean lastCellEndsRow = true; + /** The last encountered table-row. */ + private TableRow lastRow; + private List rowGroups = new LinkedList(); /** @@ -101,14 +101,15 @@ public class TableBody extends TableCellContainer { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { + super.startOfNode(); getFOEventHandler().startBody(this); } /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { if (!inMarker()) { pendingSpans = null; @@ -130,16 +131,25 @@ public class TableBody extends TableCellContainer { } } + /** {@inheritDoc} */ + TableBody getTablePart() { + return this; + } + protected void finishLastRowGroup() throws ValidationException { - RowGroupBuilder rowGroupBuilder = getTable().getRowGroupBuilder(); - if (tableRowsFound || !lastCellEndsRow) { - rowGroupBuilder.signalRowEnd(this); - } - try { - rowGroupBuilder.signalEndOfPart(this); - } catch (ValidationException e) { - e.setLocator(locator); - throw e; + if (!inMarker()) { + RowGroupBuilder rowGroupBuilder = getTable().getRowGroupBuilder(); + if (tableRowsFound) { + rowGroupBuilder.endRow(lastRow); + } else if (!lastCellEndsRow) { + rowGroupBuilder.endRow(this); + } + try { + rowGroupBuilder.endTablePart(this); + } catch (ValidationException e) { + e.setLocator(locator); + throw e; + } } } @@ -184,13 +194,19 @@ public class TableBody extends TableCellContainer { if (!inMarker()) { switch (child.getNameId()) { case FO_TABLE_ROW: - if (rowsStarted) { + if (!rowsStarted) { + getTable().getRowGroupBuilder().startTablePart(this); + } else { columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().signalRowEnd(this); + getTable().getRowGroupBuilder().endRow(lastRow); } rowsStarted = true; + lastRow = (TableRow) child; break; case FO_TABLE_CELL: + if (!rowsStarted) { + getTable().getRowGroupBuilder().startTablePart(this); + } rowsStarted = true; TableCell cell = (TableCell) child; addTableCellChild(cell, firstRow); @@ -198,7 +214,7 @@ public class TableBody extends TableCellContainer { if (lastCellEndsRow) { firstRow = false; columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().signalRowEnd(this); + getTable().getRowGroupBuilder().endRow(this); } break; default: @@ -208,11 +224,20 @@ public class TableBody extends TableCellContainer { super.addChildNode(child); } + /** {inheritDoc} */ + protected void setCollapsedBorders() { + Table table = (Table) parent; + createBorder(CommonBorderPaddingBackground.START, table); + createBorder(CommonBorderPaddingBackground.END, table); + createBorder(CommonBorderPaddingBackground.BEFORE); + createBorder(CommonBorderPaddingBackground.AFTER); + } + void addRowGroup(List rowGroup) { rowGroups.add(rowGroup); } - List getRowGroups() { + public List getRowGroups() { return rowGroups; } @@ -235,6 +260,10 @@ public class TableBody extends TableCellContainer { return FO_TABLE_BODY; } + protected boolean isTableFooter() { + return false; + } + /** * @param obj table row in question * @return true if the given table row is the first row of this body. @@ -249,7 +278,7 @@ public class TableBody extends TableCellContainer { firstRow = false; if (!lastCellEndsRow) { columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().signalRowEnd(this); + getTable().getRowGroupBuilder().endRow(this); } } rowsStarted = true; diff --git a/src/java/org/apache/fop/fo/flow/table/TableCell.java b/src/java/org/apache/fop/fo/flow/table/TableCell.java index 34c6266a7..f85d0e97e 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableCell.java +++ b/src/java/org/apache/fop/fo/flow/table/TableCell.java @@ -90,7 +90,7 @@ public class TableCell extends TableFObj { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startCell(this); } @@ -100,7 +100,7 @@ public class TableCell extends TableFObj { * FOEventHandler that we are at the end of the flow. * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { if (!blockItemFound) { if (getUserAgent().validateStrictly()) { missingChildElementError("marker* (%block;)+"); @@ -135,6 +135,21 @@ public class TableCell extends TableFObj { } /** {@inheritDoc} */ + protected void setCollapsedBorders() { + createBorder(CommonBorderPaddingBackground.BEFORE); + createBorder(CommonBorderPaddingBackground.AFTER); + Table table = getTable(); + if (table.hasExplicitColumns()) { + TableColumn col = table.getColumn(getColumnNumber() - 1); + createBorder(CommonBorderPaddingBackground.START, col); + createBorder(CommonBorderPaddingBackground.END, col); + } else { + createBorder(CommonBorderPaddingBackground.START); + createBorder(CommonBorderPaddingBackground.END); + } + } + + /** {@inheritDoc} */ public boolean generatesReferenceAreas() { return true; } diff --git a/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java b/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java index ebb066c5c..7c91be351 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java +++ b/src/java/org/apache/fop/fo/flow/table/TableCellContainer.java @@ -93,6 +93,13 @@ public abstract class TableCellContainer extends TableFObj implements ColumnNumb } } + /** + * Returns the enclosing table-header/footer/body of this container. + * + * @return <code>this</code> for TableBody, or the parent element for TableRow + */ + abstract TableBody getTablePart(); + /** {@inheritDoc} */ public ColumnNumberManager getColumnNumberManager() { return columnNumberManager; diff --git a/src/java/org/apache/fop/fo/flow/table/TableColumn.java b/src/java/org/apache/fop/fo/flow/table/TableColumn.java index aa2dfcb0a..aeb401893 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableColumn.java +++ b/src/java/org/apache/fop/fo/flow/table/TableColumn.java @@ -31,6 +31,7 @@ import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.Property; import org.apache.fop.fo.properties.TableColLength; +import org.apache.fop.layoutmgr.table.CollapsingBorderModel; /** * Class modelling the fo:table-column object. @@ -114,14 +115,27 @@ public class TableColumn extends TableFObj { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { + super.startOfNode(); getFOEventHandler().startColumn(this); } - /** - * {@inheritDoc} - */ - protected void endOfNode() throws FOPException { + void setCollapsedBorders(CollapsingBorderModel collapsingBorderModel) { + this.collapsingBorderModel = collapsingBorderModel; + setCollapsedBorders(); + } + + /** {@inheritDoc} */ + protected void setCollapsedBorders() { + Table table = (Table) parent; + createBorder(CommonBorderPaddingBackground.BEFORE, table); + createBorder(CommonBorderPaddingBackground.AFTER, table); + createBorder(CommonBorderPaddingBackground.START); + createBorder(CommonBorderPaddingBackground.END); + } + + /** {@inheritDoc} */ + public void endOfNode() throws FOPException { getFOEventHandler().endColumn(this); } diff --git a/src/java/org/apache/fop/fo/flow/table/TableFObj.java b/src/java/org/apache/fop/fo/flow/table/TableFObj.java index 53995464b..984f242f2 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableFObj.java +++ b/src/java/org/apache/fop/fo/flow/table/TableFObj.java @@ -30,6 +30,7 @@ import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.NumberProperty; import org.apache.fop.fo.properties.Property; +import org.apache.fop.layoutmgr.table.CollapsingBorderModel; /** * Common base class for table-related FOs @@ -41,6 +42,10 @@ public abstract class TableFObj extends FObj { private Numeric borderEndPrecedence; private Numeric borderStartPrecedence; + public/*TODO*/ BorderSpecification[] resolvedBorders = new BorderSpecification[4]; // TODO + + CollapsingBorderModel collapsingBorderModel; + /** * Main constructor * @@ -122,9 +127,7 @@ public abstract class TableFObj extends FObj { super(propId); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ public Property make(PropertyList propertyList) throws PropertyException { FObj fo = propertyList.getFObj(); @@ -189,4 +192,55 @@ public abstract class TableFObj extends FObj { return p; } } + + /** {@inheritDoc} */ + public void startOfNode() throws FOPException { + super.startOfNode(); + Table table = getTable(); + if (!inMarker() && !table.isSeparateBorderModel()) { + collapsingBorderModel = CollapsingBorderModel.getBorderModelFor(table + .getBorderCollapse()); + resolvedBorders = new BorderSpecification[4]; + setCollapsedBorders(); + } + } + + /* + * TODO made public so that RetrieveMarker can access it. + */ + /** {@inheritDoc} */ + public void endOfNode() throws FOPException { + super.endOfNode(); + } + + /** + * Prepares the borders of this element if the collapsing-border model is in use. + * Conflict resolution with parent elements is done where applicable. + */ + protected abstract void setCollapsedBorders(); + + /** + * Creates a BorderSpecification from the border set on the given side. If no border + * is set, a BorderSpecification with border-style none is created. + * + * @param side one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END + */ + protected void createBorder(int side) { + resolvedBorders[side] = new BorderSpecification(getCommonBorderPaddingBackground() + .getBorderInfo(side), getNameId()); + } + + /** + * Creates a BorderSpecification from the border set on the given side, performing + * conflict resolution with the same border on the given object. + * + * @param side one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END + * @param competitor a parent table element whose side coincides with the given side + * on this element + */ + protected void createBorder(int side, TableFObj competitor) { + createBorder(side); + resolvedBorders[side] = collapsingBorderModel.determineWinner(resolvedBorders[side], + competitor.resolvedBorders[side]); + } } diff --git a/src/java/org/apache/fop/fo/flow/table/TableFooter.java b/src/java/org/apache/fop/fo/flow/table/TableFooter.java index a7ee21406..e886d2ee1 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableFooter.java +++ b/src/java/org/apache/fop/fo/flow/table/TableFooter.java @@ -39,14 +39,15 @@ public class TableFooter extends TableBody { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { + super.startOfNode(); //getFOEventHandler().startBody(this); } /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { // getFOEventHandler().endFooter(this); if (!(tableRowsFound || tableCellsFound)) { missingChildElementError("marker* (table-row+|table-cell+)"); @@ -65,4 +66,9 @@ public class TableFooter extends TableBody { public int getNameId() { return FO_TABLE_FOOTER; } + + /** {@inheritDoc} */ + protected boolean isTableFooter() { + return true; + } } diff --git a/src/java/org/apache/fop/fo/flow/table/TableHeader.java b/src/java/org/apache/fop/fo/flow/table/TableHeader.java index bc9d88952..01ada2aa7 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableHeader.java +++ b/src/java/org/apache/fop/fo/flow/table/TableHeader.java @@ -39,14 +39,15 @@ public class TableHeader extends TableBody { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { + super.startOfNode(); //getFOEventHandler().startHeader(this); } /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { // getFOEventHandler().endHeader(this); if (!(tableRowsFound || tableCellsFound)) { missingChildElementError("marker* (table-row+|table-cell+)"); diff --git a/src/java/org/apache/fop/fo/flow/table/TableRow.java b/src/java/org/apache/fop/fo/flow/table/TableRow.java index edc8d13df..a025f92fd 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableRow.java +++ b/src/java/org/apache/fop/fo/flow/table/TableRow.java @@ -97,7 +97,7 @@ public class TableRow extends TableCellContainer { /** * {@inheritDoc} */ - protected void startOfNode() throws FOPException { + public void startOfNode() throws FOPException { super.startOfNode(); getFOEventHandler().startRow(this); } @@ -105,7 +105,7 @@ public class TableRow extends TableCellContainer { /** * {@inheritDoc} */ - protected void endOfNode() throws FOPException { + public void endOfNode() throws FOPException { if (firstChild == null) { missingChildElementError("(table-cell+)"); } @@ -128,6 +128,25 @@ public class TableRow extends TableCellContainer { } } + /** {@inheritDoc} */ + TableBody getTablePart() { + return (TableBody) parent; + } + + /** {@inheritDoc} */ + boolean isTableRow() { + return true; + } + + /** {inheritDoc} */ + protected void setCollapsedBorders() { + TableBody body = (TableBody) parent; + createBorder(CommonBorderPaddingBackground.START, body); + createBorder(CommonBorderPaddingBackground.END, body); + createBorder(CommonBorderPaddingBackground.BEFORE); + createBorder(CommonBorderPaddingBackground.AFTER); + } + /** @return the "break-after" property. */ public int getBreakAfter() { return breakAfter; diff --git a/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java index 53b7bfca1..e35ad5c27 100644 --- a/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java @@ -19,9 +19,12 @@ package org.apache.fop.fo.flow.table; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; -import org.apache.fop.layoutmgr.table.EmptyGridUnit; +import org.apache.fop.fo.ValidationException; + /** * A row group builder accommodating a variable number of columns. More flexible, but less @@ -31,34 +34,69 @@ class VariableColRowGroupBuilder extends RowGroupBuilder { VariableColRowGroupBuilder(Table t) { super(t); - numberOfColumns = 1; } /** - * Fills the given row group with empty grid units if necessary, so that it matches - * the given number of columns. - * - * @param rowGroup a List of List of GridUnit - * @param numberOfColumns the number of columns that the row group must have + * Each event is recorded and will be played once the table is finished, and the final + * number of columns known. */ - static void fillWithEmptyGridUnits(List rowGroup, int numberOfColumns) { - for (int i = 0; i < rowGroup.size(); i++) { - List effRow = (List) rowGroup.get(i); - for (int j = effRow.size(); j < numberOfColumns; j++) { - effRow.add(new EmptyGridUnit(null, null, null, j)); + private static interface Event { + /** + * Plays this event + * + * @param rowGroupBuilder the delegate builder which will actually create the row + * groups + * @throws ValidationException if a row-spanning cell overflows its parent body + */ + void play(RowGroupBuilder rowGroupBuilder) throws ValidationException; + } + + /** The queue of events sent to this builder. */ + private List events = new LinkedList(); + + /** {@inheritDoc} */ + void addTableCell(final TableCell cell) { + events.add(new Event() { + public void play(RowGroupBuilder rowGroupBuilder) { + rowGroupBuilder.addTableCell(cell); } - } + }); } - /** - * Updates the current row group to match the given number of columns, by adding empty - * grid units if necessary. - * - * @param numberOfColumns new number of columns - */ - void ensureNumberOfColumns(int numberOfColumns) { - this.numberOfColumns = numberOfColumns; - fillWithEmptyGridUnits(rows, numberOfColumns); + /** {@inheritDoc} */ + void endRow(final TableCellContainer container) { + events.add(new Event() { + public void play(RowGroupBuilder rowGroupBuilder) { + rowGroupBuilder.endRow(container); + } + }); } + /** {@inheritDoc} */ + void startTablePart(final TableBody part) { + events.add(new Event() { + public void play(RowGroupBuilder rowGroupBuilder) { + rowGroupBuilder.startTablePart(part); + } + }); + } + + /** {@inheritDoc} */ + void endTablePart(final TableBody tableBody) throws ValidationException { + // TODO catch the ValidationException sooner? + events.add(new Event() { + public void play(RowGroupBuilder rowGroupBuilder) throws ValidationException { + rowGroupBuilder.endTablePart(tableBody); + } + }); + } + + /** {@inheritDoc} */ + void endTable(final TableBody lastTablePart) throws ValidationException { + RowGroupBuilder delegate = new FixedColRowGroupBuilder(table); + for (Iterator eventIter = events.iterator(); eventIter.hasNext();) { + ((Event) eventIter.next()).play(delegate); + } + delegate.endTable(lastTablePart); + } } |