public int getNameId() {
return FO_TABLE_BODY;
}
+
+ /**
+ * @param obj table row in question
+ * @return true if the given table row is the first row of this body.
+ */
+ public boolean isFirst(TableRow obj) {
+ return (childNodes.size() > 0)
+ && (childNodes.get(0) == obj);
+ }
+
+ /**
+ * @param obj table row in question
+ * @return true if the given table row is the first row of this body.
+ */
+ public boolean isLast(TableRow obj) {
+ return (childNodes.size() > 0)
+ && (childNodes.get(childNodes.size() - 1) == obj);
+ }
}
/** the "end" edge */
public static final int END = 3;
- private static class BorderInfo implements Cloneable {
+ public static class BorderInfo implements Cloneable {
private int mStyle; // Enum for border style
private ColorType mColor; // Border color
private CondLengthProperty mWidth;
mWidth = width;
mColor = color;
}
+
+ public int getStyle() {
+ return this.mStyle;
+ }
+
+ public ColorType getColor() {
+ return this.mColor;
+ }
+
+ public CondLengthProperty getWidth() {
+ return this.mWidth;
+ }
+
+ public int getRetainedWidth() {
+ if ((mStyle == Constants.EN_NONE)
+ || (mStyle == Constants.EN_HIDDEN)) {
+ return 0;
+ } else {
+ return mWidth.getLengthValue();
+ }
+ }
+
+ /** @see java.lang.Object#toString() */
+ public String toString() {
+ StringBuffer sb = new StringBuffer("BorderInfo");
+ sb.append(" {");
+ sb.append(mStyle);
+ sb.append(", ");
+ sb.append(mColor);
+ sb.append(", ");
+ sb.append(mWidth);
+ sb.append("}");
+ return sb.toString();
+ }
}
private BorderInfo[] borderInfo = new BorderInfo[4];
private CondLengthProperty[] padding = new CondLengthProperty[4];
+ /**
+ * Construct a CommonBorderPaddingBackground object.
+ */
+ public CommonBorderPaddingBackground() {
+
+ }
+
/**
* Construct a CommonBorderPaddingBackground object.
* @param pList The PropertyList to get properties from.
// If style = none, force width to 0, don't get Color (spec 7.7.20)
int style = pList.get(styleProp).getEnum();
if (style != Constants.EN_NONE) {
- borderInfo[side] = new BorderInfo(style,
+ setBorderInfo(new BorderInfo(style,
pList.get(widthProp).getCondLength(),
- pList.get(colorProp).getColorType());
+ pList.get(colorProp).getColorType()), side);
}
}
+ /**
+ * Sets a border.
+ * @param info the border information
+ * @param side the side to apply the info to
+ */
+ public void setBorderInfo(BorderInfo info, int side) {
+ this.borderInfo[side] = info;
+ }
+
+ /**
+ * @param side the side to retrieve
+ * @return the border info for a side
+ */
+ public BorderInfo getBorderInfo(int side) {
+ return this.borderInfo[side];
+ }
+
/**
* @return the background image as a preloaded FopImage, null if there is
* no background image.
public static class TableLayoutManagerMaker extends Maker {
- private List getColumnLayoutManagerList(Table table) {
+ private List getColumnLayoutManagerList(Table table, TableLayoutManager tlm) {
List columnLMs = null;
List columns = table.getColumns();
if (columns != null) {
while (colnum > columnLMs.size()) {
columnLMs.add(null);
}
- columnLMs.set(colnum - 1, new Column(col));
+ Column colLM = new Column(col);
+ colLM.setParent(tlm);
+ columnLMs.set(colnum - 1, colLM);
colnum++;
}
}
public void make(FONode node, List lms) {
Table table = (Table) node;
TableLayoutManager tlm = new TableLayoutManager(table);
- List columnLMs = getColumnLayoutManagerList(table);
+ List columnLMs = getColumnLayoutManagerList(table, tlm);
if (columnLMs != null) {
tlm.setColumns(columnLMs);
}
fobj = node;
}
+ /** @return the table-body|header|footer FO */
+ public TableBody getFObj() {
+ return this.fobj;
+ }
+
/**
* Set the columns from the table.
*
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.flow.Table;
import org.apache.fop.fo.flow.TableCell;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.LengthRangeProperty;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.LayoutManager;
private int cellIPD;
private int rowHeight;
private int usedBPD;
+ private int startBorderWidth;
+ private int endBorderWidth;
private int borderAndPaddingBPD;
private boolean emptyCell = true;
+ /** List of Lists containing GridUnit instances, one List per row. */
+ private List rows = new java.util.ArrayList();
+
/**
* Create a new Cell layout manager.
* @node table-cell FO for which to create the LM
return (Table)node;
}
+
+ /**
+ * Called by Row LM to register the grid units occupied by this cell for a row.
+ * @param spannedGridUnits a List of GridUnits
+ */
+ public void addGridUnitsFromRow(List spannedGridUnits) {
+ log.debug("Getting another row, " + spannedGridUnits.size() + " grid units");
+ this.rows.add(spannedGridUnits);
+
+ }
+
private int getIPIndents() {
int iIndents = 0;
- iIndents += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
- iIndents += fobj.getCommonBorderPaddingBackground().getBorderEndWidth(false);
+ startBorderWidth = 0;
+ endBorderWidth = 0;
+ for (int i = 0; i < rows.size(); i++) {
+ List gridUnits = (List)rows.get(i);
+ startBorderWidth = Math.max(startBorderWidth,
+ ((GridUnit)gridUnits.get(0)).
+ effBorders.getBorderStartWidth(false));
+ endBorderWidth = Math.max(endBorderWidth,
+ ((GridUnit)gridUnits.get(gridUnits.size() - 1)).
+ effBorders.getBorderEndWidth(false));
+ }
+ //iIndents += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
+ iIndents += startBorderWidth;
+ //iIndents += fobj.getCommonBorderPaddingBackground().getBorderEndWidth(false);
+ iIndents += endBorderWidth;
if (!fobj.isSeparateBorderModel()) {
iIndents /= 2;
}
TraitSetter.addBackground(curBlockArea, fobj.getCommonBorderPaddingBackground());
//TODO Set these booleans right
boolean[] outer = new boolean[] {false, false, false, false};
- TraitSetter.addCollapsingBorders(curBlockArea,
- fobj.getCommonBorderPaddingBackground(), outer);
+ if (rows.size() == 1 && ((List)rows.get(0)).size() == 1) {
+ //Can set the borders directly if there's no span
+ CommonBorderPaddingBackground effBorders =
+ ((GridUnit)((List)rows.get(0)).get(0)).effBorders;
+ TraitSetter.addCollapsingBorders(curBlockArea,
+ effBorders, outer);
+ } else {
+ log.warn("TODO Add collapsed border painting for spanned cells");
+ }
}
//Handle display-align
curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
curBlockArea.setPositioning(Block.ABSOLUTE);
int indent = 0;
- indent += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
+ indent += startBorderWidth;
if (!fobj.isSeparateBorderModel()) {
indent /= 2;
}
childBreaks.clear();
}
}
+
}
--- /dev/null
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.layoutmgr.table;
+
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
+
+/**
+ * This class is a superclass for the two collapsing border models defined
+ * in the XSL 1.0 specification.
+ */
+public abstract class CollapsingBorderModel {
+
+ /** Indicates that the cell is/starts in the first row being painted on a particular page */
+ public static final int FIRST_ROW_IN_TABLE_PART = 1;
+ /** Indicates that the cell is/ends in the last row being painted on a particular page */
+ public static final int LAST_ROW_IN_TABLE_PART = 2;
+ /** Indicates that the cell is/starts in the first row of a body/table-header/table-footer */
+ public static final int FIRST_ROW_IN_GROUP = 4;
+ /** Indicates that the cell is/end in the last row of a body/table-header/table-footer */
+ public static final int LAST_ROW_IN_GROUP = 8;
+
+ private static CollapsingBorderModel collapse = null;
+ private static CollapsingBorderModel collapseWithPrecedence = null;
+
+ /**
+ * @param cellLM the cell
+ * @return the border model for the cell
+ */
+ public static CollapsingBorderModel getBorderModelFor(int borderCollapse) {
+ switch (borderCollapse) {
+ case Constants.EN_COLLAPSE:
+ if (collapse == null) {
+ collapse = new CollapsingBorderModelEyeCatching();
+ }
+ return collapse;
+ case Constants.EN_COLLAPSE_WITH_PRECEDENCE:
+ if (collapseWithPrecedence == null) {
+ //collapseWithPrecedence = new CollapsingBorderModelWithPrecedence();
+ }
+ return collapseWithPrecedence;
+ default:
+ throw new IllegalArgumentException("Illegal border-collapse mode.");
+ }
+ }
+
+ /**
+ * @param side the side on the current cell
+ * @return the adjacent side on the neighbouring cell
+ */
+ public static int getOtherSide(int side) {
+ switch (side) {
+ case CommonBorderPaddingBackground.BEFORE:
+ return CommonBorderPaddingBackground.AFTER;
+ case CommonBorderPaddingBackground.AFTER:
+ return CommonBorderPaddingBackground.BEFORE;
+ case CommonBorderPaddingBackground.START:
+ return CommonBorderPaddingBackground.END;
+ case CommonBorderPaddingBackground.END:
+ return CommonBorderPaddingBackground.START;
+ default:
+ throw new IllegalArgumentException("Illegal parameter: side");
+ }
+ }
+
+ /**
+ * @param side the side to investigate
+ * @return true if the adjacent cell is before or after
+ */
+ protected boolean isVerticalRelation(int side) {
+ return (side == CommonBorderPaddingBackground.BEFORE
+ || side == CommonBorderPaddingBackground.AFTER);
+ }
+
+
+ /**
+ * See rule 4 in 6.7.10 for the collapsing border model.
+ * @param style the border style to get the preference value for
+ * @return the preference value of the style
+ */
+ public int getPreferenceValue(int style) {
+ switch (style) {
+ case Constants.EN_DOUBLE: return 0;
+ case Constants.EN_SOLID: return -1;
+ case Constants.EN_DASHED: return -2;
+ case Constants.EN_DOTTED: return -3;
+ case Constants.EN_RIDGE: return -4;
+ case Constants.EN_OUTSET: return -5;
+ case Constants.EN_GROOVE: return -6;
+ case Constants.EN_INSET: return -6;
+ default: throw new IllegalStateException("Illegal border style: " + style);
+ }
+ }
+
+ /**
+ * Determines the winning BorderInfo.
+ * @param current cell info of the current element
+ * @param neighbour cell info of the neighbouring element
+ * @return the winning BorderInfo
+ */
+ public abstract BorderInfo determineWinner(
+ GridUnit current, GridUnit neighbour, int side, int flags);
+
+}
--- /dev/null
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.layoutmgr.table;
+
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
+
+/**
+ * Implements the normal "collapse" border model defined in 6.7.10 in XSL 1.0.
+ *
+ * TODO Column groups are not yet checked in this algorithm!
+ */
+public class CollapsingBorderModelEyeCatching extends CollapsingBorderModel {
+
+ private static final int BEFORE = CommonBorderPaddingBackground.BEFORE;
+ private static final int AFTER = CommonBorderPaddingBackground.AFTER;
+ private static final int START = CommonBorderPaddingBackground.START;
+ private static final int END = CommonBorderPaddingBackground.END;
+
+ public BorderInfo determineWinner(GridUnit currentGridUnit,
+ GridUnit otherGridUnit, int side, int flags) {
+ final boolean vertical = isVerticalRelation(side);
+ final int otherSide = getOtherSide(side);
+
+ //Get cells
+ Cell currentCell = currentGridUnit.layoutManager;
+ Cell otherCell = null;
+ if (otherGridUnit != null) {
+ otherCell = otherGridUnit.layoutManager;
+ }
+
+ //Get rows
+ Row currentRow = currentGridUnit.row;
+ Row otherRow = null;
+ if (vertical && otherCell != null) {
+ otherRow = otherGridUnit.row;
+ }
+
+ //get bodies
+ Body currentBody = (Body)currentRow.getParent();
+ Body otherBody = null;
+ if (otherRow != null) {
+ otherBody = (Body)otherRow.getParent();
+ }
+
+ //get columns
+ Column currentColumn = (Column)currentGridUnit.column;
+ Column otherColumn = null;
+ if (otherGridUnit != null) {
+ otherColumn = (Column)otherGridUnit.column;
+ }
+
+ //TODO get column groups
+
+ //Get table
+ TableLayoutManager table = (TableLayoutManager)currentBody.getParent();
+
+ //----------------------------------------------------------------------
+ //We're creating two arrays containing the applicable BorderInfos for
+ //each cell in question.
+ //0 = cell, 1 = row, 2 = row group (body), 3 = column,
+ //4 = col group (spanned column, see 6.7.3), 5 = table
+
+ BorderInfo[] current = new BorderInfo[6];
+ BorderInfo[] other = new BorderInfo[6];
+ //cell
+ current[0] = currentGridUnit.getOriginalBorderInfoForCell(side);
+ if (otherGridUnit != null) {
+ other[0] = otherGridUnit.getOriginalBorderInfoForCell(otherSide);
+ }
+ if (side == BEFORE
+ || side == AFTER
+ || (currentColumn.isFirst() && side == START)
+ || (currentColumn.isLast() && side == END)) {
+ //row
+ current[1] = currentRow.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
+ }
+ if (otherRow != null) {
+ //row
+ other[1] = otherRow.getFObj().getCommonBorderPaddingBackground().getBorderInfo(otherSide);
+ }
+ if ((side == BEFORE && currentRow.isFirstInBody())
+ || (side == AFTER && currentRow.isLastInBody())
+ || (currentColumn.isFirst() && side == START)
+ || (currentColumn.isLast() && side == END)) {
+ //row group (=body, table-header or table-footer)
+ current[2] = currentBody.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
+ }
+ if ((otherSide == BEFORE && otherRow.isFirstInBody())
+ || (otherSide == AFTER && otherRow.isLastInBody())) {
+ //row group (=body, table-header or table-footer)
+ other[2] = otherBody.getFObj().getCommonBorderPaddingBackground().getBorderInfo(otherSide);
+ }
+ if ((side == BEFORE && otherGridUnit == null)
+ || (side == AFTER && otherGridUnit == null)
+ || (side == START)
+ || (side == END)) {
+ //column
+ current[3] = currentColumn.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
+ }
+ if (otherColumn != null) {
+ //column
+ other[3] = otherColumn.getFObj().getCommonBorderPaddingBackground().getBorderInfo(otherSide);
+ }
+ //TODO current[4] and other[4] for column groups
+ if (otherGridUnit == null) {
+ //table
+ current[5] = table.getTable().getCommonBorderPaddingBackground().getBorderInfo(side);
+ }
+ //other[6] is always null, since it's always the same table
+
+ BorderInfo resolved = null;
+
+ // *** Rule 1 ***
+ resolved = doRule1(current, other);
+ if (resolved != null) {
+ return resolved;
+ }
+
+ // *** Rule 2 ***
+ if (!doRule2(current, other)) {
+ return null; //paint no border
+ }
+
+ // *** Rule 3 ***
+ resolved = doRule3(current, other);
+ if (resolved != null) {
+ return resolved;
+ }
+
+ // *** Rule 4 ***
+ resolved = doRule4(current, other);
+ if (resolved != null) {
+ return resolved;
+ }
+
+ // *** Rule 5 ***
+ resolved = doRule5(current, other);
+ if (resolved != null) {
+ return resolved;
+ }
+
+ return null; //no winner, no border
+ }
+
+ private BorderInfo doRule1(BorderInfo[] current, BorderInfo[] other) {
+ for (int i = 0; i < current.length - 1; i++) {
+ if ((current[i] != null) && (current[i].getStyle() == Constants.EN_HIDDEN)) {
+ return current[i];
+ }
+ if ((other[i] != null) && (other[i].getStyle() == Constants.EN_HIDDEN)) {
+ return other[i];
+ }
+ }
+ return null;
+ }
+
+ private boolean doRule2(BorderInfo[] current, BorderInfo[] other) {
+ boolean found = false;
+ for (int i = 0; i < current.length - 1; i++) {
+ if ((current[i] != null) && (current[i].getStyle() != Constants.EN_NONE)) {
+ found = true;
+ break;
+ }
+ if ((other[i] != null) && (other[i].getStyle() != Constants.EN_NONE)) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+ }
+
+ private BorderInfo doRule3(BorderInfo[] current, BorderInfo[] other) {
+ int width = 0;
+ //Find max border width
+ for (int i = 0; i < current.length - 1; i++) {
+ if ((current[i] != null) && (current[i].getRetainedWidth() > width)) {
+ width = current[i].getRetainedWidth();
+ }
+ if ((other[i] != null) && (other[i].getRetainedWidth() > width)) {
+ width = other[i].getRetainedWidth();
+ }
+ }
+ BorderInfo widest = null;
+ int count = 0;
+ //See if there's only one with the widest border
+ for (int i = 0; i < current.length - 1; i++) {
+ if ((current[i] != null) && (current[i].getRetainedWidth() == width)) {
+ count++;
+ if (widest == null) {
+ widest = current[i];
+ }
+ break;
+ } else {
+ current[i] = null; //Discard the narrower ones
+ }
+ if ((other[i] != null) && (other[i].getRetainedWidth() == width)) {
+ count++;
+ if (widest == null) {
+ widest = other[i];
+ }
+ break;
+ } else {
+ other[i] = null; //Discard the narrower ones
+ }
+ }
+ if (count == 1) {
+ return widest;
+ } else {
+ return null;
+ }
+ }
+
+ private BorderInfo doRule4(BorderInfo[] current, BorderInfo[] other) {
+ int pref = getPreferenceValue(Constants.EN_INSET); //Lowest preference
+ //Find highest preference value
+ for (int i = 0; i < current.length - 1; i++) {
+ if (current[i] != null) {
+ int currPref = getPreferenceValue(current[i].getStyle());
+ if (currPref > pref) {
+ pref = currPref;
+ break;
+ }
+ }
+ if (other[i] != null) {
+ int currPref = getPreferenceValue(other[i].getStyle());
+ if (currPref > pref) {
+ pref = currPref;
+ break;
+ }
+ }
+ }
+ BorderInfo preferred = null;
+ int count = 0;
+ //See if there's only one with the preferred border style
+ for (int i = 0; i < current.length - 1; i++) {
+ if (current[i] != null) {
+ int currPref = getPreferenceValue(current[i].getStyle());
+ if (currPref == pref) {
+ count++;
+ if (preferred == null) {
+ preferred = current[i];
+ }
+ break;
+ }
+ } else {
+ current[i] = null; //Discard the ones that are not preferred
+ }
+ if (other[i] != null) {
+ int currPref = getPreferenceValue(other[i].getStyle());
+ if (currPref == pref) {
+ count++;
+ if (preferred == null) {
+ preferred = other[i];
+ }
+ break;
+ }
+ } else {
+ other[i] = null; //Discard the ones that are not preferred
+ }
+ }
+ if (count == 1) {
+ return preferred;
+ } else {
+ return null;
+ }
+ }
+
+ private BorderInfo doRule5(BorderInfo[] current, BorderInfo[] other) {
+ for (int i = 0; i < current.length - 1; i++) {
+ if (current[i] != null) {
+ return current[i];
+ }
+ if (other[i] != null) {
+ return other[i];
+ }
+ }
+ return null;
+ }
+
+}
/*
- * Copyright 1999-2004 The Apache Software Foundation.
+ * Copyright 1999-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableColumn;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
* column properties.
*/
public class Column extends AbstractLayoutManager {
+
private TableColumn fobj;
+ private Length columnWidth;
/**
* Create a new column layout manager.
+ * @param node the table-column FO
*/
public Column(TableColumn node) {
super(node);
fobj = node;
+ columnWidth = fobj.getColumnWidth();
}
+ /** @return the table-column FO */
+ public TableColumn getFObj() {
+ return this.fobj;
+ }
+
+ /** @return true if the column is the first column */
+ public boolean isFirst() {
+ return ((TableLayoutManager)getParent()).isFirst(this);
+ }
+
+ /** @return true if the column is the last column */
+ public boolean isLast() {
+ return ((TableLayoutManager)getParent()).isLast(this);
+ }
+
/**
* Get the next break possibility.
* Columns do not create or return any areas.
return null;
}
+ /**
+ * Overrides the default column-with coming from the FO.
+ * @param width the new width to use
+ */
+ public void setWidth(Length width) {
+ this.columnWidth = width;
+ }
+
/**
* Get the width of this column.
*
* @return the width of the column
*/
public Length getWidth() {
- return fobj.getColumnWidth();
+ return columnWidth;
}
/**
--- /dev/null
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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.layoutmgr.table;
+
+import org.apache.fop.fo.flow.Table;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
+
+
+public class GridUnit {
+
+ /** layout manager for the cell occupying this grid unit, may be null */
+ public Cell layoutManager;
+ /** layout manager for the column that this grid unit belongs to */
+ public Column column;
+ /** layout manager for the row that this grid unit belongs to */
+ public Row row;
+ /** index of grid unit within cell in column direction */
+ public int colSpanIndex;
+ /** index of grid unit within cell in row direction */
+ public int rowSpanIndex;
+ /** effective borders for a cell slot (used for collapsing border model) */
+ public CommonBorderPaddingBackground effBorders;
+
+ public GridUnit(Cell layoutManager, int colSpanIndex) {
+ this.layoutManager = layoutManager;
+ this.colSpanIndex = colSpanIndex;
+ this.rowSpanIndex = 0;
+ }
+
+ public GridUnit(Cell layoutManager) {
+ this(layoutManager, 0);
+ }
+
+ /** @return true if the grid unit is the primary of a cell */
+ public boolean isPrimaryGridUnit() {
+ return (colSpanIndex == 0) && (rowSpanIndex == 0);
+ }
+
+ /** @return true if the grid unit is the last in column spanning direction */
+ public boolean isLastGridUnitColSpan() {
+ if (layoutManager != null) {
+ return (colSpanIndex == layoutManager.getFObj().getNumberColumnsSpanned() - 1);
+ } else {
+ return true;
+ }
+ }
+
+ /** @return true if the grid unit is the last in column spanning direction */
+ public boolean isLastGridUnitRowSpan() {
+ if (layoutManager != null) {
+ return (rowSpanIndex == layoutManager.getFObj().getNumberRowsSpanned() - 1);
+ } else {
+ return true;
+ }
+ }
+
+ /** @return true if the cell is part of a span in column direction */
+ public boolean isColSpan() {
+ return (colSpanIndex > 0);
+ }
+
+ public BorderInfo getOriginalBorderInfoForCell(int side) {
+ if (layoutManager != null) {
+ return layoutManager.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Assign the borders from the given cell to this cell info. Used in
+ * case of separate border model.
+ * @param current cell to take the borders from
+ */
+ public void assignBorder(Cell current) {
+ if (current != null) {
+ this.effBorders = current.getFObj().getCommonBorderPaddingBackground();
+ }
+ }
+
+ /**
+ * Assign the borders directly.
+ * @param borders the borders to use
+ */
+ public void assignBorder(CommonBorderPaddingBackground borders) {
+ if (borders != null) {
+ this.effBorders = borders;
+ }
+ }
+
+ /**
+ * Resolve collapsing borders for the given cell and store the resulting
+ * borders in this cell info. Use in case of the collapsing border model.
+ * @param current cell to resolve borders for
+ * @param before cell before the current cell, if any
+ * @param after cell after the current cell, if any
+ * @param start cell preceeding the current cell, if any
+ * @param end cell succeeding of the current cell, if any
+ */
+ public static void resolveBorder(Table table,
+ CommonBorderPaddingBackground target,
+ GridUnit current, GridUnit other, int side) {
+ if (current == null) {
+ return;
+ }
+
+ CollapsingBorderModel borderModel = CollapsingBorderModel.getBorderModelFor(
+ table.getBorderCollapse());
+ target.setBorderInfo(
+ borderModel.determineWinner(current, other,
+ side, 0), side);
+ }
+
+}
\ No newline at end of file
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.flow.Table;
+import org.apache.fop.fo.flow.TableBody;
import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableRow;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.LengthRangeProperty;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.LayoutManager;
*/
public class Row extends BlockStackingLayoutManager {
- /** Used by CellInfo: Indicates start of cell. */
- public static final int CI_START_OF_CELL = 0;
- /** Used by CellInfo: Indicates part of a spanned cell in column direction. */
- public static final int CI_COL_SPAN = 1;
- /** Used by CellInfo: Indicates part of a spanned cell in row direction. */
- public static final int CI_ROW_SPAN = 2;
-
private TableRow fobj;
- private List cellList = null;
+ private List gridUnits = null;
private List columns = null;
private int referenceIPD;
private int rowHeight;
fobj = node;
}
+ /** @return the table-row FO */
+ public TableRow getFObj() {
+ return this.fobj;
+ }
+
/**
* @return the table owning this row
*/
columns = cols;
}
- private void setupCells() {
- cellList = new java.util.ArrayList();
+ /** @return true if this is the layout manager for the first row in a body. */
+ public boolean isFirstInBody() {
+ return ((TableBody)getFObj().getParent()).isFirst(getFObj());
+ }
+
+ /** @return true if this is the layout manager for the last row in a body. */
+ public boolean isLastInBody() {
+ return ((TableBody)getFObj().getParent()).isLast(getFObj());
+ }
+
+ /**
+ * Gets the Column at a given index.
+ * @param index index of the column (index must be >= 1)
+ * @return the requested Column
+ */
+ private Column getColumn(int index) {
+ int size = columns.size();
+ if (index > size - 1) {
+ return (Column)columns.get(size - 1);
+ } else {
+ return (Column)columns.get(index - 1);
+ }
+ }
+
+ private void prepareGridUnits() {
+ gridUnits = new java.util.ArrayList();
List availableCells = new java.util.ArrayList();
// add cells to list
while (childLMiter.hasNext()) {
if (cell.hasColumnNumber()) {
colnum = cell.getColumnNumber();
}
- while (colnum > cellList.size()) {
- cellList.add(null);
+ while (colnum > gridUnits.size()) {
+ gridUnits.add(null);
}
- if (cellList.get(colnum - 1) != null) {
+ if (gridUnits.get(colnum - 1) != null) {
log.error("Overlapping cell at position " + colnum);
}
//Add cell info for primary slot
- cellList.set(colnum - 1, new CellInfo(cellLM));
+ GridUnit info = new GridUnit(cellLM);
+ info.row = this;
+ gridUnits.set(colnum - 1, info);
+ info.column = getColumn(colnum);
//Add cell infos on spanned slots if any
for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) {
colnum++;
- if (colnum > cellList.size()) {
- cellList.add(new CellInfo(CI_COL_SPAN));
+ GridUnit infoSpan = new GridUnit(cellLM, j);
+ infoSpan.row = this;
+ infoSpan.column = getColumn(colnum);
+ if (colnum > gridUnits.size()) {
+ gridUnits.add(infoSpan);
} else {
- if (cellList.get(colnum - 1) != null) {
+ if (gridUnits.get(colnum - 1) != null) {
log.error("Overlapping cell at position " + colnum);
+ //TODO throw layout exception
}
- cellList.set(colnum - 1, new CellInfo(CI_COL_SPAN));
+ gridUnits.set(colnum - 1, infoSpan);
}
}
colnum++;
}
- //Post-processing the list (looking for gaps)
- int pos = 1;
- ListIterator ppIter = cellList.listIterator();
- while (ppIter.hasNext()) {
- CellInfo cellInfo = (CellInfo)ppIter.next();
- if (cellInfo == null) {
- //Add cell info on empty cell
- ppIter.set(new CellInfo(CI_START_OF_CELL));
+ //Post-processing the list (looking for gaps and resolve start and end borders)
+ postProcessGridUnits();
+ }
+
+ private void postProcessGridUnits() {
+ 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 GridUnit(null);
+ gu.row = this;
+ gu.column = getColumn(pos);
+ gridUnits.set(pos - 1, gu);
+ }
+ }
+
+ //Border resolution now that the empty grid units are filled
+ for (int pos = 1; pos <= gridUnits.size(); pos++) {
+ GridUnit gu = (GridUnit)gridUnits.get(pos - 1);
+
+ //Border resolution
+ if (getTable().isSeparateBorderModel()) {
+ gu.assignBorder(gu.layoutManager);
+ } else {
+ GridUnit start = null;
+ int find = pos - 1;
+ while (find >= 1) {
+ GridUnit candidate = (GridUnit)gridUnits.get(find - 1);
+ if (candidate.isLastGridUnitColSpan()) {
+ start = candidate;
+ break;
+ }
+ find--;
+ }
+ GridUnit end = null;
+ find = pos + 1;
+ while (find <= gridUnits.size()) {
+ GridUnit candidate = (GridUnit)gridUnits.get(find - 1);
+ if (candidate.isPrimaryGridUnit()) {
+ end = candidate;
+ break;
+ }
+ }
+ CommonBorderPaddingBackground borders = new CommonBorderPaddingBackground();
+ GridUnit.resolveBorder(getTable(), borders, gu,
+ (start != null ? start : null),
+ CommonBorderPaddingBackground.START);
+ GridUnit.resolveBorder(getTable(), borders, gu,
+ (end != null ? end : null),
+ CommonBorderPaddingBackground.END);
+ gu.effBorders = borders;
+ //Only start and end borders here, before and after during layout
+ //TODO resolve before and after borders during layout
}
- pos++;
}
}
-
+
/**
* Get the cell info for a cell.
*
* @param pos the position of the cell (must be >= 1)
* @return the cell info object
*/
- protected CellInfo getCellInfo(int pos) {
- if (cellList == null) {
- setupCells();
+ protected GridUnit getCellInfo(int pos) {
+ if (gridUnits == null) {
+ prepareGridUnits();
}
- if (pos <= cellList.size()) {
- return (CellInfo)cellList.get(pos - 1);
+ if (pos <= gridUnits.size()) {
+ return (GridUnit)gridUnits.get(pos - 1);
} else {
return null;
}
*/
public BreakPoss getNextBreakPoss(LayoutContext context) {
//LayoutManager curLM; // currently active LM
- CellInfo curCellInfo; //currently active cell info
+ GridUnit curGridUnit; //currently active grid unit
BreakPoss lastPos = null;
List breakList = new java.util.ArrayList();
- List spannedColumns = new java.util.ArrayList();
int min = 0;
int opt = 0;
int startColumn = 1;
boolean over = false;
- while ((curCellInfo = getCellInfo(startColumn)) != null) {
- Cell cellLM = curCellInfo.layoutManager;
- if (curCellInfo.isColSpan()) {
+ while ((curGridUnit = getCellInfo(startColumn)) != null) {
+ Cell cellLM = curGridUnit.layoutManager;
+ if (curGridUnit.isColSpan()) {
//skip spanned slots
startColumn++;
continue;
stackSize));
//Determine which columns this cell will occupy
- getColumnsForCell(cellLM, startColumn, spannedColumns);
+ List spannedGridUnits = new java.util.ArrayList();
+ getGridUnitsForCell(cellLM, startColumn, spannedGridUnits);
int childRefIPD = 0;
- for (int i = 0; i < spannedColumns.size(); i++) {
- Column col = (Column)spannedColumns.get(i);
+ for (int i = 0; i < spannedGridUnits.size(); i++) {
+ Column col = ((GridUnit)spannedGridUnits.get(i)).column;
childRefIPD += col.getWidth().getValue();
}
childLC.setRefIPD(childRefIPD);
if (cellLM != null) {
+ cellLM.addGridUnitsFromRow(spannedGridUnits);
cellLM.setInRowIPDOffset(ipdOffset);
while (!cellLM.isFinished()) {
if ((bp = cellLM.getNextBreakPoss(childLC)) != null) {
boolean fin = true;
startColumn = 1;
//Check if any of the cell LMs haven't finished, yet
- while ((curCellInfo = getCellInfo(startColumn)) != null) {
- Cell cellLM = curCellInfo.layoutManager;
+ while ((curGridUnit = getCellInfo(startColumn)) != null) {
+ Cell cellLM = curGridUnit.layoutManager;
if (cellLM == null) {
//skip empty cell
startColumn++;
return breakPoss;
}
- /**
- * Gets the Column at a given index.
- * @param index index of the column (index must be >= 1)
- * @return the requested Column
- */
- private Column getColumn(int index) {
- int size = columns.size();
- if (index > size - 1) {
- return (Column)columns.get(size - 1);
- } else {
- return (Column)columns.get(index - 1);
- }
- }
-
/**
* Determines the columns that are spanned by the given cell.
* @param cellLM table-cell LM
* @param startCell starting cell index (must be >= 1)
* @param spannedColumns List to receive the applicable columns
*/
- private void getColumnsForCell(Cell cellLM, int startCell, List spannedColumns) {
+ private void getGridUnitsForCell(Cell cellLM, int startCell, List spannedColumns) {
int count;
if (cellLM != null) {
count = cellLM.getFObj().getNumberColumnsSpanned();
}
spannedColumns.clear();
for (int i = 0; i < count; i++) {
- spannedColumns.add(getColumn(startCell + i));
+ spannedColumns.add(this.gridUnits.get(startCell + i - 1));
}
}
*/
protected void reset(Position pos) {
//LayoutManager curLM; // currently active LM
- CellInfo curCellInfo;
+ GridUnit curGridUnit;
int cellIndex = 1;
if (pos == null) {
- while ((curCellInfo = getCellInfo(cellIndex)) != null) {
- if (curCellInfo.layoutManager != null) {
- curCellInfo.layoutManager.resetPosition(null);
+ while ((curGridUnit = getCellInfo(cellIndex)) != null) {
+ if (curGridUnit.layoutManager != null) {
+ curGridUnit.layoutManager.resetPosition(null);
}
cellIndex++;
}
RowPosition rpos = (RowPosition)pos;
List breaks = rpos.cellBreaks;
- while ((curCellInfo = getCellInfo(cellIndex)) != null) {
- if (curCellInfo.layoutManager != null) {
+ while ((curGridUnit = getCellInfo(cellIndex)) != null) {
+ if (curGridUnit.layoutManager != null) {
List childbreaks = (List)breaks.get(cellIndex);
- curCellInfo.layoutManager.resetPosition(
+ curGridUnit.layoutManager.resetPosition(
(Position)childbreaks.get(childbreaks.size() - 1));
}
cellIndex++;
}
}
- private class CellInfo {
-
- /** layout manager for this cell, may be null */
- public Cell layoutManager;
- /** flags for this cell, on of Row.CI_* */
- public int flags = CI_START_OF_CELL;
-
- public CellInfo(Cell layoutManager) {
- this.layoutManager = layoutManager;
- }
-
- public CellInfo(int flags) {
- this.flags = flags;
- }
-
- /** @return true if the cell is part of a span in column direction */
- public boolean isColSpan() {
- return (flags & CI_COL_SPAN) != 0;
- }
-
- }
-
}
//new property evaluation context so proportional-column-width() works
//correctly.
if (columns.size() == 0) {
- this.columns.add(new Column(getTable().getDefaultColumn()));
+ Column col = new Column(getTable().getDefaultColumn());
+ col.setParent(this);
+ this.columns.add(col);
}
}
+ /**
+ * @param column the column to check
+ * @return true if the column is the first column
+ */
+ public boolean isFirst(Column column) {
+ return (this.columns.size() == 0 || this.columns.get(0) == column);
+ }
+
+ /**
+ * @param column the column to check
+ * @return true if the column is the last column
+ */
+ public boolean isLast(Column column) {
+ return (this.columns.size() == 0 || this.columns.get(columns.size() - 1) == column);
+ }
+
/**
* Get the break possibility and height of the table header or footer.
*
reset(null);
}
}
-
+
}