001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: TableFObj.java 567294 2007-08-18 17:00:50Z vhennebert $ */
019:
020: package org.apache.fop.fo.flow;
021:
022: import java.util.List;
023:
024: import org.apache.fop.apps.FOPException;
025: import org.apache.fop.datatypes.Numeric;
026: import org.apache.fop.datatypes.ValidationPercentBaseContext;
027: import org.apache.fop.fo.Constants;
028: import org.apache.fop.fo.FONode;
029: import org.apache.fop.fo.FObj;
030: import org.apache.fop.fo.PropertyList;
031: import org.apache.fop.fo.expr.PropertyException;
032: import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
033: import org.apache.fop.fo.properties.NumberProperty;
034: import org.apache.fop.fo.properties.Property;
035: import org.apache.fop.fo.properties.PropertyMaker;
036:
037: /**
038: * Superclass for table-related FOs
039: */
040: public abstract class TableFObj extends FObj {
041:
042: private Numeric borderAfterPrecedence;
043: private Numeric borderBeforePrecedence;
044: private Numeric borderEndPrecedence;
045: private Numeric borderStartPrecedence;
046:
047: /**
048: * Used for determining initial values for column-numbers
049: * in case of row-spanning cells
050: * (for clarity)
051: *
052: */
053: protected static class PendingSpan {
054:
055: /**
056: * member variable holding the number of rows left
057: */
058: protected int rowsLeft;
059:
060: /**
061: * Constructor
062: *
063: * @param rows number of rows spanned
064: */
065: public PendingSpan(int rows) {
066: rowsLeft = rows;
067: }
068: }
069:
070: /**
071: * Main constructor
072: *
073: * @param parent the parent node
074: */
075: public TableFObj(FONode parent) {
076: super (parent);
077: }
078:
079: /**
080: * @see FObj#bind(PropertyList)
081: */
082: public void bind(PropertyList pList) throws FOPException {
083: super .bind(pList);
084: borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE)
085: .getNumeric();
086: borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE)
087: .getNumeric();
088: borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE)
089: .getNumeric();
090: borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE)
091: .getNumeric();
092: //Complain if table has separate border-model and fo is not a table or cell
093: //see: Rec 6.7.4, 6.7.6 - 6.7.9
094: if (getNameId() != FO_TABLE && getNameId() != FO_TABLE_CELL
095: && getTable().isSeparateBorderModel()
096: && getCommonBorderPaddingBackground().hasBorderInfo()) {
097: attributeWarning("In the separate border model (border-collapse=\"separate\")"
098: + ", borders are not applicable to "
099: + getName()
100: + ", but a non-zero value for border was found.");
101: }
102: if (getNameId() != FO_TABLE //Separate check for fo:table in Table.java
103: && getNameId() != FO_TABLE_CELL
104: && getCommonBorderPaddingBackground()
105: .hasPadding(
106: ValidationPercentBaseContext
107: .getPseudoContext())) {
108: attributeWarning("padding-* properties are not applicable to "
109: + getName()
110: + ", but a non-zero value for padding was found.");
111: }
112: }
113:
114: /**
115: * @see org.apache.fop.fo.FONode#addChildNode(FONode)
116: */
117: protected void addChildNode(FONode child) throws FOPException {
118: if (!inMarker() && child.getNameId() == FO_TABLE_CELL) {
119: /* update current column index for the table-body/table-row */
120: updateColumnIndex((TableCell) child);
121: }
122: super .addChildNode(child);
123: }
124:
125: private void updateColumnIndex(TableCell cell) {
126:
127: int rowSpan = cell.getNumberRowsSpanned();
128: int colSpan = cell.getNumberColumnsSpanned();
129: int columnIndex = getCurrentColumnIndex();
130: int i;
131:
132: if (getNameId() == FO_TABLE_ROW) {
133:
134: TableRow row = (TableRow) this ;
135:
136: for (i = colSpan; --i >= 0
137: || row.pendingSpans.size() < cell.getColumnNumber();) {
138: row.pendingSpans.add(null);
139: }
140:
141: /* if the current cell spans more than one row,
142: * update pending span list for the next row
143: */
144: if (rowSpan > 1) {
145: for (i = colSpan; --i >= 0;) {
146: row.pendingSpans.set(columnIndex - 1 + i,
147: new PendingSpan(rowSpan));
148: }
149: }
150: } else {
151:
152: TableBody body = (TableBody) this ;
153:
154: /* if body.firstRow is still true, and :
155: * a) the cell starts a row,
156: * b) there was a previous cell
157: * c) that previous cell didn't explicitly end the previous row
158: * => set firstRow flag to false
159: */
160: if (body.firstRow && cell.startsRow()) {
161: if (!body.previousCellEndedRow()) {
162: body.firstRow = false;
163: }
164: }
165:
166: /* pendingSpans not initialized for the first row...
167: */
168: if (body.firstRow) {
169: for (i = colSpan; --i >= 0
170: || body.pendingSpans.size() < cell
171: .getColumnNumber();) {
172: body.pendingSpans.add(null);
173: }
174: }
175:
176: /* if the current cell spans more than one row,
177: * update pending span list for the next row
178: */
179: if (rowSpan > 1) {
180: for (i = colSpan; --i >= 0;) {
181: body.pendingSpans.set(columnIndex - 1 + i,
182: new PendingSpan(rowSpan));
183: }
184: }
185: }
186:
187: /* flag column indices used by this cell,
188: * take into account that possibly not all column-numbers
189: * are used by columns in the parent table (if any),
190: * so a cell spanning three columns, might actually
191: * take up more than three columnIndices...
192: */
193: int startIndex = columnIndex - 1;
194: int endIndex = startIndex + colSpan;
195: if (getTable().columns != null) {
196: List cols = getTable().columns;
197: int tmpIndex = endIndex;
198: for (i = startIndex; i <= tmpIndex; ++i) {
199: if (i < cols.size() && cols.get(i) == null) {
200: endIndex++;
201: }
202: }
203: }
204: flagColumnIndices(startIndex, endIndex);
205: if (getNameId() != FO_TABLE_ROW && cell.endsRow()) {
206: ((TableBody) this ).firstRow = false;
207: ((TableBody) this ).resetColumnIndex();
208: }
209: }
210:
211: /**
212: *
213: * @param side the side for which to return the border precedence
214: * @return the "border-precedence" value for the given side
215: */
216: public Numeric getBorderPrecedence(int side) {
217: switch (side) {
218: case CommonBorderPaddingBackground.BEFORE:
219: return borderBeforePrecedence;
220: case CommonBorderPaddingBackground.AFTER:
221: return borderAfterPrecedence;
222: case CommonBorderPaddingBackground.START:
223: return borderStartPrecedence;
224: case CommonBorderPaddingBackground.END:
225: return borderEndPrecedence;
226: default:
227: return null;
228: }
229: }
230:
231: /**
232: * Returns the current column index of the given TableFObj
233: * (overridden for Table, TableBody, TableRow)
234: *
235: * @return the next column number to use
236: */
237: public int getCurrentColumnIndex() {
238: return 0;
239: }
240:
241: /**
242: * Sets the current column index of the given TableFObj
243: * used when a value for column-number is explicitly
244: * specified on the child FO (TableCell or TableColumn)
245: * (overridden for Table, TableBody, TableRow)
246: *
247: * @param newIndex new value for column index
248: */
249: public void setCurrentColumnIndex(int newIndex) {
250: //do nothing by default
251: }
252:
253: /**
254: * Checks if a certain column-number is already occupied
255: * (overridden for Table, TableBody, TableRow)
256: *
257: * @param colNr the column-number to check
258: * @return true if column-number is already in use
259: */
260: public boolean isColumnNumberUsed(int colNr) {
261: return false;
262: }
263:
264: /**
265: * Convenience method to returns a reference
266: * to the base Table instance
267: *
268: * @return the base table instance
269: *
270: */
271: public Table getTable() {
272: if (this .getNameId() == FO_TABLE) {
273: //node is a Table
274: //=> return itself
275: return (Table) this ;
276: } else {
277: //any other Table-node
278: //=> recursive call to parent.getTable()
279: return ((TableFObj) parent).getTable();
280: }
281: }
282:
283: /**
284: * @return the Common Border, Padding, and Background Properties.
285: */
286: public abstract CommonBorderPaddingBackground getCommonBorderPaddingBackground();
287:
288: /**
289: * Flags column indices from <code>start</code> to <code>end</code>,
290: * and updates the current column index.
291: * Overridden for Table, TableBody, TableRow
292: * @param start start index
293: * @param end end index
294: */
295: protected void flagColumnIndices(int start, int end) {
296: //nop
297: }
298: }
|