aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/java/org/apache/fop/fo/flow/FixedColRowGroupBuilder.java35
-rw-r--r--src/java/org/apache/fop/fo/flow/RowGroupBuilder.java132
-rw-r--r--src/java/org/apache/fop/fo/flow/Table.java57
-rw-r--r--src/java/org/apache/fop/fo/flow/TableBody.java17
-rw-r--r--src/java/org/apache/fop/fo/flow/TableCellContainer.java2
-rw-r--r--src/java/org/apache/fop/fo/flow/TableFooter.java2
-rw-r--r--src/java/org/apache/fop/fo/flow/TableHeader.java2
-rw-r--r--src/java/org/apache/fop/fo/flow/VariableColRowGroupBuilder.java64
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);
+ }
+
+}