aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop/fo/flow/table/Table.java
diff options
context:
space:
mode:
authorVincent Hennebert <vhennebert@apache.org>2007-11-05 17:42:37 +0000
committerVincent Hennebert <vhennebert@apache.org>2007-11-05 17:42:37 +0000
commit740a2f598cf99291aa781eee9e1d59957ae3099e (patch)
treebf4c38bb397cb1de0b9806f325a2a4a96590b070 /src/java/org/apache/fop/fo/flow/table/Table.java
parenta09f99a58e99a5179d74e5b00f7d246a03790e81 (diff)
downloadxmlgraphics-fop-740a2f598cf99291aa781eee9e1d59957ae3099e.tar.gz
xmlgraphics-fop-740a2f598cf99291aa781eee9e1d59957ae3099e.zip
Moved table-related FObj into new o.a.fop.fo.flow.table package
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@592103 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop/fo/flow/table/Table.java')
-rw-r--r--src/java/org/apache/fop/fo/flow/table/Table.java555
1 files changed, 555 insertions, 0 deletions
diff --git a/src/java/org/apache/fop/fo/flow/table/Table.java b/src/java/org/apache/fop/fo/flow/table/Table.java
new file mode 100644
index 000000000..07fc95f7e
--- /dev/null
+++ b/src/java/org/apache/fop/fo/flow/table/Table.java
@@ -0,0 +1,555 @@
+/*
+ * 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 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.PropertyList;
+import org.apache.fop.fo.StaticPropertyList;
+import org.apache.fop.fo.ValidationException;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonMarginBlock;
+import org.apache.fop.fo.properties.KeepProperty;
+import org.apache.fop.fo.properties.LengthPairProperty;
+import org.apache.fop.fo.properties.LengthRangeProperty;
+import org.apache.fop.fo.properties.TableColLength;
+import org.xml.sax.Locator;
+
+/**
+ * Class modelling the fo:table object.
+ */
+public class Table extends TableFObj implements ColumnNumberManagerHolder {
+
+ /** properties */
+ private CommonBorderPaddingBackground commonBorderPaddingBackground;
+ private CommonMarginBlock commonMarginBlock;
+ private LengthRangeProperty blockProgressionDimension;
+ private int borderCollapse;
+ private LengthPairProperty borderSeparation;
+ private int breakAfter;
+ private int breakBefore;
+ private LengthRangeProperty inlineProgressionDimension;
+ private KeepProperty keepTogether;
+ private KeepProperty keepWithNext;
+ private KeepProperty keepWithPrevious;
+ private int tableLayout;
+ private int tableOmitFooterAtBreak;
+ private int tableOmitHeaderAtBreak;
+ // Unused but valid items, commented out for performance:
+ // private CommonAccessibility commonAccessibility;
+ // private CommonAural commonAural;
+ // private CommonRelativePosition commonRelativePosition;
+ // private int intrusionDisplace;
+ // private int writingMode;
+
+ /** extension properties */
+ private Length widowContentLimit;
+ private Length orphanContentLimit;
+
+ /** collection of columns in this table */
+ private List columns = new ArrayList();
+
+ private ColumnNumberManager columnNumberManager = new ColumnNumberManager();
+
+ /** the table-header and -footer */
+ private TableBody tableHeader = null;
+ private TableBody tableFooter = null;
+
+ /** used for validation */
+ private boolean tableColumnFound = false;
+ private boolean tableHeaderFound = false;
+ private boolean tableFooterFound = false;
+ private boolean tableBodyFound = false;
+
+ private boolean hasExplicitColumns = false;
+ private boolean columnsFinalized = false;
+ private RowGroupBuilder rowGroupBuilder;
+
+ /**
+ * The table's property list. Used in case the table has
+ * no explicit columns, as a parent property list to
+ * internally generated TableColumns
+ */
+ private PropertyList propList;
+
+ /**
+ * @param parent FONode that is the parent of this object
+ */
+ public Table(FONode parent) {
+ super(parent);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void bind(PropertyList pList) throws FOPException {
+ super.bind(pList);
+ commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps();
+ commonMarginBlock = pList.getMarginBlockProps();
+ blockProgressionDimension = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange();
+ borderCollapse = pList.get(PR_BORDER_COLLAPSE).getEnum();
+ borderSeparation = pList.get(PR_BORDER_SEPARATION).getLengthPair();
+ breakAfter = pList.get(PR_BREAK_AFTER).getEnum();
+ breakBefore = pList.get(PR_BREAK_BEFORE).getEnum();
+ inlineProgressionDimension = pList.get(PR_INLINE_PROGRESSION_DIMENSION).getLengthRange();
+ keepTogether = pList.get(PR_KEEP_TOGETHER).getKeep();
+ keepWithNext = pList.get(PR_KEEP_WITH_NEXT).getKeep();
+ keepWithPrevious = pList.get(PR_KEEP_WITH_PREVIOUS).getKeep();
+ tableLayout = pList.get(PR_TABLE_LAYOUT).getEnum();
+ tableOmitFooterAtBreak = pList.get(PR_TABLE_OMIT_FOOTER_AT_BREAK).getEnum();
+ tableOmitHeaderAtBreak = pList.get(PR_TABLE_OMIT_HEADER_AT_BREAK).getEnum();
+
+ //Bind extension properties
+ widowContentLimit = pList.get(PR_X_WIDOW_CONTENT_LIMIT).getLength();
+ orphanContentLimit = pList.get(PR_X_ORPHAN_CONTENT_LIMIT).getLength();
+
+ if (!blockProgressionDimension.getOptimum(null).isAuto()) {
+ attributeWarning("only a value of \"auto\" for block-progression-dimension has a well-specified"
+ + " behavior on fo:table. Falling back to \"auto\"");
+ // Anyway, the bpd of a table is not used by the layout code
+ }
+ if (tableLayout == EN_AUTO) {
+ attributeWarning("table-layout=\"auto\" is currently not supported by FOP");
+ }
+ if (!isSeparateBorderModel()
+ && getCommonBorderPaddingBackground().hasPadding(
+ ValidationPercentBaseContext.getPseudoContext())) {
+ //See "17.6.2 The collapsing border model" in CSS2
+ attributeWarning("In collapsing border model a table does not have padding"
+ + " (see http://www.w3.org/TR/REC-CSS2/tables.html#collapsing-borders)"
+ + ", but a non-zero value for padding was found. The padding will be ignored.");
+ }
+
+ /* Store reference to the property list, so
+ * new lists can be created in case the table has no
+ * explicit columns
+ * (see addDefaultColumn())
+ */
+ this.propList = pList;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void startOfNode() throws FOPException {
+ super.startOfNode();
+ getFOEventHandler().startTable(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ * XSL Content Model: (marker*,table-column*,table-header?,table-footer?,table-body+)
+ */
+ protected void validateChildNode(Locator loc, String nsURI, String localName)
+ throws ValidationException {
+ if (FO_URI.equals(nsURI)) {
+ if ("marker".equals(localName)) {
+ if (tableColumnFound || tableHeaderFound || tableFooterFound
+ || tableBodyFound) {
+ nodesOutOfOrderError(loc, "fo:marker",
+ "(table-column*,table-header?,table-footer?,table-body+)");
+ }
+ } else if ("table-column".equals(localName)) {
+ tableColumnFound = true;
+ if (tableHeaderFound || tableFooterFound || tableBodyFound) {
+ nodesOutOfOrderError(loc, "fo:table-column",
+ "(table-header?,table-footer?,table-body+)");
+ }
+ } else if ("table-header".equals(localName)) {
+ if (tableHeaderFound) {
+ tooManyNodesError(loc, "table-header");
+ } else {
+ tableHeaderFound = true;
+ if (tableFooterFound || tableBodyFound) {
+ nodesOutOfOrderError(loc, "fo:table-header",
+ "(table-footer?,table-body+)");
+ }
+ }
+ } else if ("table-footer".equals(localName)) {
+ if (tableFooterFound) {
+ tooManyNodesError(loc, "table-footer");
+ } else {
+ tableFooterFound = true;
+ if (tableBodyFound && getUserAgent().validateStrictly()) {
+ nodesOutOfOrderError(loc, "fo:table-footer",
+ "(table-body+)");
+ }
+ }
+ } else if ("table-body".equals(localName)) {
+ tableBodyFound = true;
+ } else {
+ invalidChildError(loc, nsURI, localName);
+ }
+ } else {
+ invalidChildError(loc, nsURI, localName);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void endOfNode() throws FOPException {
+
+ if (!tableBodyFound) {
+ missingChildElementError(
+ "(marker*,table-column*,table-header?,table-footer?"
+ + ",table-body+)");
+ }
+ if (!inMarker()) {
+ /* clean up */
+ for (int i = columns.size(); --i >= 0;) {
+ TableColumn col = (TableColumn) columns.get(i);
+ if (col != null) {
+ col.releasePropertyList();
+ }
+ }
+ this.propList = null;
+ rowGroupBuilder = null;
+ }
+ getFOEventHandler().endTable(this);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected void addChildNode(FONode child) throws FOPException {
+
+ int childId = child.getNameId();
+
+ switch (childId) {
+ case FO_TABLE_COLUMN:
+ hasExplicitColumns = true;
+ if (!inMarker()) {
+ addColumnNode((TableColumn) child);
+ } else {
+ columns.add((TableColumn) child);
+ }
+ break;
+ case FO_TABLE_HEADER:
+ case FO_TABLE_FOOTER:
+ case FO_TABLE_BODY:
+ if (!columnsFinalized) {
+ columnsFinalized = true;
+ if (hasExplicitColumns) {
+ finalizeColumns();
+ rowGroupBuilder = new FixedColRowGroupBuilder(this);
+ } else {
+ rowGroupBuilder = new VariableColRowGroupBuilder(this);
+ }
+
+ }
+ switch (childId) {
+ case FO_TABLE_FOOTER:
+ tableFooter = (TableBody) child;
+ break;
+ case FO_TABLE_HEADER:
+ tableHeader = (TableBody) child;
+ break;
+ default:
+ super.addChildNode(child);
+ }
+ break;
+ default:
+ super.addChildNode(child);
+ }
+ }
+
+ private void finalizeColumns() throws FOPException {
+ for (int i = 0; i < columns.size(); i++) {
+ if (columns.get(i) == null) {
+ columns.set(i, createImplicitColumn(i + 1));
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ public Table getTable() {
+ return this;
+ }
+
+ /**
+ * Creates the appropriate number of additional implicit columns to match the given
+ * column number. Used when the table has no explicit column: the number of columns is
+ * then determined by the row that has the most columns.
+ *
+ * @param columnNumber the table must at least have this number of column
+ * @throws FOPException if there was an error creating the property list for implicit
+ * 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)
+ throws FOPException {
+ TableColumn implicitColumn = new TableColumn(this, true);
+ PropertyList pList = new StaticPropertyList(
+ implicitColumn, this.propList);
+ pList.setWritingMode();
+ implicitColumn.bind(pList);
+ implicitColumn.setColumnWidth(new TableColLength(1.0, implicitColumn));
+ implicitColumn.setColumnNumber(colNumber);
+ return implicitColumn;
+ }
+
+ /**
+ * Adds a column to the columns List, and updates the columnIndex
+ * used for determining initial values for column-number
+ *
+ * @param col the column to add
+ * @throws FOPException
+ */
+ private void addColumnNode(TableColumn col) {
+
+ int colNumber = col.getColumnNumber();
+ int colRepeat = col.getNumberColumnsRepeated();
+
+ /* add nulls for non-occupied indices between
+ * the last column up to and including the current one
+ */
+ while (columns.size() < colNumber + colRepeat - 1) {
+ columns.add(null);
+ }
+
+ // in case column is repeated:
+ // for the time being, add the same column
+ // (colRepeat - 1) times to the columns list
+ // TODO: need to force the column-number (?)
+ for (int i = colNumber - 1; i < colNumber + colRepeat - 1; i++) {
+ columns.set(i, col);
+ }
+
+ columnNumberManager.signalUsedColumnNumbers(colNumber, colNumber + colRepeat - 1);
+ }
+
+ boolean hasExplicitColumns() {
+ return hasExplicitColumns;
+ }
+
+ /** @return true of table-layout="auto" */
+ public boolean isAutoLayout() {
+ return (tableLayout == EN_AUTO);
+ }
+
+ /**
+ * Returns the list of table-column elements.
+ *
+ * @return a list of {@link TableColumn} elements, may contain null elements
+ */
+ public List getColumns() {
+ return columns;
+ }
+
+ /**
+ * Returns the column at the given index.
+ *
+ * @param index index of the column to be retrieved, 0-based
+ * @return the corresponding column (may be an implicitly created column)
+ */
+ TableColumn getColumn(int index) {
+ return (TableColumn) columns.get(index);
+ }
+
+ /**
+ * Returns the number of columns of this table.
+ *
+ * @return the number of columns, implicit or explicit, in this table
+ */
+ int getNumberOfColumns() {
+ return columns.size();
+ }
+
+ /** @return the body for the table-header. */
+ public TableBody getTableHeader() {
+ return tableHeader;
+ }
+
+ /** @return the body for the table-footer. */
+ public TableBody getTableFooter() {
+ return tableFooter;
+ }
+
+ /** @return true if the table-header should be omitted at breaks */
+ public boolean omitHeaderAtBreak() {
+ return (this.tableOmitHeaderAtBreak == EN_TRUE);
+ }
+
+ /** @return true if the table-footer should be omitted at breaks */
+ public boolean omitFooterAtBreak() {
+ return (this.tableOmitFooterAtBreak == EN_TRUE);
+ }
+
+ /**
+ * @return the "inline-progression-dimension" property.
+ */
+ public LengthRangeProperty getInlineProgressionDimension() {
+ return inlineProgressionDimension;
+ }
+
+ /**
+ * @return the "block-progression-dimension" property.
+ */
+ public LengthRangeProperty getBlockProgressionDimension() {
+ return blockProgressionDimension;
+ }
+
+ /**
+ * @return the Common Margin Properties-Block.
+ */
+ public CommonMarginBlock getCommonMarginBlock() {
+ return commonMarginBlock;
+ }
+
+ /**
+ * @return the Common Border, Padding, and Background Properties.
+ */
+ public CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
+ return commonBorderPaddingBackground;
+ }
+
+ /** @return the "break-after" property. */
+ public int getBreakAfter() {
+ return breakAfter;
+ }
+
+ /** @return the "break-before" property. */
+ public int getBreakBefore() {
+ return breakBefore;
+ }
+
+ /** @return the "keep-with-next" property. */
+ public KeepProperty getKeepWithNext() {
+ return keepWithNext;
+ }
+
+ /** @return the "keep-with-previous" property. */
+ public KeepProperty getKeepWithPrevious() {
+ return keepWithPrevious;
+ }
+
+ /** @return the "keep-together" property. */
+ public KeepProperty getKeepTogether() {
+ return keepTogether;
+ }
+
+ /**
+ * Convenience method to check if a keep-together constraint is specified.
+ * @return true if keep-together is active.
+ */
+ public boolean mustKeepTogether() {
+ return !getKeepTogether().getWithinPage().isAuto()
+ || !getKeepTogether().getWithinColumn().isAuto();
+ }
+
+ /** @return the "border-collapse" property. */
+ public int getBorderCollapse() {
+ return borderCollapse;
+ }
+
+ /** @return true if the separate border model is active */
+ public boolean isSeparateBorderModel() {
+ return (getBorderCollapse() == EN_SEPARATE);
+ }
+
+ /** @return the "border-separation" property. */
+ public LengthPairProperty getBorderSeparation() {
+ return borderSeparation;
+ }
+
+ /** @return the "fox:widow-content-limit" extension property */
+ public Length getWidowContentLimit() {
+ return widowContentLimit;
+ }
+
+ /** @return the "fox:orphan-content-limit" extension property */
+ public Length getOrphanContentLimit() {
+ return orphanContentLimit;
+ }
+
+ /** {@inheritDoc} */
+ public String getLocalName() {
+ return "table";
+ }
+
+ /** {@inheritDoc} */
+ public int getNameId() {
+ return FO_TABLE;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public FONode clone(FONode parent, boolean removeChildren)
+ throws FOPException {
+ Table clone = (Table) super.clone(parent, removeChildren);
+ clone.columnsFinalized = false;
+ if (removeChildren) {
+ clone.columns = new ArrayList();
+ clone.tableHeader = null;
+ clone.tableFooter = null;
+ }
+ return clone;
+ }
+
+ /** {@inheritDoc} */
+ public ColumnNumberManager getColumnNumberManager() {
+ return columnNumberManager;
+ }
+
+ RowGroupBuilder getRowGroupBuilder() {
+ return rowGroupBuilder;
+ }
+}