blob: 275905f2daf549cac02e1b5a36e2fa3534583692 [file] [log] [blame]
/*
* 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.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.ValidationException;
/**
* 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 {
/** Number of columns in the corresponding table. */
private int numberOfColumns;
private TableRow currentTableRow = null;
/** 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 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;
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, columnIndex);
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, 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, 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 startTableRow(TableRow tableRow) {
currentTableRow = tableRow;
}
/** {@inheritDoc} */
void endTableRow() {
assert currentTableRow != null;
if (currentRowIndex > 0 && currentTableRow.getBreakBefore() != Constants.EN_AUTO) {
TableEventProducer eventProducer = TableEventProducer.Provider.get(
currentTableRow.getUserAgent().getEventBroadcaster());
eventProducer.breakIgnoredDueToRowSpanning(this, currentTableRow.getName(), true,
currentTableRow.getLocator());
}
if (currentRowIndex < rows.size() - 1
&& currentTableRow.getBreakAfter() != Constants.EN_AUTO) {
TableEventProducer eventProducer = TableEventProducer.Provider.get(
currentTableRow.getUserAgent().getEventBroadcaster());
eventProducer.breakIgnoredDueToRowSpanning(this, currentTableRow.getName(), false,
currentTableRow.getLocator());
}
for (Iterator iter = ((List) rows.get(currentRowIndex)).iterator(); iter.hasNext();) {
GridUnit gu = (GridUnit) iter.next();
// The row hasn't been filled with empty grid units yet
if (gu != null) {
gu.setRow(currentTableRow);
}
}
handleRowEnd(currentTableRow);
}
/** {@inheritDoc} */
void endRow(TablePart part) {
handleRowEnd(part);
}
private void handleRowEnd(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, currentTableRow, i));
}
}
borderResolver.endRow(currentRow, container);
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++;
}
currentTableRow = null;
}
/** {@inheritDoc} */
void startTablePart(TablePart part) {
firstInPart = true;
borderResolver.startPart(part);
}
/** {@inheritDoc} */
void endTablePart() 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();
}
/** {@inheritDoc} */
void endTable() {
borderResolver.endTable();
}
}