KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > fo > flow > TableFObj


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 /* $Id: TableFObj.java 488960 2006-12-20 08:34:28Z spepping $ */
19
20 package org.apache.fop.fo.flow;
21
22 import java.util.BitSet JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25
26 import org.apache.fop.apps.FOPException;
27 import org.apache.fop.datatypes.Numeric;
28 import org.apache.fop.datatypes.ValidationPercentBaseContext;
29 import org.apache.fop.fo.Constants;
30 import org.apache.fop.fo.FONode;
31 import org.apache.fop.fo.FObj;
32 import org.apache.fop.fo.PropertyList;
33 import org.apache.fop.fo.ValidationException;
34 import org.apache.fop.fo.expr.PropertyException;
35 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
36 import org.apache.fop.fo.properties.NumberProperty;
37 import org.apache.fop.fo.properties.Property;
38 import org.apache.fop.fo.properties.PropertyMaker;
39
40 /**
41  * Superclass for table-related FOs
42  */

43 public abstract class TableFObj extends FObj {
44
45     private Numeric borderAfterPrecedence;
46     private Numeric borderBeforePrecedence;
47     private Numeric borderEndPrecedence;
48     private Numeric borderStartPrecedence;
49     
50     /**
51      * Used for determining initial values for column-numbers
52      * in case of row-spanning cells
53      * (for clarity)
54      *
55      */

56     protected static class PendingSpan {
57         
58         /**
59          * member variable holding the number of rows left
60          */

61         protected int rowsLeft;
62         
63         /**
64          * Constructor
65          *
66          * @param rows number of rows spanned
67          */

68         public PendingSpan(int rows) {
69             rowsLeft = rows;
70         }
71     }
72     
73     /**
74      * Main constructor
75      *
76      * @param parent the parent node
77      */

78     public TableFObj(FONode parent) {
79         super(parent);
80     }
81
82     /**
83      * @see FObj#bind(PropertyList)
84      */

85     public void bind(PropertyList pList) throws FOPException {
86         borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE).getNumeric();
87         borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric();
88         borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric();
89         borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric();
90         //Complain if table has separate border-model and fo is not a table or cell
91
//see: Rec 6.7.4, 6.7.6 - 6.7.9
92
if (getNameId() != FO_TABLE && getNameId() != FO_TABLE_CELL
93                 && getTable().isSeparateBorderModel()
94                 && getCommonBorderPaddingBackground().hasBorderInfo()) {
95             attributeWarning("In the separate border model (border-collapse=\"separate\")"
96                     + ", borders are not applicable to " + getName()
97                     + ", but a non-zero value for border was found.");
98         }
99         if (getNameId() != FO_TABLE //Separate check for fo:table in Table.java
100
&& getNameId() != FO_TABLE_CELL
101                 && getCommonBorderPaddingBackground().hasPadding(
102                         ValidationPercentBaseContext
103                             .getPseudoContextForValidationPurposes())) {
104             attributeWarning(
105                     "padding-* properties are not applicable to " + getName()
106                     + ", but a non-zero value for padding was found.");
107         }
108     }
109     
110     /**
111      * @see org.apache.fop.fo.FONode#addChildNode(FONode)
112      */

113     protected void addChildNode(FONode child) throws FOPException {
114         if (!inMarker()
115                 && child.getNameId() == FO_TABLE_CELL) {
116             /* update current column index for the table-body/table-row */
117             updateColumnIndex((TableCell) child);
118         }
119         super.addChildNode(child);
120     }
121     
122     private void updateColumnIndex(TableCell cell)
123             throws ValidationException {
124         
125         int rowSpan = cell.getNumberRowsSpanned();
126         int colSpan = cell.getNumberColumnsSpanned();
127         int columnIndex = getCurrentColumnIndex();
128         
129         int i = -1;
130         while (++i < colSpan) {
131             if (isColumnNumberUsed(columnIndex + i)) {
132                 /* if column-number is already in use by another cell
133                  * in the current row => error!
134                  */

135                 StringBuffer JavaDoc errorMessage = new StringBuffer JavaDoc();
136                 errorMessage.append("fo:table-cell overlaps in column ")
137                        .append(columnIndex + i);
138                 if (locator.getLineNumber() != -1) {
139                     errorMessage.append(" (line #")
140                         .append(locator.getLineNumber()).append(", column #")
141                         .append(locator.getColumnNumber()).append(")");
142                 }
143                 throw new ValidationException(errorMessage.toString());
144             }
145         }
146
147         if (getNameId() == FO_TABLE_ROW) {
148             
149             TableRow row = (TableRow) this;
150             
151             for (i = colSpan; --i >= 0;) {
152                 row.pendingSpans.add(null);
153             }
154             
155             /* if the current cell spans more than one row,
156              * update pending span list for the next row
157              */

158             if (rowSpan > 1) {
159                 for (i = colSpan; --i >= 0;) {
160                     row.pendingSpans.set(columnIndex - 1 + i,
161                             new PendingSpan(rowSpan));
162                 }
163             }
164         } else {
165             
166             TableBody body = (TableBody) this;
167             
168             /* if body.firstRow is still true, and :
169              * a) the cell starts a row,
170              * b) there was a previous cell
171              * c) that previous cell didn't explicitly end the previous row
172              * => set firstRow flag to false
173              */

174             if (body.firstRow && cell.startsRow()) {
175                 if (!body.previousCellEndedRow()) {
176                     body.firstRow = false;
177                 }
178             }
179             
180             /* pendingSpans not initialized for the first row...
181              */

182             if (body.firstRow) {
183                 for (i = colSpan; --i >= 0;) {
184                     body.pendingSpans.add(null);
185                 }
186             }
187             
188             /* if the current cell spans more than one row,
189              * update pending span list for the next row
190              */

191             if (rowSpan > 1) {
192                 for (i = colSpan; --i >= 0;) {
193                     body.pendingSpans.set(columnIndex - 1 + i,
194                             new PendingSpan(rowSpan));
195                 }
196             }
197         }
198
199         /* flag column indices used by this cell,
200          * take into account that possibly not all column-numbers
201          * are used by columns in the parent table (if any),
202          * so a cell spanning three columns, might actually
203          * take up more than three columnIndices...
204          */

205         int startIndex = columnIndex - 1;
206         int endIndex = startIndex + colSpan;
207         if (getTable().columns != null) {
208             List JavaDoc cols = getTable().columns;
209             int tmpIndex = endIndex;
210             for (i = startIndex; i <= tmpIndex; ++i) {
211                 if (i < cols.size() && cols.get(i) == null) {
212                     endIndex++;
213                 }
214             }
215         }
216         flagColumnIndices(startIndex, endIndex);
217         if (getNameId() != FO_TABLE_ROW && cell.endsRow()) {
218             ((TableBody) this).firstRow = false;
219             ((TableBody) this).resetColumnIndex();
220         }
221     }
222     
223     /**
224      *
225      * @param side the side for which to return the border precedence
226      * @return the "border-precedence" value for the given side
227      */

228     public Numeric getBorderPrecedence(int side) {
229         switch (side) {
230         case CommonBorderPaddingBackground.BEFORE:
231             return borderBeforePrecedence;
232         case CommonBorderPaddingBackground.AFTER:
233             return borderAfterPrecedence;
234         case CommonBorderPaddingBackground.START:
235             return borderStartPrecedence;
236         case CommonBorderPaddingBackground.END:
237             return borderEndPrecedence;
238         default:
239             return null;
240         }
241     }
242
243     /**
244      * Returns the current column index of the given TableFObj
245      * (overridden for Table, TableBody, TableRow)
246      *
247      * @return the next column number to use
248      */

249     protected int getCurrentColumnIndex() {
250         return 0;
251     }
252     
253     /**
254      * Sets the current column index of the given TableFObj
255      * used when a value for column-number is explicitly
256      * specified on the child FO (TableCell or TableColumn)
257      * (overridden for Table, TableBody, TableRow)
258      *
259      * @param newIndex new value for column index
260      */

261     protected void setCurrentColumnIndex(int newIndex) {
262         //do nothing by default
263
}
264         
265     /**
266      * Checks if a certain column-number is already occupied
267      * (overridden for Table, TableBody, TableRow)
268      *
269      * @param colNr the column-number to check
270      * @return true if column-number is already in use
271      */

272     public boolean isColumnNumberUsed(int colNr) {
273         return false;
274     }
275     
276     /**
277      * Convenience method to returns a reference
278      * to the base Table instance
279      *
280      * @return the base table instance
281      *
282      */

283     public Table getTable() {
284         if (this.getNameId() == FO_TABLE) {
285             //node is a Table
286
//=> return itself
287
return (Table) this;
288         } else {
289             //any other Table-node
290
//=> recursive call to parent.getTable()
291
return ((TableFObj) parent).getTable();
292         }
293     }
294     
295     /**
296      * @return the Common Border, Padding, and Background Properties.
297      */

298     public abstract CommonBorderPaddingBackground getCommonBorderPaddingBackground();
299     
300     /**
301      * Flags column indices from <code>start</code> to <code>end</code>,
302      * and updates the current column index.
303      * Overridden for Table, TableBody, TableRow
304      * @param start start index
305      * @param end end index
306      */

307     protected void flagColumnIndices(int start, int end) {
308         //nop
309
}
310     
311     /**
312      * PropertyMaker subclass for the column-number property
313      *
314      */

315     public static class ColumnNumberPropertyMaker extends NumberProperty.Maker {
316
317         /**
318          * Constructor
319          * @param propId the id of the property for which the maker should
320          * be created
321          */

322         public ColumnNumberPropertyMaker(int propId) {
323             super(propId);
324         }
325
326         /**
327          * @see PropertyMaker#make(PropertyList)
328          */

329         public Property make(PropertyList propertyList)
330                 throws PropertyException {
331             FObj fo = propertyList.getFObj();
332
333             if (fo.getNameId() == Constants.FO_TABLE_CELL
334                     || fo.getNameId() == Constants.FO_TABLE_COLUMN) {
335                 if (fo.getNameId() == Constants.FO_TABLE_CELL
336                         && fo.getParent().getNameId() != Constants.FO_TABLE_ROW
337                         && (propertyList.get(Constants.PR_STARTS_ROW).getEnum()
338                                 == Constants.EN_TRUE)) {
339                     TableBody parent = (TableBody) fo.getParent();
340                     if (!parent.previousCellEndedRow()) {
341                         parent.resetColumnIndex();
342                     }
343                 }
344                 return new NumberProperty(((TableFObj) fo.getParent())
345                                             .getCurrentColumnIndex());
346             } else {
347                 throw new PropertyException(
348                         "column-number property is only allowed"
349                         + " on fo:table-cell or fo:table-column, not on "
350                         + fo.getName());
351             }
352         }
353         
354         /**
355          * Check the value of the column-number property.
356          * Return the parent's column index (initial value) in case
357          * of a negative or zero value
358          *
359          * @see org.apache.fop.fo.properties.PropertyMaker#get(
360          * int, PropertyList, boolean, boolean)
361          */

362         public Property get(int subpropId, PropertyList propertyList,
363                             boolean tryInherit, boolean tryDefault)
364                 throws PropertyException {
365             
366             Property p = super.get(0, propertyList, tryInherit, tryDefault);
367             TableFObj fo = (TableFObj) propertyList.getFObj();
368             TableFObj parent = (TableFObj) propertyList.getParentFObj();
369             
370             if (p != null) {
371                 int columnIndex = p.getNumeric().getValue();
372                 
373                 if (columnIndex <= 0) {
374                     fo.getLogger().warn("Specified negative or zero value for "
375                             + "column-number on " + fo.getName() + ": "
376                             + columnIndex + " forced to "
377                             + parent.getCurrentColumnIndex());
378                     return new NumberProperty(parent.getCurrentColumnIndex());
379                 }
380                 
381                 double tmpIndex = p.getNumeric().getNumericValue();
382                 if (tmpIndex - columnIndex > 0.0) {
383                     columnIndex = (int) Math.round(tmpIndex);
384                     fo.getLogger().warn("Rounding specified column-number of "
385                             + tmpIndex + " to " + columnIndex);
386                     return new NumberProperty(columnIndex);
387                 }
388                         
389                 /* if column-number was explicitly specified, force the
390                  * parent's current column index to the specified value,
391                  * so that the updated index will be the correct initial
392                  * value for the next cell/column (see Rec 7.26.8)
393                  */

394                 if (propertyList.getExplicit(Constants.PR_COLUMN_NUMBER) != null) {
395                     parent.setCurrentColumnIndex(p.getNumeric().getValue());
396                 }
397             }
398             return p;
399         }
400     }
401 }
402
Popular Tags