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: ColumnSetup.java 521640 2007-03-23 09:19:04Z jeremias $ */
019:
020: package org.apache.fop.layoutmgr.table;
021:
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.ListIterator;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.apache.fop.datatypes.PercentBaseContext;
029: import org.apache.fop.datatypes.Length;
030:
031: import org.apache.fop.fo.FONode;
032: import org.apache.fop.fo.flow.Table;
033: import org.apache.fop.fo.flow.TableColumn;
034: import org.apache.fop.fo.properties.TableColLength;
035:
036: /**
037: * Class holding a number of columns making up the column setup of a row.
038: */
039: public class ColumnSetup {
040:
041: /** Logger **/
042: private static Log log = LogFactory.getLog(ColumnSetup.class);
043:
044: private Table table;
045: private List columns = new java.util.ArrayList();
046: private List colWidths = new java.util.ArrayList();
047:
048: private int maxColIndexReferenced = 0;
049:
050: /**
051: * Main Constructor.
052: * @param table the table to construct this column setup for
053: */
054: public ColumnSetup(Table table) {
055: this .table = table;
056: prepareColumns();
057: initializeColumnWidths();
058: }
059:
060: private void prepareColumns() {
061: List rawCols = table.getColumns();
062: if (rawCols != null) {
063: int colnum = 1;
064: ListIterator iter = rawCols.listIterator();
065: while (iter.hasNext()) {
066: TableColumn col = (TableColumn) iter.next();
067: if (col == null) {
068: continue;
069: }
070: colnum = col.getColumnNumber();
071: for (int i = 0; i < col.getNumberColumnsRepeated(); i++) {
072: while (colnum > columns.size()) {
073: columns.add(null);
074: }
075: columns.set(colnum - 1, col);
076: colnum++;
077: }
078: }
079: //Post-processing the list (looking for gaps)
080: int pos = 1;
081: ListIterator ppIter = columns.listIterator();
082: while (ppIter.hasNext()) {
083: TableColumn col = (TableColumn) ppIter.next();
084: if (col == null) {
085: log
086: .error("Found a gap in the table-columns at position "
087: + pos);
088: }
089: pos++;
090: }
091: }
092: }
093:
094: /**
095: * Returns a column. If the index of the column is bigger than the number of explicitly
096: * defined columns the last column is returned.
097: * @param index index of the column (1 is the first column)
098: * @return the requested column
099: */
100: public TableColumn getColumn(int index) {
101: int size = columns.size();
102: if (index > size) {
103: if (index > maxColIndexReferenced) {
104: maxColIndexReferenced = index;
105: if (!(size == 1 && getColumn(1).isDefaultColumn())) {
106: log
107: .warn(FONode
108: .decorateWithContextInfo(
109: "There are fewer table-columns than are needed. "
110: + "Column "
111: + index
112: + " was accessed, but only "
113: + size
114: + " columns have been defined. "
115: + "The last defined column will be reused.",
116: table));
117: if (!table.isAutoLayout()) {
118: log
119: .warn("Please note that according XSL-FO 1.0 (7.26.9) says that "
120: + "the 'column-width' property must be specified for every "
121: + "column, unless the automatic table layout is used.");
122: }
123: }
124: }
125: return (TableColumn) columns.get(size - 1);
126: } else {
127: return (TableColumn) columns.get(index - 1);
128: }
129: }
130:
131: /** @see java.lang.Object#toString() */
132: public String toString() {
133: return columns.toString();
134: }
135:
136: /** @return the number of columns in the setup. */
137: public int getColumnCount() {
138: if (maxColIndexReferenced > columns.size()) {
139: return maxColIndexReferenced;
140: } else {
141: return columns.size();
142: }
143: }
144:
145: /** @return an Iterator over all columns */
146: public Iterator iterator() {
147: return this .columns.iterator();
148: }
149:
150: /*
151: private void createColumnsFromFirstRow() {
152: //TODO Create oldColumns from first row here
153: //--> rule 2 in "fixed table layout", see CSS2, 17.5.2
154: //Alternative: extend oldColumns on-the-fly, but in this case we need the
155: //new property evaluation context so proportional-column-width() works
156: //correctly.
157: if (columns.size() == 0) {
158: this.columns.add(table.getDefaultColumn());
159: }
160: }
161: */
162:
163: /**
164: * Initializes the column's widths
165: *
166: */
167: private void initializeColumnWidths() {
168:
169: TableColumn col;
170: Length colWidth;
171:
172: for (int i = columns.size(); --i >= 0;) {
173: if (columns.get(i) != null) {
174: col = (TableColumn) columns.get(i);
175: colWidth = col.getColumnWidth();
176: colWidths.add(0, colWidth);
177: }
178: }
179: colWidths.add(0, null);
180: }
181:
182: /**
183: * Works out the base unit for resolving proportional-column-width()
184: * [p-c-w(x) = x * base_unit_ipd]
185: *
186: * @param tlm the TableLayoutManager
187: * @return the computed base unit (in millipoint)
188: */
189: protected double computeTableUnit(TableLayoutManager tlm) {
190:
191: int sumCols = 0;
192: float factors = 0;
193: double unit = 0;
194:
195: /* calculate the total width (specified absolute/percentages),
196: * and work out the total number of factors to use to distribute
197: * the remaining space (if any)
198: */
199: for (Iterator i = colWidths.iterator(); i.hasNext();) {
200: Length colWidth = (Length) i.next();
201: if (colWidth != null) {
202: sumCols += colWidth.getValue(tlm);
203: if (colWidth instanceof TableColLength) {
204: factors += ((TableColLength) colWidth)
205: .getTableUnits();
206: }
207: }
208: }
209:
210: /* distribute the remaining space over the accumulated
211: * factors (if any)
212: */
213: if (factors > 0) {
214: if (sumCols < tlm.getContentAreaIPD()) {
215: unit = (tlm.getContentAreaIPD() - sumCols) / factors;
216: } else {
217: log
218: .warn("No space remaining to distribute over columns.");
219: }
220: }
221:
222: return unit;
223: }
224:
225: /**
226: * @param col column index (1 is first column)
227: * @param context the context for percentage based calculations
228: * @return the X offset of the requested column
229: */
230: public int getXOffset(int col, PercentBaseContext context) {
231: int xoffset = 0;
232: for (int i = col; --i >= 0;) {
233: int effCol;
234: if (i < colWidths.size()) {
235: effCol = i;
236: } else {
237: effCol = colWidths.size() - 1;
238: }
239: if (colWidths.get(effCol) != null) {
240: xoffset += ((Length) colWidths.get(effCol))
241: .getValue(context);
242: }
243: }
244: return xoffset;
245: }
246:
247: /**
248: * Calculates the sum of all column widths.
249: * @param context the context for percentage based calculations
250: * @return the requested sum in millipoints
251: */
252: public int getSumOfColumnWidths(PercentBaseContext context) {
253: int sum = 0;
254: for (int i = 1, c = getColumnCount(); i <= c; i++) {
255: int effIndex = i;
256: if (i >= colWidths.size()) {
257: effIndex = colWidths.size() - 1;
258: }
259: if (colWidths.get(effIndex) != null) {
260: sum += ((Length) colWidths.get(effIndex))
261: .getValue(context);
262: }
263: }
264: return sum;
265: }
266:
267: }
|