diff options
author | Vincent Hennebert <vhennebert@apache.org> | 2007-11-05 16:07:45 +0000 |
---|---|---|
committer | Vincent Hennebert <vhennebert@apache.org> | 2007-11-05 16:07:45 +0000 |
commit | 2a762125322db82658fb650b131f80ed600fc93d (patch) | |
tree | f18aa23be572dc66809b135e958c8fb6faa8fb9f /src/java/org/apache | |
parent | 9f7240917415e7cb777c1b446bdc8b09cca23237 (diff) | |
download | xmlgraphics-fop-2a762125322db82658fb650b131f80ed600fc93d.tar.gz xmlgraphics-fop-2a762125322db82658fb650b131f80ed600fc93d.zip |
First step towards building row groups at the FO tree stage. The built row groups are currently not used and the TableRowIterator stuff remains unchanged; this allows for more atomic commits.
- introduced RowGroupBuilder hierarchy;
- moved TableRowIterator test cases into fotree, and integrated them in the test suite.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@592058 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache')
8 files changed, 302 insertions, 9 deletions
diff --git a/src/java/org/apache/fop/fo/flow/FixedColRowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/FixedColRowGroupBuilder.java new file mode 100644 index 000000000..5a4bd24b2 --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/FixedColRowGroupBuilder.java @@ -0,0 +1,35 @@ +/* + * 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; + + +/** + * A row group builder optimised for a fixed number of columns, known before the parsing + * of cells starts (that is, if the fo:table has explicit fo:table-column children). + */ +class FixedColRowGroupBuilder extends RowGroupBuilder { + + + FixedColRowGroupBuilder(Table t) { + super(t); + numberOfColumns = t.getNumberOfColumns(); + } + +} diff --git a/src/java/org/apache/fop/fo/flow/RowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/RowGroupBuilder.java new file mode 100644 index 000000000..359ccd59a --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/RowGroupBuilder.java @@ -0,0 +1,132 @@ +/* + * 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; + +import java.util.ArrayList; +import java.util.List; + +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 + * such a group has only cells which don't span over several rows, or whose spanning + * starts on this row. Similarly, the last row has only non-row spanning cells or spans + * which end on this row. + */ +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; + + /** + * Creates and initialises a new builder for the given table. + * + * @param t a table + */ + protected RowGroupBuilder(Table t) { + table = t; + initialize(); + } + + /** + * Prepares this builder for creating a new row group. + */ + private void initialize() { + rows = new ArrayList(); + currentRowIndex = 0; + } + + /** + * Adds a table-cell to the row-group, creating {@link GridUnit}s accordingly. + * + * @param cell + */ + 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)); + } + } + + } + + /** + * Signals that a table row has just ended, potentially finishing the current row + * group. + * + * @param body the table-body containing the row. Its + * {@link TableBody#addRowGroup(List)} method will be called if the current row group + * is finished. + */ + void signalNewRow(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++; + } + } + + /** + * Finishes and records the last row-group of the given table-body, if any. If there + * is no fo:table-row and the last cell of the table-body didn't have ends-row="true", + * then the {@link signalNewRow} method has not been called and the last row group has + * yet to be recorded. + * + * @param tableBody + */ + void finishLastRowGroup(TableBody tableBody) { + if (rows.size() > 0) { + tableBody.addRowGroup(rows); + } + // Reset, in case this rowGroupBuilder is re-used for other + // table-header/footer/body + initialize(); + } + +} diff --git a/src/java/org/apache/fop/fo/flow/Table.java b/src/java/org/apache/fop/fo/flow/Table.java index 87f224c65..ab58686fc 100644 --- a/src/java/org/apache/fop/fo/flow/Table.java +++ b/src/java/org/apache/fop/fo/flow/Table.java @@ -20,13 +20,13 @@ package org.apache.fop.fo.flow; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Length; import org.apache.fop.datatypes.ValidationPercentBaseContext; import org.apache.fop.fo.FONode; -import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.StaticPropertyList; import org.apache.fop.fo.ValidationException; @@ -86,6 +86,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { private boolean hasExplicitColumns = false; private boolean columnsFinalized = false; + private RowGroupBuilder rowGroupBuilder; /** * The table's property list. Used in case the table has @@ -226,6 +227,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { } } this.propList = null; + rowGroupBuilder = null; } getFOEventHandler().endTable(this); @@ -250,9 +252,15 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { case FO_TABLE_HEADER: case FO_TABLE_FOOTER: case FO_TABLE_BODY: - if (hasExplicitColumns && !columnsFinalized) { + if (!columnsFinalized) { columnsFinalized = true; - finalizeColumns(); + if (hasExplicitColumns) { + finalizeColumns(); + rowGroupBuilder = new FixedColRowGroupBuilder(this); + } else { + rowGroupBuilder = new VariableColRowGroupBuilder(this); + } + } switch (childId) { case FO_TABLE_FOOTER: @@ -293,9 +301,36 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { * columns */ void ensureColumnNumber(int columnNumber) throws FOPException { + assert !hasExplicitColumns; 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) @@ -499,18 +534,22 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { */ public FONode clone(FONode parent, boolean removeChildren) throws FOPException { - FObj fobj = (FObj) super.clone(parent, removeChildren); + Table clone = (Table) super.clone(parent, removeChildren); + clone.columnsFinalized = false; if (removeChildren) { - Table t = (Table) fobj; - t.columns = new ArrayList(); - t.tableHeader = null; - t.tableFooter = null; + clone.columns = new ArrayList(); + clone.tableHeader = null; + clone.tableFooter = null; } - return fobj; + return clone; } /** {@inheritDoc} */ public ColumnNumberManager getColumnNumberManager() { return columnNumberManager; } + + RowGroupBuilder getRowGroupBuilder() { + return rowGroupBuilder; + } } diff --git a/src/java/org/apache/fop/fo/flow/TableBody.java b/src/java/org/apache/fop/fo/flow/TableBody.java index 72c0ff610..e8e1183b3 100644 --- a/src/java/org/apache/fop/fo/flow/TableBody.java +++ b/src/java/org/apache/fop/fo/flow/TableBody.java @@ -20,6 +20,8 @@ package org.apache.fop.fo.flow; import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FONode; @@ -55,6 +57,8 @@ public class TableBody extends TableCellContainer { private boolean rowsStarted = false; + private List rowGroups = new LinkedList(); + /** * @param parent FONode that is the parent of the object */ @@ -119,6 +123,8 @@ public class TableBody extends TableCellContainer { + "Expected: marker* (table-row+|table-cell+)"); getParent().removeChild(this); } + } else { + getTable().getRowGroupBuilder().finishLastRowGroup(this); } } @@ -165,6 +171,7 @@ public class TableBody extends TableCellContainer { case FO_TABLE_ROW: if (rowsStarted) { columnNumberManager.prepareForNextRow(pendingSpans); + getTable().getRowGroupBuilder().signalNewRow(this); } rowsStarted = true; break; @@ -175,6 +182,7 @@ public class TableBody extends TableCellContainer { if (cell.endsRow()) { firstRow = false; columnNumberManager.prepareForNextRow(pendingSpans); + getTable().getRowGroupBuilder().signalNewRow(this); } break; default: @@ -184,6 +192,14 @@ public class TableBody extends TableCellContainer { super.addChildNode(child); } + void addRowGroup(List rowGroup) { + rowGroups.add(rowGroup); + } + + List getRowGroups() { + return rowGroups; + } + /** * @return the Common Border, Padding, and Background Properties. */ @@ -218,6 +234,7 @@ public class TableBody extends TableCellContainer { TableCell previousCell = (TableCell) getChildNodes().lastNode(); if (!previousCell.endsRow()) { columnNumberManager.prepareForNextRow(pendingSpans); + getTable().getRowGroupBuilder().signalNewRow(this); } } rowsStarted = true; diff --git a/src/java/org/apache/fop/fo/flow/TableCellContainer.java b/src/java/org/apache/fop/fo/flow/TableCellContainer.java index 9f9b72d75..c409e01af 100644 --- a/src/java/org/apache/fop/fo/flow/TableCellContainer.java +++ b/src/java/org/apache/fop/fo/flow/TableCellContainer.java @@ -95,6 +95,8 @@ public abstract class TableCellContainer extends TableFObj implements ColumnNumb } columnNumberManager.signalUsedColumnNumbers(colNumber, colNumber + colSpan - 1); + + t.getRowGroupBuilder().addTableCell(cell); } private void handleCellWidth(TableCell cell, int colNumber, int colSpan) throws FOPException { diff --git a/src/java/org/apache/fop/fo/flow/TableFooter.java b/src/java/org/apache/fop/fo/flow/TableFooter.java index a543ca11f..a16586af9 100644 --- a/src/java/org/apache/fop/fo/flow/TableFooter.java +++ b/src/java/org/apache/fop/fo/flow/TableFooter.java @@ -50,6 +50,8 @@ public class TableFooter extends TableBody { // getFOEventHandler().endFooter(this); if (!(tableRowsFound || tableCellsFound)) { missingChildElementError("marker* (table-row+|table-cell+)"); + } else { + getTable().getRowGroupBuilder().finishLastRowGroup(this); } // convertCellsToRows(); } diff --git a/src/java/org/apache/fop/fo/flow/TableHeader.java b/src/java/org/apache/fop/fo/flow/TableHeader.java index 568303c0d..eb3568d47 100644 --- a/src/java/org/apache/fop/fo/flow/TableHeader.java +++ b/src/java/org/apache/fop/fo/flow/TableHeader.java @@ -50,6 +50,8 @@ public class TableHeader extends TableBody { // getFOEventHandler().endHeader(this); if (!(tableRowsFound || tableCellsFound)) { missingChildElementError("marker* (table-row+|table-cell+)"); + } else { + getTable().getRowGroupBuilder().finishLastRowGroup(this); } // convertCellsToRows(); } diff --git a/src/java/org/apache/fop/fo/flow/VariableColRowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/VariableColRowGroupBuilder.java new file mode 100644 index 000000000..a59c98786 --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/VariableColRowGroupBuilder.java @@ -0,0 +1,64 @@ +/* + * 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; + +import java.util.List; + +import org.apache.fop.layoutmgr.table.EmptyGridUnit; + +/** + * A row group builder accommodating a variable number of columns. More flexible, but less + * efficient. + */ +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 + */ + 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)); + } + } + } + + /** + * 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); + } + +} |