/*
 * 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: ColumnSetup.java 1761021 2016-09-16 11:40:57Z ssteiner $ */

package org.apache.fop.layoutmgr.table;

import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.datatypes.Length;
import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.expr.RelativeNumericProperty;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableColumn;
import org.apache.fop.fo.properties.TableColLength;
import org.apache.fop.traits.Direction;
import org.apache.fop.traits.WritingModeTraits;
import org.apache.fop.traits.WritingModeTraitsGetter;

Class holding a number of columns making up the column setup of a row.
/** * Class holding a number of columns making up the column setup of a row. */
public class ColumnSetup {
Logger
/** Logger **/
private static Log log = LogFactory.getLog(ColumnSetup.class); private Table table; private WritingModeTraitsGetter wmTraits; private List columns = new java.util.ArrayList(); private List colWidths = new java.util.ArrayList(); private int maxColIndexReferenced;
Main Constructor.
Params:
  • table – the table to construct this column setup for
/** * Main Constructor. * @param table the table to construct this column setup for */
public ColumnSetup(Table table) { assert table != null; this.table = table; this.wmTraits = WritingModeTraits.getWritingModeTraitsGetter(table); prepareColumns(); initializeColumnWidths(); } private void prepareColumns() { List rawCols = table.getColumns(); if (rawCols != null) { int colnum = 1; for (Object rawCol : rawCols) { TableColumn col = (TableColumn) rawCol; if (col == null) { continue; } colnum = col.getColumnNumber(); for (int i = 0; i < col.getNumberColumnsRepeated(); i++) { while (colnum > columns.size()) { columns.add(null); } columns.set(colnum - 1, col); colnum++; } } //Post-processing the list (looking for gaps) //TODO The following block could possibly be removed int pos = 1; for (Object column : columns) { TableColumn col = (TableColumn) column; if (col == null) { assert false; //Gaps are filled earlier by fo.flow.table.Table.finalizeColumns() //log.error("Found a gap in the table-columns at position " + pos); } pos++; } } }
Returns a column. If the index of the column is bigger than the number of explicitly defined columns the last column is returned.
Params:
  • index – index of the column (1 is the first column)
Returns:the requested column
/** * Returns a column. If the index of the column is bigger than the number of explicitly * defined columns the last column is returned. * @param index index of the column (1 is the first column) * @return the requested column */
public TableColumn getColumn(int index) { int size = columns.size(); if (index > size) { if (index > maxColIndexReferenced) { maxColIndexReferenced = index; TableColumn col = getColumn(1); if (!(size == 1 && col.isImplicitColumn())) { assert false; //TODO Seems to be removable as this is now done in the FO tree log.warn(FONode.decorateWithContextInfo( "There are fewer table-columns than are needed. " + "Column " + index + " was accessed, but only " + size + " columns have been defined. " + "The last defined column will be reused." , table)); if (!table.isAutoLayout()) { log.warn("Please note that according XSL-FO 1.0 (7.26.9) says that " + "the 'column-width' property must be specified for every " + "column, unless the automatic table layout is used."); } } } return (TableColumn) columns.get(size - 1); } else { return (TableColumn) columns.get(index - 1); } }
{@inheritDoc}
/** {@inheritDoc} */
public String toString() { return columns.toString(); }
Returns:the number of columns in the setup.
/** @return the number of columns in the setup. */
public int getColumnCount() { if (maxColIndexReferenced > columns.size()) { return maxColIndexReferenced; } else { return columns.size(); } }
Returns:an Iterator over all columns
/** @return an Iterator over all columns */
public Iterator iterator() { return this.columns.iterator(); } /* private void createColumnsFromFirstRow() { //TODO Create oldColumns from first row here //--> rule 2 in "fixed table layout", see CSS2, 17.5.2 //Alternative: extend oldColumns on-the-fly, but in this case we need the //new property evaluation context so proportional-column-width() works //correctly. if (columns.size() == 0) { this.columns.add(table.getDefaultColumn()); } } */
Initializes the column's widths
/** * Initializes the column's widths * */
private void initializeColumnWidths() { TableColumn col; Length colWidth; for (int i = columns.size(); --i >= 0;) { if (columns.get(i) != null) { col = (TableColumn) columns.get(i); colWidth = col.getColumnWidth(); colWidths.add(0, colWidth); } } colWidths.add(0, null); }
Works out the base unit for resolving proportional-column-width() [p-c-w(x) = x * base_unit_ipd]
Params:
  • tlm – the TableLayoutManager
Returns:the computed base unit (in millipoint)
/** * Works out the base unit for resolving proportional-column-width() * [p-c-w(x) = x * base_unit_ipd] * * @param tlm the TableLayoutManager * @return the computed base unit (in millipoint) */
protected double computeTableUnit(TableLayoutManager tlm) { return computeTableUnit(tlm, tlm.getContentAreaIPD()); }
Works out the base unit for resolving proportional-column-width() [p-c-w(x) = x * base_unit_ipd]
Params:
  • percentBaseContext – the percent base context for relative values
  • contentAreaIPD – the IPD of the available content area
Returns:the computed base unit (in millipoints)
/** * Works out the base unit for resolving proportional-column-width() * [p-c-w(x) = x * base_unit_ipd] * * @param percentBaseContext the percent base context for relative values * @param contentAreaIPD the IPD of the available content area * @return the computed base unit (in millipoints) */
public float computeTableUnit(PercentBaseContext percentBaseContext, int contentAreaIPD) { int sumCols = 0; float factors = 0; float unit = 0; /* calculate the total width (specified absolute/percentages), * and work out the total number of factors to use to distribute * the remaining space (if any) */ for (Object colWidth1 : colWidths) { Length colWidth = (Length) colWidth1; if (colWidth != null) { sumCols += colWidth.getValue(percentBaseContext); if (colWidth instanceof RelativeNumericProperty) { factors += ((RelativeNumericProperty) colWidth).getTableUnits(); } else if (colWidth instanceof TableColLength) { factors += ((TableColLength) colWidth).getTableUnits(); } } } /* distribute the remaining space over the accumulated * factors (if any) */ if (factors > 0) { if (sumCols < contentAreaIPD) { unit = (contentAreaIPD - sumCols) / factors; } else { log.warn("No space remaining to distribute over columns."); } } return unit; }
Determine the X offset of the indicated column, where this offset denotes the left edge of the column irrespective of writing mode. If writing mode's column progression direction is right-to-left, then the first column is the right-most column and the last column is the left-most column; otherwise, the first column is the left-most column.
Params:
  • col – column index (1 is first column)
  • nrColSpan – number columns spanned (for calculating offset in rtl mode)
  • context – the context for percentage based calculations
Returns:the X offset of the requested column
/** * Determine the X offset of the indicated column, where this * offset denotes the left edge of the column irrespective of writing * mode. If writing mode's column progression direction is right-to-left, * then the first column is the right-most column and the last column is * the left-most column; otherwise, the first column is the left-most * column. * @param col column index (1 is first column) * @param nrColSpan number columns spanned (for calculating offset in rtl mode) * @param context the context for percentage based calculations * @return the X offset of the requested column */
public int getXOffset(int col, int nrColSpan, PercentBaseContext context) { // TODO handle vertical WMs [GA] if ((wmTraits != null) && (wmTraits.getColumnProgressionDirection() == Direction.RL)) { return getXOffsetRTL(col, nrColSpan, context); } else { return getXOffsetLTR(col, context); } } /* * Determine x offset by summing widths of columns to left of specified * column; i.e., those columns whose column numbers are greater than the * specified column number. */ private int getXOffsetRTL(int col, int nrColSpan, PercentBaseContext context) { int xoffset = 0; for (int i = (col + nrColSpan - 1), nc = colWidths.size(); ++i < nc;) { int effCol = i; if (colWidths.get(effCol) != null) { xoffset += ((Length) colWidths.get(effCol)).getValue(context); } } return xoffset; } /* * Determine x offset by summing widths of columns to left of specified * column; i.e., those columns whose column numbers are less than the * specified column number. */ private int getXOffsetLTR(int col, PercentBaseContext context) { int xoffset = 0; for (int i = col; --i >= 0;) { int effCol; if (i < colWidths.size()) { effCol = i; } else { effCol = colWidths.size() - 1; } if (colWidths.get(effCol) != null) { xoffset += ((Length) colWidths.get(effCol)).getValue(context); } } return xoffset; }
Calculates the sum of all column widths.
Params:
  • context – the context for percentage based calculations
Returns:the requested sum in millipoints
/** * Calculates the sum of all column widths. * @param context the context for percentage based calculations * @return the requested sum in millipoints */
public int getSumOfColumnWidths(PercentBaseContext context) { int sum = 0; for (int i = 1, c = getColumnCount(); i <= c; i++) { int effIndex = i; if (i >= colWidths.size()) { effIndex = colWidths.size() - 1; } if (colWidths.get(effIndex) != null) { sum += ((Length) colWidths.get(effIndex)).getValue(context); } } return sum; } }