| /* |
| * 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.List; |
| |
| import org.apache.fop.fo.Constants; |
| import org.apache.fop.fo.FONode; |
| import org.apache.fop.fo.properties.CommonBorderPaddingBackground; |
| import org.apache.fop.layoutmgr.ElementListUtils; |
| import org.apache.fop.layoutmgr.Keep; |
| import org.apache.fop.layoutmgr.table.TableCellLayoutManager; |
| |
| /** |
| * This class represents a primary grid unit of a spanned cell. This is the "before-start" |
| * (top-left, usually) grid unit of the span. |
| */ |
| public class PrimaryGridUnit extends GridUnit { |
| |
| /** Cell layout manager. */ |
| private TableCellLayoutManager cellLM; |
| /** List of Knuth elements representing the contents of the cell. */ |
| private List elements; |
| |
| /** Index of the row where this cell starts. */ |
| private int rowIndex; |
| |
| /** Index of the column where this cell starts. */ |
| private int colIndex; |
| |
| /** Links to the spanned grid units. (List of GridUnit arrays, one array represents a row) */ |
| private List rows; |
| /** The calculated size of the cell's content. (cached value) */ |
| private int contentLength = -1; |
| |
| private boolean isSeparateBorderModel; |
| private int halfBorderSeparationBPD; |
| |
| private Keep keepWithPrevious = Keep.KEEP_AUTO; |
| private Keep keepWithNext = Keep.KEEP_AUTO; |
| private int breakBefore = Constants.EN_AUTO; |
| private int breakAfter = Constants.EN_AUTO; |
| |
| /** |
| * Creates a new primary grid unit. |
| * |
| * @param cell table cell which occupies this grid unit |
| * @param colIndex index of the column this grid unit belongs to, zero-based |
| */ |
| PrimaryGridUnit(TableCell cell, int colIndex) { |
| super(cell, 0, 0); |
| this.colIndex = colIndex; |
| this.isSeparateBorderModel = cell.getTable().isSeparateBorderModel(); // TODO |
| this.halfBorderSeparationBPD = cell.getTable().getBorderSeparation().getBPD().getLength() |
| .getValue() / 2; // TODO |
| } |
| |
| /** |
| * Returns the fo:table-header/footer/body element containing this cell. |
| * |
| * @return the enclosing table part |
| */ |
| public TablePart getTablePart() { |
| FONode node = cell.getParent(); |
| if (node instanceof TableRow) { |
| node = node.getParent(); |
| } |
| return (TablePart) node; |
| } |
| |
| public TableCellLayoutManager getCellLM() { |
| assert cellLM != null; |
| return cellLM; |
| } |
| |
| /** {@inheritDoc} */ |
| public PrimaryGridUnit getPrimary() { |
| return this; |
| } |
| |
| /** {@inheritDoc} */ |
| public boolean isPrimary() { |
| return true; |
| } |
| |
| /** |
| * Sets the Knuth elements for the table cell containing this grid unit. |
| * |
| * @param elements a list of ListElement (?) |
| */ |
| public void setElements(List elements) { |
| this.elements = elements; |
| } |
| |
| public List getElements() { |
| return this.elements; |
| } |
| |
| /** |
| * Returns the widths of the border-before and -after for this cell. In the separate |
| * border model the border-separation is included. In the collapsing model only half |
| * of them is counted, since the other halves belong to the neighbouring cells; also, |
| * the returned value is the maximum of the segments of each applicable grid unit. |
| * |
| * @return the sum of the before and after border widths |
| */ |
| public int getBeforeAfterBorderWidth() { |
| return getBeforeBorderWidth(0, ConditionalBorder.NORMAL) |
| + getAfterBorderWidth(ConditionalBorder.NORMAL); |
| } |
| |
| /** |
| * Returns the width of the before-border for the given row-span of this cell. In the |
| * separate border model half of the border-separation is included. In the collapsing |
| * model only half of the border is counted, since the other half belongs to the |
| * preceding cell; also, the returned value is the maximum of the segments of each |
| * applicable grid unit. |
| * |
| * @param rowIndex index of the span for which the border must be computed, 0-based |
| * @param which one of {@link ConditionalBorder#NORMAL}, |
| * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST} |
| * @return the before border width |
| */ |
| public int getBeforeBorderWidth(int rowIndex, int which) { |
| if (isSeparateBorderModel) { |
| if (getCell() == null) { |
| return 0; |
| } else { |
| CommonBorderPaddingBackground cellBorders = getCell() |
| .getCommonBorderPaddingBackground(); |
| switch (which) { |
| case ConditionalBorder.NORMAL: |
| case ConditionalBorder.LEADING_TRAILING: |
| return cellBorders.getBorderBeforeWidth(false) + halfBorderSeparationBPD; |
| case ConditionalBorder.REST: |
| if (cellBorders.getBorderInfo(CommonBorderPaddingBackground.BEFORE).getWidth() |
| .isDiscard()) { |
| return 0; |
| } else { |
| return cellBorders.getBorderBeforeWidth(true) + halfBorderSeparationBPD; |
| } |
| default: |
| assert false; |
| return 0; |
| } |
| } |
| } else { |
| int width = 0; |
| GridUnit[] row = (GridUnit[]) rows.get(rowIndex); |
| for (int i = 0; i < row.length; i++) { |
| width = Math.max(width, |
| row[i].getBorderBefore(which).getRetainedWidth()); |
| } |
| return width / 2; |
| } |
| } |
| |
| /** |
| * Returns the width of the before-after for the given row-span of this cell. In the |
| * separate border model half of the border-separation is included. In the collapsing |
| * model only half of the border is counted, since the other half belongs to the |
| * following cell; also, the returned value is the maximum of the segments of each |
| * applicable grid unit. |
| * |
| * @param rowIndex index of the span for which the border must be computed, 0-based |
| * @param which one of {@link ConditionalBorder#NORMAL}, |
| * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST} |
| * @return the after border width |
| */ |
| public int getAfterBorderWidth(int rowIndex, int which) { |
| if (isSeparateBorderModel) { |
| if (getCell() == null) { |
| return 0; |
| } else { |
| CommonBorderPaddingBackground cellBorders = getCell() |
| .getCommonBorderPaddingBackground(); |
| switch (which) { |
| case ConditionalBorder.NORMAL: |
| case ConditionalBorder.LEADING_TRAILING: |
| return cellBorders.getBorderAfterWidth(false) + halfBorderSeparationBPD; |
| case ConditionalBorder.REST: |
| if (cellBorders.getBorderInfo(CommonBorderPaddingBackground.AFTER).getWidth() |
| .isDiscard()) { |
| return 0; |
| } else { |
| return cellBorders.getBorderAfterWidth(true) + halfBorderSeparationBPD; |
| } |
| default: |
| assert false; |
| return 0; |
| } |
| } |
| } else { |
| int width = 0; |
| GridUnit[] row = (GridUnit[]) rows.get(rowIndex); |
| for (int i = 0; i < row.length; i++) { |
| width = Math.max(width, |
| row[i].getBorderAfter(which).getRetainedWidth()); |
| } |
| return width / 2; |
| } |
| } |
| |
| /** |
| * Returns the width of the before-after for the last row-span of this cell. See |
| * {@link #getAfterBorderWidth(int, int)}. |
| * |
| * @param which one of {@link ConditionalBorder#NORMAL}, |
| * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST} |
| * @return the after border width |
| */ |
| public int getAfterBorderWidth(int which) { |
| return getAfterBorderWidth(getCell().getNumberRowsSpanned() - 1, which); |
| } |
| |
| /** @return the length of the cell content. */ |
| public int getContentLength() { |
| if (contentLength < 0) { |
| contentLength = ElementListUtils.calcContentLength(elements); |
| } |
| return contentLength; |
| } |
| |
| /** |
| * Returns the grid units belonging to the same span as this one. |
| * |
| * @return a list of GridUnit[], each array corresponds to a row |
| */ |
| public List getRows() { |
| return this.rows; |
| } |
| |
| public void addRow(GridUnit[] row) { |
| if (rows == null) { |
| rows = new java.util.ArrayList(); |
| } |
| rows.add(row); |
| } |
| |
| void setRowIndex(int rowIndex) { |
| this.rowIndex = rowIndex; |
| } |
| |
| /** |
| * Returns the index of the row this grid unit belongs to. This is the index, in the |
| * enclosing table part, of the first row spanned by the cell. Note that if the table |
| * has several table-body children, then the index grows continuously across them; |
| * they are considered to form one single part, the "body of the table". |
| * |
| * @return the index of the row this grid unit belongs to, 0-based. |
| */ |
| public int getRowIndex() { |
| return rowIndex; |
| } |
| |
| /** |
| * Returns the index of the column this grid unit belongs to. |
| * |
| * @return the column index, 0-based |
| */ |
| public int getColIndex() { |
| return colIndex; |
| } |
| |
| /** |
| * Returns the widths of the start- and end-borders of the span this grid unit belongs |
| * to. |
| * |
| * @return a two-element array containing the widths of the start-border then the |
| * end-border |
| */ |
| public int[] getStartEndBorderWidths() { |
| int[] widths = new int[2]; |
| if (getCell() == null) { |
| return widths; |
| } else if (getCell().getTable().isSeparateBorderModel()) { |
| widths[0] = getCell().getCommonBorderPaddingBackground().getBorderStartWidth(false); |
| widths[1] = getCell().getCommonBorderPaddingBackground().getBorderEndWidth(false); |
| } else { |
| for (int i = 0; i < rows.size(); i++) { |
| GridUnit[] gridUnits = (GridUnit[])rows.get(i); |
| widths[0] = Math.max(widths[0], |
| gridUnits[0].borderStart.getBorderInfo().getRetainedWidth()); |
| widths[1] = Math.max(widths[1], gridUnits[gridUnits.length - 1].borderEnd |
| .getBorderInfo().getRetainedWidth()); |
| } |
| } |
| return widths; |
| } |
| |
| /** {@inheritDoc} */ |
| public String toString() { |
| StringBuffer sb = new StringBuffer(super.toString()); |
| sb.append(" rowIndex=").append(rowIndex); |
| sb.append(" colIndex=").append(colIndex); |
| return sb.toString(); |
| } |
| |
| /** @return true if this cell spans over more than one grid unit. */ |
| public boolean hasSpanning() { |
| return (getCell().getNumberColumnsSpanned() > 1) |
| || (getCell().getNumberRowsSpanned() > 1); |
| } |
| |
| /** |
| * Creates a cellLM for the corresponding table-cell. A new one must be created |
| * for each new static-content (TODO). |
| */ |
| public void createCellLM() { |
| cellLM = new TableCellLayoutManager(cell, this); |
| } |
| |
| /** |
| * Returns the strength of the keep constraint if the first child block (or its descendants) |
| * of this cell has keep-with-previous. |
| * |
| * @return the keep-with-previous strength |
| */ |
| public Keep getKeepWithPrevious() { |
| return keepWithPrevious; |
| } |
| |
| /** |
| * Don't use, reserved for TableCellLM. TODO |
| * @param keep the keep strength |
| */ |
| public void setKeepWithPrevious(Keep keep) { |
| this.keepWithPrevious = keep; |
| } |
| |
| /** |
| * Returns the strength of the keep constraint if the last child block (or its descendants) of |
| * this cell has keep-with-next. |
| * |
| * @return the keep-with-next strength |
| */ |
| public Keep getKeepWithNext() { |
| return keepWithNext; |
| } |
| |
| /** |
| * Don't use, reserved for TableCellLM. TODO |
| * @param keep the keep strength |
| */ |
| public void setKeepWithNext(Keep keep) { |
| this.keepWithNext = keep; |
| } |
| |
| /** |
| * Returns the class of the before break for the first child element of this cell. |
| * |
| * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link |
| * Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE} |
| */ |
| public int getBreakBefore() { |
| return breakBefore; |
| } |
| |
| /** |
| * Don't use, reserved for TableCellLM. TODO |
| * |
| * @param breakBefore the breakBefore to set |
| */ |
| public void setBreakBefore(int breakBefore) { |
| this.breakBefore = breakBefore; |
| } |
| |
| /** |
| * Returns the class of the before after for the last child element of this cell. |
| * |
| * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link |
| * Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE} |
| */ |
| public int getBreakAfter() { |
| return breakAfter; |
| } |
| |
| /** |
| * Don't use, reserved for TableCellLM. TODO |
| * |
| * @param breakAfter the breakAfter to set |
| */ |
| public void setBreakAfter(int breakAfter) { |
| this.breakAfter = breakAfter; |
| } |
| |
| } |