return this.fopimage;
}
+ /**
+ * @param bDiscard indicates whether the .conditionality component should be
+ * considered (start of a reference-area)
+ */
public int getBorderStartWidth(boolean bDiscard) {
return getBorderWidth(START, bDiscard);
}
+ /**
+ * @param bDiscard indicates whether the .conditionality component should be
+ * considered (end of a reference-area)
+ */
public int getBorderEndWidth(boolean bDiscard) {
return getBorderWidth(END, bDiscard);
}
+ /**
+ * @param bDiscard indicates whether the .conditionality component should be
+ * considered (start of a reference-area)
+ */
public int getBorderBeforeWidth(boolean bDiscard) {
return getBorderWidth(BEFORE, bDiscard);
}
+ /**
+ * @param bDiscard indicates whether the .conditionality component should be
+ * considered (end of a reference-area)
+ */
public int getBorderAfterWidth(boolean bDiscard) {
return getBorderWidth(AFTER, bDiscard);
}
* SourceList to targetList
* @param sourceList source list
* @param targetList target list receiving the wrapped position elements
- * @param force if true, every Position is wrapper regardless of its LM of origin
+ * @param force if true, every Position is wrapped regardless of its LM of origin
*/
protected void wrapPositionElements(List sourceList, List targetList, boolean force) {
other[1] = otherRow.getCommonBorderPaddingBackground().getBorderInfo(otherSide);
}
if (currentBody != null
- && ((side == BEFORE && currentGridUnit.getFlag(GridUnit.FIRST_IN_BODY))
- || (side == AFTER && currentGridUnit.getFlag(GridUnit.LAST_IN_BODY))
+ && ((side == BEFORE && currentGridUnit.getFlag(GridUnit.FIRST_IN_PART))
+ || (side == AFTER && currentGridUnit.getFlag(GridUnit.LAST_IN_PART))
|| (currentGridUnit.getFlag(GridUnit.IN_FIRST_COLUMN) && side == START)
|| (currentGridUnit.getFlag(GridUnit.IN_LAST_COLUMN) && side == END))) {
//row group (=body, table-header or table-footer)
}
if (otherGridUnit != null
&& otherBody != null
- && ((otherSide == BEFORE && otherGridUnit.getFlag(GridUnit.FIRST_IN_BODY))
- || (otherSide == AFTER && otherGridUnit.getFlag(GridUnit.LAST_IN_BODY)))) {
+ && ((otherSide == BEFORE && otherGridUnit.getFlag(GridUnit.FIRST_IN_PART))
+ || (otherSide == AFTER && otherGridUnit.getFlag(GridUnit.LAST_IN_PART)))) {
//row group (=body, table-header or table-footer)
other[2] = otherBody.getCommonBorderPaddingBackground().getBorderInfo(otherSide);
}
* This class represents an effective row in a table and holds a list of grid units occupying
* the row as well as some additional values.
*/
-public class EffRow {
+class EffRow {
/** Indicates that the row is the first in a table-body */
- public static final int FIRST_IN_BODY = GridUnit.FIRST_IN_BODY;
+ public static final int FIRST_IN_PART = GridUnit.FIRST_IN_PART;
/** Indicates that the row is the last in a table-body */
- public static final int LAST_IN_BODY = GridUnit.LAST_IN_BODY;
+ public static final int LAST_IN_PART = GridUnit.LAST_IN_PART;
private List gridUnits = new java.util.ArrayList();
private int index;
+ /** One of HEADER, FOOTER, BODY */
private int bodyType;
private MinOptMax height;
private MinOptMax explicitHeight;
/**
* Returns a flag for this effective row. Only a subset of the flags on GridUnit is supported.
* The flag is determined by inspecting flags on the EffRow's GridUnits.
- * @param which the requested flag
+ * @param which the requested flag (one of {@link EffRow#FIRST_IN_PART} or {@link
+ * EffRow#LAST_IN_PART})
* @return true if the flag is set
*/
public boolean getFlag(int which) {
- if (which == FIRST_IN_BODY) {
- return getGridUnit(0).getFlag(GridUnit.FIRST_IN_BODY);
- } else if (which == LAST_IN_BODY) {
- return getGridUnit(0).getFlag(GridUnit.LAST_IN_BODY);
+ if (which == FIRST_IN_PART) {
+ return getGridUnit(0).getFlag(GridUnit.FIRST_IN_PART);
+ } else if (which == LAST_IN_PART) {
+ return getGridUnit(0).getFlag(GridUnit.LAST_IN_PART);
} else {
throw new IllegalArgumentException("Illegal flag queried: " + which);
}
sb.append("}");
return sb.toString();
}
-}
\ No newline at end of file
+}
public static final int IN_FIRST_COLUMN = 0;
/** Indicates that the grid unit is in the last column. */
public static final int IN_LAST_COLUMN = 1;
- /** Indicates that the grid unit is in the first row (context: table). */
+ /** Indicates that the grid unit is in the first row of the table. */
public static final int FIRST_IN_TABLE = 2;
- /** Indicates that the grid unit is in the first row (context: body). */
- public static final int FIRST_IN_BODY = 3;
- /** Indicates that the grid unit is in the last row (context: body). */
- public static final int LAST_IN_BODY = 4;
- /** Indicates that the grid unit is in the last row (context: table). */
+ /** Indicates that the grid unit is in the first row of the table part (header, footer, body). */
+ public static final int FIRST_IN_PART = 3;
+ /** Indicates that the grid unit is in the last row of the table part (header, footer, body). */
+ public static final int LAST_IN_PART = 4;
+ /** Indicates that the grid unit is in the last row of the table. */
public static final int LAST_IN_TABLE = 5;
/** Indicates that the primary grid unit has a pending keep-with-next. */
public static final int KEEP_WITH_NEXT_PENDING = 6;
/** Indicates that the primary grid unit has a pending keep-with-previous. */
public static final int KEEP_WITH_PREVIOUS_PENDING = 7;
-
+
/** Primary grid unit */
private PrimaryGridUnit primary;
/** Table cell which occupies this grid unit */
private TableCell cell;
- /** Table row which occupied this grid unit (may be null) */
+ /** Table row which occupies this grid unit (may be null) */
private TableRow row;
/** Table column that this grid unit belongs to */
private TableColumn column;
-
+
/** start index of grid unit within row in column direction */
private int startCol;
/** index of grid unit within cell in column direction */
private CommonBorderPaddingBackground effectiveBorders;
/** flags for the grid unit */
private byte flags = 0;
-
-
+
+
+ /**
+ * Creates a new grid unit.
+ *
+ * @param cell table cell which occupies this grid unit
+ * @param column table column this grid unit belongs to
+ * @param startCol index of the column this grid unit belongs to
+ * @param colSpanIndex index of this grid unit in the span, in column direction
+ */
public GridUnit(TableCell cell, TableColumn column, int startCol, int colSpanIndex) {
this(null, cell, column, startCol, colSpanIndex);
}
-
+
+ /**
+ * Creates a new grid unit.
+ *
+ * @param primary ??
+ * @param column table column this grid unit belongs to
+ * @param startCol index of the column this grid unit belongs to
+ * @param colSpanIndex index of this grid unit in the span, in column direction
+ */
public GridUnit(PrimaryGridUnit primary, TableColumn column, int startCol, int colSpanIndex) {
this(primary, primary.getCell(), column, startCol, colSpanIndex);
}
-
+
+ /**
+ * Creates a new grid unit.
+ *
+ * @param primary ??
+ * @param cell table cell which occupies this grid unit
+ * @param column table column this grid unit belongs to
+ * @param startCol index of the column this grid unit belongs to
+ * @param colSpanIndex index of this grid unit in the span, in column direction
+ */
protected GridUnit(PrimaryGridUnit primary, TableCell cell, TableColumn column, int startCol, int colSpanIndex) {
this.primary = primary;
this.cell = cell;
this.startCol = startCol;
this.colSpanIndex = colSpanIndex;
}
-
+
public TableCell getCell() {
return cell;
}
-
+
public TableColumn getColumn() {
return column;
}
-
+
public TableRow getRow() {
if (row != null) {
return row;
return null;
}
}
-
+
/**
* Sets the table-row FO, if applicable.
* @param row the table-row FO
}
return (TableBody)node;
}
-
+
public Table getTable() {
FONode node = getBody();
while (node != null && !(node instanceof Table)) {
}
return (Table)node;
}
-
+
/**
* @return the primary grid unit if this is a spanned grid unit
*/
public boolean isPrimary() {
return false;
}
-
+
public boolean isEmpty() {
return cell == null;
}
-
+
public int getStartCol() {
return startCol;
}
-
+
/** @return true if the grid unit is the last in column spanning direction */
public boolean isLastGridUnitColSpan() {
if (cell != null) {
return true;
}
}
-
- /** @return true if the grid unit is the last in column spanning direction */
+
+ /** @return true if the grid unit is the last in row spanning direction */
public boolean isLastGridUnitRowSpan() {
if (cell != null) {
return (rowSpanIndex == cell.getNumberRowsSpanned() - 1);
return true;
}
}
-
+
/**
* @return the index of the grid unit inside a cell in row direction
*/
public int getRowSpanIndex() {
return rowSpanIndex;
}
-
+
/**
* @return the index of the grid unit inside a cell in column direction
*/
/**
* Returns a BorderInfo instance for a side of the currently applicable cell before border
* resolution (i.e. the value from the FO). A return value of null indicates an empty cell.
- * See CollapsingBorderModel(EyeCatching) where this method is used.
+ * See CollapsingBorderModel(EyeCatching) where this method is used.
* @param side for which side to return the BorderInfo
* @return the requested BorderInfo instance or null if the grid unit is an empty cell
*/
return null;
}
}
-
+
/**
* @return the resolved normal borders for this grid unit
*/
public CommonBorderPaddingBackground getBorders() {
return effectiveBorders;
}
-
+
/**
* @return true if the grid unit has any borders.
*/
public boolean hasBorders() {
return (getBorders() != null) && getBorders().hasBorder();
}
-
+
/**
* Assigns the borders from the given cell to this cell info. Used in
* case of separate border model.
effectiveBorders = cell.getCommonBorderPaddingBackground();
}
}
-
+
/**
* Resolve collapsing borders for the given cell. Used in case of the collapsing border model.
* @param other neighbouring grid unit if any
public void resolveBorder(GridUnit other, int side) {
resolveBorder(other, side, 0);
}
-
+
/**
* Resolve collapsing borders for the given cell. Used in case of the collapsing border model.
* @param other neighbouring grid unit if any
if (effectiveBorders == null) {
effectiveBorders = new CommonBorderPaddingBackground();
}
- effectiveBorders.setBorderInfo(borderModel.determineWinner(this, other,
+ effectiveBorders.setBorderInfo(borderModel.determineWinner(this, other,
side, resFlags), side);
if (cell != null) {
effectiveBorders.setPadding(cell.getCommonBorderPaddingBackground());
}
}
-
+
/**
* Returns a flag for this GridUnit.
* @param which the requested flag
public boolean getFlag(int which) {
return (flags & (1 << which)) != 0;
}
-
+
/**
* Sets a flag on a GridUnit.
* @param which the flag to set
flags &= ~(1 << which); //clear flag
}
}
-
+
/**
* @return the grid unit just below this grid unit if the cell is spanning.
*/
private LinkedList elements;
/** Index of row where this cell starts */
private int startRow;
- /** Links to the spanned grid units. (List of GridUnit arrays, one array represents a row) */
+ /** Links to the spanned grid units. (List of GridUnit arrays, one array represents a row) */
private List rows;
/** The calculated size of the cell's content. (cached value) */
private int contentLength = -1;
-
+
+ /**
+ * Creates a new primary grid unit.
+ *
+ * @param cell table cell which occupies this grid unit
+ * @param column table column this grid unit belongs to
+ * @param startCol index of the column this grid unit belongs to, zero-based
+ * @param startRow index of the row this grid unit belongs to, zero-based
+ */
public PrimaryGridUnit(TableCell cell, TableColumn column, int startCol, int startRow) {
super(cell, column, startCol, 0);
this.startRow = startRow;
cellLM = new TableCellLayoutManager(cell, this);
}
}
-
+
public TableCellLayoutManager getCellLM() {
return cellLM;
}
-
+
public boolean isPrimary() {
return true;
}
-
+
+ /**
+ * Sets the Knuth elements for the table cell containing this grid unit.
+ *
+ * @param elements a list of ListElement (?)
+ */
public void setElements(LinkedList elements) {
this.elements = elements;
}
-
+
public LinkedList getElements() {
return this.elements;
}
-
- /**
- * @return Returns the half the maximum before border width of this cell.
+
+ /**
+ * @return half the maximum before border width of this cell.
*/
public int getHalfMaxBeforeBorderWidth() {
int value = 0;
GridUnit[] row = (GridUnit[])getRows().get(0);
for (int i = 0; i < row.length; i++) {
if (row[i].hasBorders()) {
- before = Math.max(before,
+ before = Math.max(before,
row[i].getBorders().getBorderBeforeWidth(false));
}
}
}
return value;
}
-
- /**
- * @return Returns the half the maximum after border width of this cell.
+
+ /**
+ * @return half the maximum after border width of this cell.
*/
public int getHalfMaxAfterBorderWidth() {
int value = 0;
}
return value;
}
-
- /**
- * @return Returns the sum of half the maximum before and after border
+
+ /**
+ * @return the sum of half the maximum before and after border
* widths of this cell.
*/
public int getHalfMaxBorderWidth() {
return getHalfMaxBeforeBorderWidth() + getHalfMaxAfterBorderWidth();
}
-
+
/** @param value The length of the cell content to remember. */
public void setContentLength(int value) {
this.contentLength = value;
}
-
- /** @return Returns the length of the cell content. */
+
+ /** @return the length of the cell content. */
public int getContentLength() {
return contentLength;
}
if (!getCell().getBlockProgressionDimension().getOptimum(null).isAuto()) {
return true;
}
- if (getRow() != null
+ if (getRow() != null
&& !getRow().getBlockProgressionDimension().getOptimum(null).isAuto()) {
return true;
}
return false;
}
+ /**
+ * Returns the grid units belonging to the same span as this one.
+ *
+ * @return a list of GridUnit[], each array corresponds to a row
+ */
public List getRows() {
return this.rows;
}
-
+
public void addRow(GridUnit[] row) {
if (rows == null) {
rows = new java.util.ArrayList();
}
rows.add(row);
}
-
+
+ /**
+ * Returns the index of the row this grid unit belongs to.
+ *
+ * @return the index of the row this grid unit belongs to.
+ */
public int getStartRow() {
return this.startRow;
}
+ /**
+ * Returns the widths of the start- and end-borders of the span this grid unit belongs
+ * to.
+ *
+ * @return a two-element array containing the widths of the start-border then the
+ * end-border
+ */
public int[] getStartEndBorderWidths() {
int[] widths = new int[2];
if (rows == null) {
} else {
for (int i = 0; i < rows.size(); i++) {
GridUnit[] gridUnits = (GridUnit[])rows.get(i);
- widths[0] = Math.max(widths[0],
+ widths[0] = Math.max(widths[0],
(gridUnits[0]).
getBorders().getBorderStartWidth(false));
- widths[1] = Math.max(widths[1],
+ widths[1] = Math.max(widths[1],
(gridUnits[gridUnits.length - 1]).
getBorders().getBorderEndWidth(false));
}
}
return widths;
}
-
+
/** @see java.lang.Object#toString() */
public String toString() {
StringBuffer sb = new StringBuffer(super.toString());
/** @return true if this cell spans over more than one grid unit. */
public boolean hasSpanning() {
- return (getCell().getNumberColumnsSpanned() > 1)
+ return (getCell().getNumberColumnsSpanned() > 1)
|| (getCell().getNumberRowsSpanned() > 1);
}
-
+
}
private static Log log = LogFactory.getLog(TableContentLayoutManager.class);
private TableLayoutManager tableLM;
- private TableRowIterator trIter;
+ private TableRowIterator bodyIter;
private TableRowIterator headerIter;
private TableRowIterator footerIter;
private LinkedList headerList;
public TableContentLayoutManager(TableLayoutManager parent) {
this.tableLM = parent;
Table table = getTableLM().getTable();
- this.trIter = new TableRowIterator(table, getTableLM().getColumns(), TableRowIterator.BODY);
+ this.bodyIter = new TableRowIterator(table, getTableLM().getColumns(),
+ TableRowIterator.BODY);
if (table.getTableHeader() != null) {
headerIter = new TableRowIterator(table,
getTableLM().getColumns(), TableRowIterator.HEADER);
this.headerList = getKnuthElementsForRowIterator(
headerIter, context, alignment, TableRowIterator.HEADER);
ElementListUtils.removeLegalBreaks(this.headerList);
- this.headerNetHeight =
- ElementListUtils.calcContentLength(this.headerList);
+ this.headerNetHeight
+ = ElementListUtils.calcContentLength(this.headerList);
if (log.isDebugEnabled()) {
log.debug("==> Header: "
+ headerNetHeight + " - " + this.headerList);
this.footerList = getKnuthElementsForRowIterator(
footerIter, context, alignment, TableRowIterator.FOOTER);
ElementListUtils.removeLegalBreaks(this.footerList);
- this.footerNetHeight =
- ElementListUtils.calcContentLength(this.footerList);
+ this.footerNetHeight
+ = ElementListUtils.calcContentLength(this.footerList);
if (log.isDebugEnabled()) {
log.debug("==> Footer: "
+ footerNetHeight + " - " + this.footerList);
footerAsLast = box;
}
LinkedList returnList = getKnuthElementsForRowIterator(
- trIter, context, alignment, TableRowIterator.BODY);
+ bodyIter, context, alignment, TableRowIterator.BODY);
if (headerAsFirst != null) {
returnList.add(0, headerAsFirst);
} else if (headerAsSecondToLast != null) {
TableRowIterator iter) {
for (int rgi = 0; rgi < rowGroup.length; rgi++) {
EffRow row = rowGroup[rgi];
- EffRow prev = iter.getCachedRow(row.getIndex() - 1);
- EffRow next = iter.getCachedRow(row.getIndex() + 1);
- if (next == null) {
- //It wasn't read, yet, or we are at the last row
- next = iter.getNextRow();
- iter.backToPreviousRow();
+ EffRow prevRow = iter.getPrecedingRow(row);
+ EffRow nextRow = iter.getFollowingRow(row);
+ if ((prevRow == null) && (iter == this.bodyIter) && (this.headerIter != null)) {
+ prevRow = this.headerIter.getLastRow();
}
- if ((prev == null) && (iter == this.trIter) && (this.headerIter != null)) {
- prev = this.headerIter.getLastRow();
+ if ((nextRow == null) && (iter == this.headerIter)) {
+ nextRow = this.bodyIter.getFirstRow();
}
- if ((next == null) && (iter == this.headerIter)) {
- next = this.trIter.getFirstRow();
+ if ((nextRow == null) && (iter == this.bodyIter) && (this.footerIter != null)) {
+ nextRow = this.footerIter.getFirstRow();
}
- if ((next == null) && (iter == this.trIter) && (this.footerIter != null)) {
- next = this.footerIter.getFirstRow();
- }
- if ((prev == null) && (iter == this.footerIter)) {
+ if ((prevRow == null) && (iter == this.footerIter)) {
//TODO This could be bad for memory consumption because it already causes the
//whole body iterator to be prefetched!
- prev = this.trIter.getLastRow();
+ prevRow = this.bodyIter.getLastRow();
}
- log.debug(prev + " - " + row + " - " + next);
+ log.debug(prevRow + " - " + row + " - " + nextRow);
//Determine the grid units necessary for getting all the borders right
int guCount = row.getGridUnits().size();
- if (prev != null) {
- guCount = Math.max(guCount, prev.getGridUnits().size());
+ if (prevRow != null) {
+ guCount = Math.max(guCount, prevRow.getGridUnits().size());
}
- if (next != null) {
- guCount = Math.max(guCount, next.getGridUnits().size());
+ if (nextRow != null) {
+ guCount = Math.max(guCount, nextRow.getGridUnits().size());
}
GridUnit gu = row.getGridUnit(0);
//Create empty grid units to hold resolved borders of neighbouring cells
gu = row.getGridUnit(i);
GridUnit other;
int flags = 0;
- if (prev != null && i < prev.getGridUnits().size()) {
- other = prev.getGridUnit(i);
+ if (prevRow != null && i < prevRow.getGridUnits().size()) {
+ other = prevRow.getGridUnit(i);
} else {
other = null;
}
|| other.isEmpty()
|| gu.isEmpty()
|| gu.getPrimary() != other.getPrimary()) {
- if ((iter == this.trIter)
+ if ((iter == this.bodyIter)
&& gu.getFlag(GridUnit.FIRST_IN_TABLE)
&& (this.headerIter == null)) {
flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE;
}
flags = 0;
- if (next != null && i < next.getGridUnits().size()) {
- other = next.getGridUnit(i);
+ if (nextRow != null && i < nextRow.getGridUnits().size()) {
+ other = nextRow.getGridUnit(i);
} else {
other = null;
}
|| other.isEmpty()
|| gu.isEmpty()
|| gu.getPrimary() != other.getPrimary()) {
- if ((iter == this.trIter)
+ if ((iter == this.bodyIter)
&& gu.getFlag(GridUnit.LAST_IN_TABLE)
&& (this.footerIter == null)) {
flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE;
}
/**
- * Adds the areas generated my this layout manager to the area tree.
+ * Adds the areas generated by this layout manager to the area tree.
* @param parentIter the position iterator
* @param layoutContext the layout context for adding areas
*/
body = part.pgu.getBody();
}
if (tcpos.getFlag(TableContentPosition.FIRST_IN_ROWGROUP)
- && tcpos.row.getFlag(EffRow.FIRST_IN_BODY)) {
+ && tcpos.row.getFlag(EffRow.FIRST_IN_PART)) {
firstPos = true;
}
if (tcpos.getFlag(TableContentPosition.LAST_IN_ROWGROUP)
- && tcpos.row.getFlag(EffRow.LAST_IN_BODY)) {
+ && tcpos.row.getFlag(EffRow.LAST_IN_PART)) {
lastPos = true;
getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
true, firstPos, lastPos);
/**
* LayoutManager for a table FO.
- * A table consists of oldColumns, table header, table footer and multiple
+ * A table consists of columns, table header, table footer and multiple
* table bodies.
* The header, footer and body add the areas created from the table cells.
- * The table then creates areas for the oldColumns, bodies and rows
+ * The table then creates areas for the columns, bodies and rows
* the render background.
*/
public class TableLayoutManager extends BlockStackingLayoutManager
//Spaces, border and padding to be repeated at each break
addPendingMarks(context);
- LinkedList returnedList = null;
+ LinkedList contentKnuthElements = null;
LinkedList contentList = new LinkedList();
//Position returnPosition = new NonLeafPosition(this, null);
//Body prevLM = null;
if (contentLM == null) {
contentLM = new TableContentLayoutManager(this);
}
- returnedList = contentLM.getNextKnuthElements(childLC, alignment);
+ contentKnuthElements = contentLM.getNextKnuthElements(childLC, alignment);
if (childLC.isKeepWithNextPending()) {
log.debug("TableContentLM signals pending keep-with-next");
context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING);
}
//Set index values on elements coming from the content LM
- Iterator iter = returnedList.iterator();
+ Iterator iter = contentKnuthElements.iterator();
while (iter.hasNext()) {
ListElement el = (ListElement)iter.next();
notifyPos(el.getPosition());
}
- log.debug(returnedList);
+ log.debug(contentKnuthElements);
- if (returnedList.size() == 1
- && ((ListElement)returnedList.getFirst()).isForcedBreak()) {
+ if (contentKnuthElements.size() == 1
+ && ((ListElement)contentKnuthElements.getFirst()).isForcedBreak()) {
// a descendant of this block has break-before
if (returnList.size() == 0) {
// the first child (or its first child ...) has
//FIX ME
//bSpaceBeforeServed = false;
}
- contentList.addAll(returnedList);
+ contentList.addAll(contentKnuthElements);
// "wrap" the Position inside each element
// moving the elements from contentList to returnList
- returnedList = new LinkedList();
+ contentKnuthElements = new LinkedList();
wrapPositionElements(contentList, returnList);
return returnList;
// a penalty
}
}*/
- contentList.addAll(returnedList);
- if (returnedList.size() > 0) {
- if (((ListElement)returnedList.getLast()).isForcedBreak()) {
+ contentList.addAll(contentKnuthElements);
+ if (contentKnuthElements.size() > 0) {
+ if (((ListElement)contentKnuthElements.getLast()).isForcedBreak()) {
// a descendant of this block has break-after
if (false /*curLM.isFinished()*/) {
// there is no other content in this block;
setFinished(true);
}
- returnedList = new LinkedList();
+ contentKnuthElements = new LinkedList();
wrapPositionElements(contentList, returnList);
return returnList;
/**
* The table area is a reference area that contains areas for
- * oldColumns, bodies, rows and the contents are in cells.
+ * columns, bodies, rows and the contents are in cells.
*
* @param parentIter the position iterator
* @param layoutContext the layout context for adding areas
/**
- * <p>Iterator that lets the table layout manager step over all rows of a table.
- * </p>
- * <p>Note: This class is not thread-safe.
- * </p>
+ * Iterator that lets the table layout manager step over all of the rows of a part of the
+ * table (table-header, table-footer or table-body).
+ * <p>Note: This class is not thread-safe.</p>
*/
public class TableRowIterator {
- /** Selects the list of table-body elements for iteration. */
+ /** Selects the table-body elements for iteration. */
public static final int BODY = 0;
- /** Selects the table-header element for iteration. */
+ /** Selects the table-header elements for iteration. */
public static final int HEADER = 1;
- /** Selects the table-footer element for iteration. */
- public static final int FOOTER = 2;
-
+ /** Selects the table-footer elements for iteration. */
+ public static final int FOOTER = 2;
+
/** Logger **/
private static Log log = LogFactory.getLog(TableRowIterator.class);
- /** The table on with this instance operates. */
+ /** The table on which this instance operates. */
protected Table table;
+ /** Column setup of the operated table. */
private ColumnSetup columns;
- private int type;
-
- /** Holds the current row (TableCell instances) */
+
+ /** Part of the table over which to iterate. One of BODY, HEADER or FOOTER. */
+ private int tablePart;
+
+ /** Holds the currently fetched row (TableCell instances). */
private List currentRow = new java.util.ArrayList();
- /** Holds the grid units of cell from the last row while will span over the current row
- * (GridUnit instance) */
- private List lastRowsSpanningCells = new java.util.ArrayList();
- private int currentRowIndex = -1;
- //TODO rows should later be a Jakarta Commons LinkedList so concurrent modifications while
- //using a ListIterator are possible
- /** List of cache rows. */
- private List rows = new java.util.ArrayList();
- //private int indexOfFirstRowInList;
- private int currentIndex = -1;
+
+ /**
+ * Holds the grid units of cells from the previous row which will span over the
+ * current row. Should be read "previous row's spanning cells". List of GridUnit
+ * instances.
+ */
+ private List previousRowsSpanningCells = new java.util.ArrayList();
+
+ /** Index of the row currently being fetched. */
+ private int fetchIndex = -1;
+
+ /** Spans found on the current row which will also span over the next row. */
private int pendingRowSpans;
-
+
+ //TODO rows should later be a Jakarta Commons LinkedList so concurrent modifications while
+ //using a ListIterator are possible
+ /** List of cached rows. This a list of EffRow elements. */
+ private List fetchedRows = new java.util.ArrayList();
+
+ /**
+ * Index of the row that will be returned at the next iteration step. Note that there
+ * is no direct relation between this field and {@link
+ * TableRowIterator#fetchIndex}. The fetching of rows and the iterating over them are
+ * two different processes. Hence the two indices. */
+ private int iteratorIndex = 0;
+
//prefetch state
- private ListIterator bodyIterator = null;
- private ListIterator childInBodyIterator = null;
-
+ /**
+ * Iterator over the requested table's part(s) (header, footer, body). Note that
+ * a table may have several table-body children, hence the iterator.
+ */
+ private ListIterator tablePartIterator = null;
+ /** Iterator over a part's child elements (either table-rows or table-cells). */
+ private ListIterator tablePartChildIterator = null;
+
/**
* Creates a new TableRowIterator.
* @param table the table to iterate over
* @param columns the column setup for the table
- * @param what indicates what part of the table to iterate over (HEADER, FOOTER, BODY)
+ * @param tablePart indicates what part of the table to iterate over (HEADER, FOOTER, BODY)
*/
- public TableRowIterator(Table table, ColumnSetup columns, int what) {
+ public TableRowIterator(Table table, ColumnSetup columns, int tablePart) {
this.table = table;
this.columns = columns;
- this.type = what;
- switch(what) {
+ this.tablePart = tablePart;
+ switch(tablePart) {
case HEADER: {
List bodyList = new java.util.ArrayList();
bodyList.add(table.getTableHeader());
- this.bodyIterator = bodyList.listIterator();
+ this.tablePartIterator = bodyList.listIterator();
break;
}
case FOOTER: {
List bodyList = new java.util.ArrayList();
bodyList.add(table.getTableFooter());
- this.bodyIterator = bodyList.listIterator();
+ this.tablePartIterator = bodyList.listIterator();
break;
}
default: {
- this.bodyIterator = table.getChildNodes();
+ this.tablePartIterator = table.getChildNodes();
}
}
}
-
+
/**
- * <p>Preloads the whole table.
- * </p>
- * <p>Note:This is inefficient for large tables.
- * </p>
+ * Preloads the whole table.
+ * <p>Note:This is inefficient for large tables.</p>
*/
public void prefetchAll() {
while (prefetchNext()) {
log.trace("found row...");
}
}
-
+
/**
- * Returns the next row group if any. A row group in this context is the minimum number of
+ * Returns the next row group if any. A row group in this context is the minimum number of
* consecutive rows which contains all spanned grid units of its cells.
* @return the next row group, or null
*/
}
return rowGroup;
}
-
+
/**
- * Retuns the next effective row.
- * @return the requested effective row.
+ * Returns the row at the given index, fetching rows up to the requested one if
+ * necessary.
+ *
+ * @return the requested row, or null if there is no row at the given index (index
+ * < 0 or end of table-part reached)
*/
- public EffRow getNextRow() {
- currentIndex++;
+ private EffRow getRow(int index) {
boolean moreRows = true;
- while (moreRows && rows.size() < currentIndex + 1) {
+ while (moreRows && fetchedRows.size() <= index) {
moreRows = prefetchNext();
}
- if (currentIndex < rows.size()) {
- return getCachedRow(currentIndex);
- } else {
- return null;
- }
+ // Whatever the value of index, getCachedRow will handle it nicely
+ return getCachedRow(index);
+ }
+
+ /**
+ * Returns the next effective row.
+ * @return the requested effective row or null if there is no more row.
+ */
+ private EffRow getNextRow() {
+ return getRow(iteratorIndex++);
+ }
+
+ /**
+ * Returns the row preceding the given row, without moving the iterator.
+ *
+ * @param row a row in the iterated table part
+ * @return the preceding row, or null if there is no such row (the given row is the
+ * first one in the table part)
+ */
+ public EffRow getPrecedingRow(EffRow row) {
+ return getRow(row.getIndex() - 1);
+ }
+
+ /**
+ * Returns the row following the given row, without moving the iterator.
+ *
+ * @param row a row in the iterated table part
+ * @return the following row, or null if there is no more row
+ */
+ public EffRow getFollowingRow(EffRow row) {
+ return getRow(row.getIndex() + 1);
}
-
+
/**
* Sets the iterator to the previous row.
*/
public void backToPreviousRow() {
- currentIndex--;
+ iteratorIndex--;
}
-
+
/**
* Returns the first effective row.
* @return the requested effective row.
*/
public EffRow getFirstRow() {
- if (rows.size() == 0) {
+ if (fetchedRows.size() == 0) {
prefetchNext();
}
return getCachedRow(0);
}
-
+
/**
- * <p>Returns the last effective row.
- * </p>
+ * Returns the last effective row.
* <p>Note:This is inefficient for large tables because the whole table
- * if preloaded.
- * </p>
+ * if preloaded.</p>
* @return the requested effective row.
*/
public EffRow getLastRow() {
while (prefetchNext()) {
//nop
}
- return getCachedRow(rows.size() - 1);
+ return getCachedRow(fetchedRows.size() - 1);
}
-
+
/**
- * Returns a cached effective row.
+ * Returns a cached effective row. If the given index points outside the range of rows
+ * (negative or greater than the number of already fetched rows), this methods
+ * terminates nicely by returning null.
+ *
* @param index index of the row (zero-based)
- * @return the requested effective row
+ * @return the requested effective row or null if (index < 0 || index >= the
+ * number of already fetched rows)
*/
public EffRow getCachedRow(int index) {
- if (index < 0 || index >= rows.size()) {
+ if (index < 0 || index >= fetchedRows.size()) {
return null;
} else {
- return (EffRow)rows.get(index);
+ return (EffRow)fetchedRows.get(index);
}
}
-
+
+ /**
+ * Fetches the next row.
+ *
+ * @return true if there was a row to fetch; otherwise, false (the end of the
+ * table-part has been reached)
+ */
private boolean prefetchNext() {
boolean firstInTable = false;
- boolean firstInBody = false;
- if (childInBodyIterator != null) {
- if (!childInBodyIterator.hasNext()) {
- //force skip on to next body
- if (pendingRowSpans > 0) {
- this.currentRow.clear();
- this.currentRowIndex++;
- EffRow gridUnits = buildGridRow(this.currentRow, null);
- log.debug(gridUnits);
- rows.add(gridUnits);
- return true;
- }
- childInBodyIterator = null;
- if (rows.size() > 0) {
- getCachedRow(rows.size() - 1).setFlagForAllGridUnits(
- GridUnit.LAST_IN_BODY, true);
- }
+ boolean firstInTablePart = false;
+ // If we are at the end of the current table part
+ if (tablePartChildIterator != null && !tablePartChildIterator.hasNext()) {
+ //force skip on to next component
+ if (pendingRowSpans > 0) {
+ this.currentRow.clear();
+ this.fetchIndex++;
+ EffRow gridUnits = buildGridRow(this.currentRow, null);
+ log.debug(gridUnits);
+ fetchedRows.add(gridUnits);
+ return true;
+ }
+ tablePartChildIterator = null;
+ if (fetchedRows.size() > 0) {
+ getCachedRow(fetchedRows.size() - 1).setFlagForAllGridUnits(
+ GridUnit.LAST_IN_PART, true);
}
}
- if (childInBodyIterator == null) {
- if (bodyIterator.hasNext()) {
- childInBodyIterator = ((TableBody)bodyIterator.next()).getChildNodes();
- if (rows.size() == 0) {
+ // If the iterating over the current table-part has not started yet
+ if (tablePartChildIterator == null) {
+ if (tablePartIterator.hasNext()) {
+ tablePartChildIterator = ((TableBody)tablePartIterator.next()).getChildNodes();
+ if (fetchedRows.size() == 0) {
firstInTable = true;
}
- firstInBody = true;
+ firstInTablePart = true;
} else {
- //no more rows
- if (rows.size() > 0) {
- getCachedRow(rows.size() - 1).setFlagForAllGridUnits(
- GridUnit.LAST_IN_BODY, true);
- if ((type == FOOTER || table.getTableFooter() == null)
- && type != HEADER) {
- getCachedRow(rows.size() - 1).setFlagForAllGridUnits(
+ //no more rows in that part of the table
+ if (fetchedRows.size() > 0) {
+ getCachedRow(fetchedRows.size() - 1).setFlagForAllGridUnits(
+ GridUnit.LAST_IN_PART, true);
+ // If the last row is the last of the table
+ if (tablePart == FOOTER
+ || (tablePart == BODY && table.getTableFooter() == null)) {
+ getCachedRow(fetchedRows.size() - 1).setFlagForAllGridUnits(
GridUnit.LAST_IN_TABLE, true);
}
}
return false;
}
}
- Object node = childInBodyIterator.next();
+ Object node = tablePartChildIterator.next();
while (node instanceof Marker) {
- node = childInBodyIterator.next();
+ node = tablePartChildIterator.next();
}
this.currentRow.clear();
- this.currentRowIndex++;
+ this.fetchIndex++;
TableRow rowFO = null;
if (node instanceof TableRow) {
rowFO = (TableRow)node;
} else if (node instanceof TableCell) {
this.currentRow.add(node);
if (!((TableCell)node).endsRow()) {
- while (childInBodyIterator.hasNext()) {
- TableCell cell = (TableCell)childInBodyIterator.next();
+ while (tablePartChildIterator.hasNext()) {
+ TableCell cell = (TableCell)tablePartChildIterator.next();
if (cell.startsRow()) {
//next row already starts here, one step back
- childInBodyIterator.previous();
+ tablePartChildIterator.previous();
break;
}
this.currentRow.add(cell);
throw new IllegalStateException("Illegal class found: " + node.getClass().getName());
}
EffRow gridUnits = buildGridRow(this.currentRow, rowFO);
- if (firstInBody) {
- gridUnits.setFlagForAllGridUnits(GridUnit.FIRST_IN_BODY, true);
+ if (firstInTablePart) {
+ gridUnits.setFlagForAllGridUnits(GridUnit.FIRST_IN_PART, true);
}
- if (firstInTable && (type == HEADER || table.getTableHeader() == null)
- && type != FOOTER) {
+ if (firstInTable && (tablePart == HEADER || table.getTableHeader() == null)
+ && tablePart != FOOTER) {
gridUnits.setFlagForAllGridUnits(GridUnit.FIRST_IN_TABLE, true);
}
log.debug(gridUnits);
- rows.add(gridUnits);
+ fetchedRows.add(gridUnits);
return true;
}
+ /**
+ * Places the given object at the given position in the list, first extending it if
+ * necessary with null objects to reach the position.
+ *
+ * @param list the list in which to place the object
+ * @param position index at which the object must be placed (0-based)
+ * @param obj the object to place
+ */
private void safelySetListItem(List list, int position, Object obj) {
while (position >= list.size()) {
list.add(null);
}
list.set(position, obj);
}
-
+
private Object safelyGetListItem(List list, int position) {
if (position >= list.size()) {
return null;
return list.get(position);
}
}
-
+
+ /**
+ * Builds the list of grid units corresponding to the given table row.
+ *
+ * @param cells list of cells belonging to the row
+ * @param rowFO the fo:table-row object containing the row, possibly null
+ * @return the list of grid units
+ */
private EffRow buildGridRow(List cells, TableRow rowFO) {
- EffRow row = new EffRow(this.currentRowIndex, type);
+ EffRow row = new EffRow(this.fetchIndex, tablePart);
List gridUnits = row.getGridUnits();
-
+
TableBody bodyFO = null;
-
- //Create all row-spanned grid units based on information from the last row
+
+ //Create all row-spanned grid units based on information from the previous row
int colnum = 1;
- GridUnit[] horzSpan = null;
+ GridUnit[] horzSpan = null; // Grid units horizontally spanned by a single cell
if (pendingRowSpans > 0) {
- ListIterator spanIter = lastRowsSpanningCells.listIterator();
+ ListIterator spanIter = previousRowsSpanningCells.listIterator();
while (spanIter.hasNext()) {
GridUnit gu = (GridUnit)spanIter.next();
if (gu != null) {
if (pendingRowSpans < 0) {
throw new IllegalStateException("pendingRowSpans must not become negative!");
}
-
+
//Transfer available cells to their slots
colnum = 1;
ListIterator iter = cells.listIterator();
while (iter.hasNext()) {
TableCell cell = (TableCell)iter.next();
-
+
colnum = cell.getColumnNumber();
//TODO: remove the check below???
//shouldn't happen here, since
- //overlapping cells already caught in
+ //overlapping cells already caught in
//fo.flow.TableCell.bind()...
- GridUnit other = (GridUnit)safelyGetListItem(gridUnits, colnum - 1);
+ GridUnit other = (GridUnit)safelyGetListItem(gridUnits, colnum - 1);
if (other != null) {
- String err = "A table-cell ("
- + cell.getContextInfo()
- + ") is overlapping with another ("
- + other.getCell().getContextInfo()
+ String err = "A table-cell ("
+ + cell.getContextInfo()
+ + ") is overlapping with another ("
+ + other.getCell().getContextInfo()
+ ") in column " + colnum;
- throw new IllegalStateException(err
+ throw new IllegalStateException(err
+ " (this should have been catched by FO tree validation)");
}
TableColumn col = columns.getColumn(colnum);
//Add grid unit for primary grid unit
- PrimaryGridUnit gu = new PrimaryGridUnit(cell, col, colnum - 1, this.currentRowIndex);
+ PrimaryGridUnit gu = new PrimaryGridUnit(cell, col, colnum - 1, this.fetchIndex);
safelySetListItem(gridUnits, colnum - 1, gu);
boolean hasRowSpanningLeft = !gu.isLastGridUnitRowSpan();
if (hasRowSpanningLeft) {
pendingRowSpans++;
- safelySetListItem(lastRowsSpanningCells, colnum - 1, gu);
+ safelySetListItem(previousRowsSpanningCells, colnum - 1, gu);
}
-
+
if (gu.hasSpanning()) {
//Add grid units on spanned slots if any
horzSpan = new GridUnit[cell.getNumberColumnsSpanned()];
colnum++;
GridUnit guSpan = new GridUnit(gu, columns.getColumn(colnum), colnum - 1, j);
//TODO: remove the check below???
- other = (GridUnit)safelyGetListItem(gridUnits, colnum - 1);
+ other = (GridUnit)safelyGetListItem(gridUnits, colnum - 1);
if (other != null) {
- String err = "A table-cell ("
- + cell.getContextInfo()
- + ") is overlapping with another ("
- + other.getCell().getContextInfo()
+ String err = "A table-cell ("
+ + cell.getContextInfo()
+ + ") is overlapping with another ("
+ + other.getCell().getContextInfo()
+ ") in column " + colnum;
- throw new IllegalStateException(err
+ throw new IllegalStateException(err
+ " (this should have been catched by FO tree validation)");
}
safelySetListItem(gridUnits, colnum - 1, guSpan);
if (hasRowSpanningLeft) {
pendingRowSpans++;
- safelySetListItem(lastRowsSpanningCells, colnum - 1, gu);
+ safelySetListItem(previousRowsSpanningCells, colnum - 1, gu);
}
horzSpan[j] = guSpan;
}
gu.addRow(horzSpan);
}
-
+
//Gather info for empty grid units (used later)
if (bodyFO == null) {
bodyFO = gu.getBody();
}
-
+
colnum++;
}
-
+
//Post-processing the list (looking for gaps and resolve start and end borders)
fillEmptyGridUnits(gridUnits, rowFO, bodyFO);
resolveStartEndBorders(gridUnits);
-
+
return row;
}
-
+
private void fillEmptyGridUnits(List gridUnits, TableRow row, TableBody body) {
for (int pos = 1; pos <= gridUnits.size(); pos++) {
GridUnit gu = (GridUnit)gridUnits.get(pos - 1);
-
+
//Empty grid units
if (gu == null) {
//Add grid unit
- gu = new EmptyGridUnit(row, columns.getColumn(pos), body,
+ gu = new EmptyGridUnit(row, columns.getColumn(pos), body,
pos - 1);
gridUnits.set(pos - 1, gu);
}
-
+
//Set flags
gu.setFlag(GridUnit.IN_FIRST_COLUMN, (pos == 1));
gu.setFlag(GridUnit.IN_LAST_COLUMN, (pos == gridUnits.size()));
}
}
-
+
private void resolveStartEndBorders(List gridUnits) {
for (int pos = 1; pos <= gridUnits.size(); pos++) {
GridUnit starting = (GridUnit)gridUnits.get(pos - 1);
-
+
//Border resolution
if (table.isSeparateBorderModel()) {
starting.assignBorderForSeparateBorderModel();
} else {
- //Neighbouring grid unit at start edge
+ //Neighbouring grid unit at start edge
GridUnit start = null;
int find = pos - 1;
while (find >= 1) {
}
find--;
}
-
+
//Ending grid unit for current cell
GridUnit ending = null;
if (starting.getCell() != null) {
pos += starting.getCell().getNumberColumnsSpanned() - 1;
}
ending = (GridUnit)gridUnits.get(pos - 1);
-
- //Neighbouring grid unit at end edge
+
+ //Neighbouring grid unit at end edge
GridUnit end = null;
find = pos + 1;
while (find <= gridUnits.size()) {
}
find++;
}
- starting.resolveBorder(start,
+ starting.resolveBorder(start,
CommonBorderPaddingBackground.START);
- ending.resolveBorder(end,
+ ending.resolveBorder(end,
CommonBorderPaddingBackground.END);
//Only start and end borders here, before and after during layout
}