0001: /*
0002: * $Id: PdfPTable.java 2863 2007-07-02 10:21:42Z psoares33 $
0003: * $Name$
0004: *
0005: * Copyright 2001, 2002 Paulo Soares
0006: *
0007: * The contents of this file are subject to the Mozilla Public License Version 1.1
0008: * (the "License"); you may not use this file except in compliance with the License.
0009: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
0010: *
0011: * Software distributed under the License is distributed on an "AS IS" basis,
0012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013: * for the specific language governing rights and limitations under the License.
0014: *
0015: * The Original Code is 'iText, a free JAVA-PDF library'.
0016: *
0017: * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
0018: * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
0019: * All Rights Reserved.
0020: * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
0021: * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
0022: *
0023: * Contributor(s): all the names of the contributors are added in the source code
0024: * where applicable.
0025: *
0026: * Alternatively, the contents of this file may be used under the terms of the
0027: * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
0028: * provisions of LGPL are applicable instead of those above. If you wish to
0029: * allow use of your version of this file only under the terms of the LGPL
0030: * License and not to allow others to use your version of this file under
0031: * the MPL, indicate your decision by deleting the provisions above and
0032: * replace them with the notice and other provisions required by the LGPL.
0033: * If you do not delete the provisions above, a recipient may use your version
0034: * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
0035: *
0036: * This library is free software; you can redistribute it and/or modify it
0037: * under the terms of the MPL as stated above or under the terms of the GNU
0038: * Library General Public License as published by the Free Software Foundation;
0039: * either version 2 of the License, or any later version.
0040: *
0041: * This library is distributed in the hope that it will be useful, but WITHOUT
0042: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0043: * FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
0044: * details.
0045: *
0046: * If you didn't download this code from the following link, you should check if
0047: * you aren't using an obsolete version:
0048: * http://www.lowagie.com/iText/
0049: */
0050:
0051: package com.lowagie.text.pdf;
0052:
0053: import java.util.ArrayList;
0054:
0055: import com.lowagie.text.DocumentException;
0056: import com.lowagie.text.Element;
0057: import com.lowagie.text.ElementListener;
0058: import com.lowagie.text.Image;
0059: import com.lowagie.text.Phrase;
0060: import com.lowagie.text.Rectangle;
0061: import com.lowagie.text.pdf.events.PdfPTableEventForwarder;
0062:
0063: /** This is a table that can be put at an absolute position but can also
0064: * be added to the document as the class <CODE>Table</CODE>.
0065: * In the last case when crossing pages the table always break at full rows; if a
0066: * row is bigger than the page it is dropped silently to avoid infinite loops.
0067: * <P>
0068: * A PdfPTableEvent can be associated to the table to do custom drawing
0069: * when the table is rendered.
0070: * @author Paulo Soares (psoares@consiste.pt)
0071: */
0072:
0073: public class PdfPTable implements Element {
0074:
0075: /** The index of the original <CODE>PdfcontentByte</CODE>.
0076: */
0077: public static final int BASECANVAS = 0;
0078: /** The index of the duplicate <CODE>PdfContentByte</CODE> where the background will be drawn.
0079: */
0080: public static final int BACKGROUNDCANVAS = 1;
0081: /** The index of the duplicate <CODE>PdfContentByte</CODE> where the border lines will be drawn.
0082: */
0083: public static final int LINECANVAS = 2;
0084: /** The index of the duplicate <CODE>PdfContentByte</CODE> where the text will be drawn.
0085: */
0086: public static final int TEXTCANVAS = 3;
0087:
0088: protected ArrayList rows = new ArrayList();
0089: protected float totalHeight = 0;
0090: protected PdfPCell currentRow[];
0091: protected int currentRowIdx = 0;
0092: protected PdfPCell defaultCell = new PdfPCell((Phrase) null);
0093: protected float totalWidth = 0;
0094: protected float relativeWidths[];
0095: protected float absoluteWidths[];
0096: protected PdfPTableEvent tableEvent;
0097:
0098: /** Holds value of property headerRows. */
0099: protected int headerRows;
0100:
0101: /** Holds value of property widthPercentage. */
0102: protected float widthPercentage = 80;
0103:
0104: /** Holds value of property horizontalAlignment. */
0105: private int horizontalAlignment = Element.ALIGN_CENTER;
0106:
0107: /** Holds value of property skipFirstHeader. */
0108: private boolean skipFirstHeader = false;
0109:
0110: protected boolean isColspan = false;
0111:
0112: protected int runDirection = PdfWriter.RUN_DIRECTION_DEFAULT;
0113:
0114: /**
0115: * Holds value of property lockedWidth.
0116: */
0117: private boolean lockedWidth = false;
0118:
0119: /**
0120: * Holds value of property splitRows.
0121: */
0122: private boolean splitRows = true;
0123:
0124: /** The spacing before the table. */
0125: protected float spacingBefore;
0126:
0127: /** The spacing after the table. */
0128: protected float spacingAfter;
0129:
0130: /**
0131: * Holds value of property extendLastRow.
0132: */
0133: private boolean extendLastRow;
0134:
0135: /**
0136: * Holds value of property headersInEvent.
0137: */
0138: private boolean headersInEvent;
0139:
0140: /**
0141: * Holds value of property splitLate.
0142: */
0143: private boolean splitLate = true;
0144:
0145: /**
0146: * Defines if the table should be kept
0147: * on one page if possible
0148: */
0149: private boolean keepTogether;
0150:
0151: /**
0152: * Holds value of property footerRows.
0153: */
0154: private int footerRows;
0155:
0156: protected PdfPTable() {
0157: }
0158:
0159: /** Constructs a <CODE>PdfPTable</CODE> with the relative column widths.
0160: * @param relativeWidths the relative column widths
0161: */
0162: public PdfPTable(float relativeWidths[]) {
0163: if (relativeWidths == null)
0164: throw new NullPointerException(
0165: "The widths array in PdfPTable constructor can not be null.");
0166: if (relativeWidths.length == 0)
0167: throw new IllegalArgumentException(
0168: "The widths array in PdfPTable constructor can not have zero length.");
0169: this .relativeWidths = new float[relativeWidths.length];
0170: System.arraycopy(relativeWidths, 0, this .relativeWidths, 0,
0171: relativeWidths.length);
0172: absoluteWidths = new float[relativeWidths.length];
0173: calculateWidths();
0174: currentRow = new PdfPCell[absoluteWidths.length];
0175: keepTogether = false;
0176: }
0177:
0178: /** Constructs a <CODE>PdfPTable</CODE> with <CODE>numColumns</CODE> columns.
0179: * @param numColumns the number of columns
0180: */
0181: public PdfPTable(int numColumns) {
0182: if (numColumns <= 0)
0183: throw new IllegalArgumentException(
0184: "The number of columns in PdfPTable constructor must be greater than zero.");
0185: relativeWidths = new float[numColumns];
0186: for (int k = 0; k < numColumns; ++k)
0187: relativeWidths[k] = 1;
0188: absoluteWidths = new float[relativeWidths.length];
0189: calculateWidths();
0190: currentRow = new PdfPCell[absoluteWidths.length];
0191: keepTogether = false;
0192: }
0193:
0194: /** Constructs a copy of a <CODE>PdfPTable</CODE>.
0195: * @param table the <CODE>PdfPTable</CODE> to be copied
0196: */
0197: public PdfPTable(PdfPTable table) {
0198: copyFormat(table);
0199: for (int k = 0; k < currentRow.length; ++k) {
0200: if (table.currentRow[k] == null)
0201: break;
0202: currentRow[k] = new PdfPCell(table.currentRow[k]);
0203: }
0204: for (int k = 0; k < table.rows.size(); ++k) {
0205: PdfPRow row = (PdfPRow) (table.rows.get(k));
0206: if (row != null)
0207: row = new PdfPRow(row);
0208: rows.add(row);
0209: }
0210: }
0211:
0212: /**
0213: * Makes a shallow copy of a table (format without content).
0214: * @param table
0215: * @return a shallow copy of the table
0216: */
0217: public static PdfPTable shallowCopy(PdfPTable table) {
0218: PdfPTable nt = new PdfPTable();
0219: nt.copyFormat(table);
0220: return nt;
0221: }
0222:
0223: /**
0224: * Copies the format of the sourceTable without copying the content.
0225: * @param sourceTable
0226: */
0227: private void copyFormat(PdfPTable sourceTable) {
0228: relativeWidths = new float[sourceTable.relativeWidths.length];
0229: absoluteWidths = new float[sourceTable.relativeWidths.length];
0230: System.arraycopy(sourceTable.relativeWidths, 0, relativeWidths,
0231: 0, relativeWidths.length);
0232: System.arraycopy(sourceTable.absoluteWidths, 0, absoluteWidths,
0233: 0, relativeWidths.length);
0234: totalWidth = sourceTable.totalWidth;
0235: totalHeight = sourceTable.totalHeight;
0236: currentRowIdx = 0;
0237: tableEvent = sourceTable.tableEvent;
0238: runDirection = sourceTable.runDirection;
0239: defaultCell = new PdfPCell(sourceTable.defaultCell);
0240: currentRow = new PdfPCell[sourceTable.currentRow.length];
0241: isColspan = sourceTable.isColspan;
0242: splitRows = sourceTable.splitRows;
0243: spacingAfter = sourceTable.spacingAfter;
0244: spacingBefore = sourceTable.spacingBefore;
0245: headerRows = sourceTable.headerRows;
0246: footerRows = sourceTable.footerRows;
0247: lockedWidth = sourceTable.lockedWidth;
0248: extendLastRow = sourceTable.extendLastRow;
0249: headersInEvent = sourceTable.headersInEvent;
0250: widthPercentage = sourceTable.widthPercentage;
0251: splitLate = sourceTable.splitLate;
0252: skipFirstHeader = sourceTable.skipFirstHeader;
0253: horizontalAlignment = sourceTable.horizontalAlignment;
0254: keepTogether = sourceTable.keepTogether;
0255: }
0256:
0257: /** Sets the relative widths of the table.
0258: * @param relativeWidths the relative widths of the table.
0259: * @throws DocumentException if the number of widths is different than the number
0260: * of columns
0261: */
0262: public void setWidths(float relativeWidths[])
0263: throws DocumentException {
0264: if (relativeWidths.length != this .relativeWidths.length)
0265: throw new DocumentException("Wrong number of columns.");
0266: this .relativeWidths = new float[relativeWidths.length];
0267: System.arraycopy(relativeWidths, 0, this .relativeWidths, 0,
0268: relativeWidths.length);
0269: absoluteWidths = new float[relativeWidths.length];
0270: totalHeight = 0;
0271: calculateWidths();
0272: calculateHeights();
0273: }
0274:
0275: /** Sets the relative widths of the table.
0276: * @param relativeWidths the relative widths of the table.
0277: * @throws DocumentException if the number of widths is different than the number
0278: * of columns
0279: */
0280: public void setWidths(int relativeWidths[])
0281: throws DocumentException {
0282: float tb[] = new float[relativeWidths.length];
0283: for (int k = 0; k < relativeWidths.length; ++k)
0284: tb[k] = relativeWidths[k];
0285: setWidths(tb);
0286: }
0287:
0288: private void calculateWidths() {
0289: if (totalWidth <= 0)
0290: return;
0291: float total = 0;
0292: for (int k = 0; k < absoluteWidths.length; ++k) {
0293: total += relativeWidths[k];
0294: }
0295: for (int k = 0; k < absoluteWidths.length; ++k) {
0296: absoluteWidths[k] = totalWidth * relativeWidths[k] / total;
0297: }
0298: }
0299:
0300: /** Sets the full width of the table.
0301: * @param totalWidth the full width of the table.
0302: */
0303: public void setTotalWidth(float totalWidth) {
0304: if (this .totalWidth == totalWidth)
0305: return;
0306: this .totalWidth = totalWidth;
0307: totalHeight = 0;
0308: calculateWidths();
0309: calculateHeights();
0310: }
0311:
0312: /** Sets the full width of the table from the absolute column width.
0313: * @param columnWidth the absolute width of each column
0314: * @throws DocumentException if the number of widths is different than the number
0315: * of columns
0316: */
0317: public void setTotalWidth(float columnWidth[])
0318: throws DocumentException {
0319: if (columnWidth.length != this .relativeWidths.length)
0320: throw new DocumentException("Wrong number of columns.");
0321: totalWidth = 0;
0322: for (int k = 0; k < columnWidth.length; ++k)
0323: totalWidth += columnWidth[k];
0324: setWidths(columnWidth);
0325: }
0326:
0327: /** Sets the percentage width of the table from the absolute column width.
0328: * @param columnWidth the absolute width of each column
0329: * @param pageSize the page size
0330: * @throws DocumentException
0331: */
0332: public void setWidthPercentage(float columnWidth[],
0333: Rectangle pageSize) throws DocumentException {
0334: if (columnWidth.length != this .relativeWidths.length)
0335: throw new IllegalArgumentException(
0336: "Wrong number of columns.");
0337: float totalWidth = 0;
0338: for (int k = 0; k < columnWidth.length; ++k)
0339: totalWidth += columnWidth[k];
0340: widthPercentage = totalWidth
0341: / (pageSize.getRight() - pageSize.getLeft()) * 100f;
0342: setWidths(columnWidth);
0343: }
0344:
0345: /** Gets the full width of the table.
0346: * @return the full width of the table
0347: */
0348: public float getTotalWidth() {
0349: return totalWidth;
0350: }
0351:
0352: void calculateHeights() {
0353: if (totalWidth <= 0)
0354: return;
0355: totalHeight = 0;
0356: for (int k = 0; k < rows.size(); ++k) {
0357: PdfPRow row = (PdfPRow) rows.get(k);
0358: if (row != null) {
0359: row.setWidths(absoluteWidths);
0360: totalHeight += row.getMaxHeights();
0361: }
0362: }
0363: }
0364:
0365: /**
0366: * Calculates the heights of the table.
0367: */
0368: public void calculateHeightsFast() {
0369: if (totalWidth <= 0)
0370: return;
0371: totalHeight = 0;
0372: for (int k = 0; k < rows.size(); ++k) {
0373: PdfPRow row = (PdfPRow) rows.get(k);
0374: if (row != null)
0375: totalHeight += row.getMaxHeights();
0376: }
0377: }
0378:
0379: /** Gets the default <CODE>PdfPCell</CODE> that will be used as
0380: * reference for all the <CODE>addCell</CODE> methods except
0381: * <CODE>addCell(PdfPCell)</CODE>.
0382: * @return default <CODE>PdfPCell</CODE>
0383: */
0384: public PdfPCell getDefaultCell() {
0385: return defaultCell;
0386: }
0387:
0388: /** Adds a cell element.
0389: * @param cell the cell element
0390: */
0391: public void addCell(PdfPCell cell) {
0392: PdfPCell ncell = new PdfPCell(cell);
0393: int colspan = ncell.getColspan();
0394: colspan = Math.max(colspan, 1);
0395: colspan = Math.min(colspan, currentRow.length - currentRowIdx);
0396: ncell.setColspan(colspan);
0397: if (colspan != 1)
0398: isColspan = true;
0399: int rdir = ncell.getRunDirection();
0400: if (rdir == PdfWriter.RUN_DIRECTION_DEFAULT)
0401: ncell.setRunDirection(runDirection);
0402: currentRow[currentRowIdx] = ncell;
0403: currentRowIdx += colspan;
0404: if (currentRowIdx >= currentRow.length) {
0405: if (runDirection == PdfWriter.RUN_DIRECTION_RTL) {
0406: PdfPCell rtlRow[] = new PdfPCell[absoluteWidths.length];
0407: int rev = currentRow.length;
0408: for (int k = 0; k < currentRow.length; ++k) {
0409: PdfPCell rcell = currentRow[k];
0410: int cspan = rcell.getColspan();
0411: rev -= cspan;
0412: rtlRow[rev] = rcell;
0413: k += cspan - 1;
0414: }
0415: currentRow = rtlRow;
0416: }
0417: PdfPRow row = new PdfPRow(currentRow);
0418: if (totalWidth > 0) {
0419: row.setWidths(absoluteWidths);
0420: totalHeight += row.getMaxHeights();
0421: }
0422: rows.add(row);
0423: currentRow = new PdfPCell[absoluteWidths.length];
0424: currentRowIdx = 0;
0425: }
0426: }
0427:
0428: /** Adds a cell element.
0429: * @param text the text for the cell
0430: */
0431: public void addCell(String text) {
0432: addCell(new Phrase(text));
0433: }
0434:
0435: /**
0436: * Adds a nested table.
0437: * @param table the table to be added to the cell
0438: */
0439: public void addCell(PdfPTable table) {
0440: defaultCell.setTable(table);
0441: addCell(defaultCell);
0442: defaultCell.setTable(null);
0443: }
0444:
0445: /**
0446: * Adds an Image as Cell.
0447: * @param image the <CODE>Image</CODE> to add to the table. This image will fit in the cell
0448: */
0449: public void addCell(Image image) {
0450: defaultCell.setImage(image);
0451: addCell(defaultCell);
0452: defaultCell.setImage(null);
0453: }
0454:
0455: /**
0456: * Adds a cell element.
0457: * @param phrase the <CODE>Phrase</CODE> to be added to the cell
0458: */
0459: public void addCell(Phrase phrase) {
0460: defaultCell.setPhrase(phrase);
0461: addCell(defaultCell);
0462: defaultCell.setPhrase(null);
0463: }
0464:
0465: /**
0466: * Writes the selected rows to the document.
0467: * <P>
0468: * <CODE>canvases</CODE> is obtained from <CODE>beginWritingRows()</CODE>.
0469: * @param rowStart the first row to be written, zero index
0470: * @param rowEnd the last row to be written + 1. If it is -1 all the
0471: * rows to the end are written
0472: * @param xPos the x write coodinate
0473: * @param yPos the y write coodinate
0474: * @param canvases an array of 4 <CODE>PdfContentByte</CODE> obtained from
0475: * <CODE>beginWrittingRows()</CODE>
0476: * @return the y coordinate position of the bottom of the last row
0477: * @see #beginWritingRows(com.lowagie.text.pdf.PdfContentByte)
0478: */
0479: public float writeSelectedRows(int rowStart, int rowEnd,
0480: float xPos, float yPos, PdfContentByte[] canvases) {
0481: return writeSelectedRows(0, -1, rowStart, rowEnd, xPos, yPos,
0482: canvases);
0483: }
0484:
0485: /** Writes the selected rows and columns to the document.
0486: * This method does not clip the columns; this is only important
0487: * if there are columns with colspan at boundaries.
0488: * <P>
0489: * <CODE>canvases</CODE> is obtained from <CODE>beginWritingRows()</CODE>.
0490: * <P>
0491: * The table event is only fired for complete rows.
0492: * @param colStart the first column to be written, zero index
0493: * @param colEnd the last column to be written + 1. If it is -1 all the
0494: * columns to the end are written
0495: * @param rowStart the first row to be written, zero index
0496: * @param rowEnd the last row to be written + 1. If it is -1 all the
0497: * rows to the end are written
0498: * @param xPos the x write coodinate
0499: * @param yPos the y write coodinate
0500: * @param canvases an array of 4 <CODE>PdfContentByte</CODE> obtained from
0501: * <CODE>beginWrittingRows()</CODE>
0502: * @return the y coordinate position of the bottom of the last row
0503: * @see #beginWritingRows(com.lowagie.text.pdf.PdfContentByte)
0504: */
0505: public float writeSelectedRows(int colStart, int colEnd,
0506: int rowStart, int rowEnd, float xPos, float yPos,
0507: PdfContentByte[] canvases) {
0508: if (totalWidth <= 0)
0509: throw new RuntimeException(
0510: "The table width must be greater than zero.");
0511: int size = rows.size();
0512: if (rowEnd < 0)
0513: rowEnd = size;
0514: rowEnd = Math.min(rowEnd, size);
0515: if (rowStart < 0)
0516: rowStart = 0;
0517: if (rowStart >= rowEnd)
0518: return yPos;
0519: if (colEnd < 0)
0520: colEnd = absoluteWidths.length;
0521: colEnd = Math.min(colEnd, absoluteWidths.length);
0522: if (colStart < 0)
0523: colStart = 0;
0524: colStart = Math.min(colStart, absoluteWidths.length);
0525: float yPosStart = yPos;
0526: for (int k = rowStart; k < rowEnd; ++k) {
0527: PdfPRow row = (PdfPRow) rows.get(k);
0528: if (row != null) {
0529: row.writeCells(colStart, colEnd, xPos, yPos, canvases);
0530: yPos -= row.getMaxHeights();
0531: }
0532: }
0533: if (tableEvent != null && colStart == 0
0534: && colEnd == absoluteWidths.length) {
0535: float heights[] = new float[rowEnd - rowStart + 1];
0536: heights[0] = yPosStart;
0537: for (int k = rowStart; k < rowEnd; ++k) {
0538: PdfPRow row = (PdfPRow) rows.get(k);
0539: float hr = 0;
0540: if (row != null)
0541: hr = row.getMaxHeights();
0542: heights[k - rowStart + 1] = heights[k - rowStart] - hr;
0543: }
0544: tableEvent
0545: .tableLayout(this , getEventWidths(xPos, rowStart,
0546: rowEnd, headersInEvent), heights,
0547: headersInEvent ? headerRows : 0, rowStart,
0548: canvases);
0549: }
0550: return yPos;
0551: }
0552:
0553: /**
0554: * Writes the selected rows to the document.
0555: *
0556: * @param rowStart the first row to be written, zero index
0557: * @param rowEnd the last row to be written + 1. If it is -1 all the
0558: * rows to the end are written
0559: * @param xPos the x write coodinate
0560: * @param yPos the y write coodinate
0561: * @param canvas the <CODE>PdfContentByte</CODE> where the rows will
0562: * be written to
0563: * @return the y coordinate position of the bottom of the last row
0564: */
0565: public float writeSelectedRows(int rowStart, int rowEnd,
0566: float xPos, float yPos, PdfContentByte canvas) {
0567: return writeSelectedRows(0, -1, rowStart, rowEnd, xPos, yPos,
0568: canvas);
0569: }
0570:
0571: /**
0572: * Writes the selected rows to the document.
0573: * This method clips the columns; this is only important
0574: * if there are columns with colspan at boundaries.
0575: * <P>
0576: * The table event is only fired for complete rows.
0577: *
0578: * @param colStart the first column to be written, zero index
0579: * @param colEnd the last column to be written + 1. If it is -1 all the
0580: * @param rowStart the first row to be written, zero index
0581: * @param rowEnd the last row to be written + 1. If it is -1 all the
0582: * rows to the end are written
0583: * @param xPos the x write coodinate
0584: * @param yPos the y write coodinate
0585: * @param canvas the <CODE>PdfContentByte</CODE> where the rows will
0586: * be written to
0587: * @return the y coordinate position of the bottom of the last row
0588: */
0589: public float writeSelectedRows(int colStart, int colEnd,
0590: int rowStart, int rowEnd, float xPos, float yPos,
0591: PdfContentByte canvas) {
0592: if (colEnd < 0)
0593: colEnd = absoluteWidths.length;
0594: colEnd = Math.min(colEnd, absoluteWidths.length);
0595: if (colStart < 0)
0596: colStart = 0;
0597: colStart = Math.min(colStart, absoluteWidths.length);
0598: if (colStart != 0 || colEnd != absoluteWidths.length) {
0599: float w = 0;
0600: for (int k = colStart; k < colEnd; ++k)
0601: w += absoluteWidths[k];
0602: canvas.saveState();
0603: float lx = 0;
0604: float rx = 0;
0605: if (colStart == 0)
0606: lx = 10000;
0607: if (colEnd == absoluteWidths.length)
0608: rx = 10000;
0609: canvas.rectangle(xPos - lx, -10000, w + lx + rx, 20000);
0610: canvas.clip();
0611: canvas.newPath();
0612: }
0613: PdfContentByte[] canvases = beginWritingRows(canvas);
0614: float y = writeSelectedRows(colStart, colEnd, rowStart, rowEnd,
0615: xPos, yPos, canvases);
0616: endWritingRows(canvases);
0617: if (colStart != 0 || colEnd != absoluteWidths.length)
0618: canvas.restoreState();
0619: return y;
0620: }
0621:
0622: /** Gets and initializes the 4 layers where the table is written to. The text or graphics are added to
0623: * one of the 4 <CODE>PdfContentByte</CODE> returned with the following order:<p>
0624: * <ul>
0625: * <li><CODE>PdfPtable.BASECANVAS</CODE> - the original <CODE>PdfContentByte</CODE>. Anything placed here
0626: * will be under the table.
0627: * <li><CODE>PdfPtable.BACKGROUNDCANVAS</CODE> - the layer where the background goes to.
0628: * <li><CODE>PdfPtable.LINECANVAS</CODE> - the layer where the lines go to.
0629: * <li><CODE>PdfPtable.TEXTCANVAS</CODE> - the layer where the text go to. Anything placed here
0630: * will be over the table.
0631: * </ul><p>
0632: * The layers are placed in sequence on top of each other.
0633: * @param canvas the <CODE>PdfContentByte</CODE> where the rows will
0634: * be written to
0635: * @return an array of 4 <CODE>PdfContentByte</CODE>
0636: * @see #writeSelectedRows(int, int, float, float, PdfContentByte[])
0637: */
0638: public static PdfContentByte[] beginWritingRows(
0639: PdfContentByte canvas) {
0640: return new PdfContentByte[] { canvas, canvas.getDuplicate(),
0641: canvas.getDuplicate(), canvas.getDuplicate(), };
0642: }
0643:
0644: /** Finishes writing the table.
0645: * @param canvases the array returned by <CODE>beginWritingRows()</CODE>
0646: */
0647: public static void endWritingRows(PdfContentByte[] canvases) {
0648: PdfContentByte canvas = canvases[BASECANVAS];
0649: canvas.saveState();
0650: canvas.add(canvases[BACKGROUNDCANVAS]);
0651: canvas.restoreState();
0652: canvas.saveState();
0653: canvas.setLineCap(2);
0654: canvas.resetRGBColorStroke();
0655: canvas.add(canvases[LINECANVAS]);
0656: canvas.restoreState();
0657: canvas.add(canvases[TEXTCANVAS]);
0658: }
0659:
0660: /** Gets the number of rows in this table.
0661: * @return the number of rows in this table
0662: */
0663: public int size() {
0664: return rows.size();
0665: }
0666:
0667: /** Gets the total height of the table.
0668: * @return the total height of the table
0669: */
0670: public float getTotalHeight() {
0671: return totalHeight;
0672: }
0673:
0674: /** Gets the height of a particular row.
0675: * @param idx the row index (starts at 0)
0676: * @return the height of a particular row
0677: */
0678: public float getRowHeight(int idx) {
0679: if (totalWidth <= 0 || idx < 0 || idx >= rows.size())
0680: return 0;
0681: PdfPRow row = (PdfPRow) rows.get(idx);
0682: if (row == null)
0683: return 0;
0684: return row.getMaxHeights();
0685: }
0686:
0687: /** Gets the height of the rows that constitute the header as defined by
0688: * <CODE>setHeaderRows()</CODE>.
0689: * @return the height of the rows that constitute the header
0690: */
0691: public float getHeaderHeight() {
0692: float total = 0;
0693: int size = Math.min(rows.size(), headerRows);
0694: for (int k = 0; k < size; ++k) {
0695: PdfPRow row = (PdfPRow) rows.get(k);
0696: if (row != null)
0697: total += row.getMaxHeights();
0698: }
0699: return total;
0700: }
0701:
0702: /** Deletes a row from the table.
0703: * @param rowNumber the row to be deleted
0704: * @return <CODE>true</CODE> if the row was deleted
0705: */
0706: public boolean deleteRow(int rowNumber) {
0707: if (rowNumber < 0 || rowNumber >= rows.size()) {
0708: return false;
0709: }
0710: if (totalWidth > 0) {
0711: PdfPRow row = (PdfPRow) rows.get(rowNumber);
0712: if (row != null)
0713: totalHeight -= row.getMaxHeights();
0714: }
0715: rows.remove(rowNumber);
0716: return true;
0717: }
0718:
0719: /** Deletes the last row in the table.
0720: * @return <CODE>true</CODE> if the last row was deleted
0721: */
0722: public boolean deleteLastRow() {
0723: return deleteRow(rows.size() - 1);
0724: }
0725:
0726: /**
0727: * Removes all of the rows except headers
0728: */
0729: public void deleteBodyRows() {
0730: ArrayList rows2 = new ArrayList();
0731: for (int k = 0; k < headerRows; ++k)
0732: rows2.add(rows.get(k));
0733: rows = rows2;
0734: totalHeight = 0;
0735: if (totalWidth > 0)
0736: totalHeight = getHeaderHeight();
0737: }
0738:
0739: /** Gets the number of the rows that constitute the header.
0740: * @return the number of the rows that constitute the header
0741: */
0742: public int getHeaderRows() {
0743: return headerRows;
0744: }
0745:
0746: /** Sets the number of the top rows that constitute the header.
0747: * This header has only meaning if the table is added to <CODE>Document</CODE>
0748: * and the table crosses pages.
0749: * @param headerRows the number of the top rows that constitute the header
0750: */
0751: public void setHeaderRows(int headerRows) {
0752: if (headerRows < 0)
0753: headerRows = 0;
0754: this .headerRows = headerRows;
0755: }
0756:
0757: /**
0758: * Gets all the chunks in this element.
0759: *
0760: * @return an <CODE>ArrayList</CODE>
0761: */
0762: public ArrayList getChunks() {
0763: return new ArrayList();
0764: }
0765:
0766: /**
0767: * Gets the type of the text element.
0768: *
0769: * @return a type
0770: */
0771: public int type() {
0772: return Element.PTABLE;
0773: }
0774:
0775: /**
0776: * Processes the element by adding it (or the different parts) to an
0777: * <CODE>ElementListener</CODE>.
0778: *
0779: * @param listener an <CODE>ElementListener</CODE>
0780: * @return <CODE>true</CODE> if the element was processed successfully
0781: */
0782: public boolean process(ElementListener listener) {
0783: try {
0784: return listener.add(this );
0785: } catch (DocumentException de) {
0786: return false;
0787: }
0788: }
0789:
0790: /** Gets the width percentage that the table will occupy in the page.
0791: * @return the width percentage that the table will occupy in the page
0792: */
0793: public float getWidthPercentage() {
0794: return widthPercentage;
0795: }
0796:
0797: /** Sets the width percentage that the table will occupy in the page.
0798: * @param widthPercentage the width percentage that the table will occupy in the page
0799: */
0800: public void setWidthPercentage(float widthPercentage) {
0801: this .widthPercentage = widthPercentage;
0802: }
0803:
0804: /** Gets the horizontal alignment of the table relative to the page.
0805: * @return the horizontal alignment of the table relative to the page
0806: */
0807: public int getHorizontalAlignment() {
0808: return horizontalAlignment;
0809: }
0810:
0811: /** Sets the horizontal alignment of the table relative to the page.
0812: * It only has meaning if the width percentage is less than
0813: * 100%.
0814: * @param horizontalAlignment the horizontal alignment of the table relative to the page
0815: */
0816: public void setHorizontalAlignment(int horizontalAlignment) {
0817: this .horizontalAlignment = horizontalAlignment;
0818: }
0819:
0820: /**
0821: * Gets a row with a given index
0822: * (added by Jin-Hsia Yang).
0823: * @param idx
0824: * @return the row at position idx
0825: */
0826: public PdfPRow getRow(int idx) {
0827: return (PdfPRow) rows.get(idx);
0828: }
0829:
0830: /**
0831: * Gets an arraylist with all the rows in the table.
0832: * @return an arraylist
0833: */
0834: public ArrayList getRows() {
0835: return rows;
0836: }
0837:
0838: /** Sets the table event for this table.
0839: * @param event the table event for this table
0840: */
0841: public void setTableEvent(PdfPTableEvent event) {
0842: if (event == null)
0843: this .tableEvent = null;
0844: else if (this .tableEvent == null)
0845: this .tableEvent = event;
0846: else if (this .tableEvent instanceof PdfPTableEventForwarder)
0847: ((PdfPTableEventForwarder) this .tableEvent)
0848: .addTableEvent(event);
0849: else {
0850: PdfPTableEventForwarder forward = new PdfPTableEventForwarder();
0851: forward.addTableEvent(this .tableEvent);
0852: forward.addTableEvent(event);
0853: this .tableEvent = forward;
0854: }
0855: }
0856:
0857: /** Gets the table event for this page.
0858: * @return the table event for this page
0859: */
0860: public PdfPTableEvent getTableEvent() {
0861: return tableEvent;
0862: }
0863:
0864: /** Gets the absolute sizes of each column width.
0865: * @return he absolute sizes of each column width
0866: */
0867: public float[] getAbsoluteWidths() {
0868: return absoluteWidths;
0869: }
0870:
0871: float[][] getEventWidths(float xPos, int firstRow, int lastRow,
0872: boolean includeHeaders) {
0873: if (includeHeaders) {
0874: firstRow = Math.max(firstRow, headerRows);
0875: lastRow = Math.max(lastRow, headerRows);
0876: }
0877: float widths[][] = new float[(includeHeaders ? headerRows : 0)
0878: + lastRow - firstRow][];
0879: if (isColspan) {
0880: int n = 0;
0881: if (includeHeaders) {
0882: for (int k = 0; k < headerRows; ++k) {
0883: PdfPRow row = (PdfPRow) rows.get(k);
0884: if (row == null)
0885: ++n;
0886: else
0887: widths[n++] = row.getEventWidth(xPos);
0888: }
0889: }
0890: for (; firstRow < lastRow; ++firstRow) {
0891: PdfPRow row = (PdfPRow) rows.get(firstRow);
0892: if (row == null)
0893: ++n;
0894: else
0895: widths[n++] = row.getEventWidth(xPos);
0896: }
0897: } else {
0898: float width[] = new float[absoluteWidths.length + 1];
0899: width[0] = xPos;
0900: for (int k = 0; k < absoluteWidths.length; ++k)
0901: width[k + 1] = width[k] + absoluteWidths[k];
0902: for (int k = 0; k < widths.length; ++k)
0903: widths[k] = width;
0904: }
0905: return widths;
0906: }
0907:
0908: /** Getter for property skipFirstHeader.
0909: * @return Value of property skipFirstHeader.
0910: */
0911: public boolean isSkipFirstHeader() {
0912: return skipFirstHeader;
0913: }
0914:
0915: /** Skips the printing of the first header. Used when printing
0916: * tables in succession belonging to the same printed table aspect.
0917: * @param skipFirstHeader New value of property skipFirstHeader.
0918: */
0919: public void setSkipFirstHeader(boolean skipFirstHeader) {
0920: this .skipFirstHeader = skipFirstHeader;
0921: }
0922:
0923: /**
0924: * Sets the run direction of the contents of the table.
0925: * @param runDirection
0926: */
0927: public void setRunDirection(int runDirection) {
0928: if (runDirection < PdfWriter.RUN_DIRECTION_DEFAULT
0929: || runDirection > PdfWriter.RUN_DIRECTION_RTL)
0930: throw new RuntimeException("Invalid run direction: "
0931: + runDirection);
0932: this .runDirection = runDirection;
0933: }
0934:
0935: /**
0936: * Returns the run direction of the contents in the table.
0937: * @return One of the following values: PdfWriter.RUN_DIRECTION_DEFAULT, PdfWriter.RUN_DIRECTION_NO_BIDI, PdfWriter.RUN_DIRECTION_LTR or PdfWriter.RUN_DIRECTION_RTL.
0938: */
0939: public int getRunDirection() {
0940: return runDirection;
0941: }
0942:
0943: /**
0944: * Getter for property lockedWidth.
0945: * @return Value of property lockedWidth.
0946: */
0947: public boolean isLockedWidth() {
0948: return this .lockedWidth;
0949: }
0950:
0951: /**
0952: * Uses the value in <CODE>setTotalWidth()</CODE> in <CODE>Document.add()</CODE>.
0953: * @param lockedWidth <CODE>true</CODE> to use the value in <CODE>setTotalWidth()</CODE> in <CODE>Document.add()</CODE>
0954: */
0955: public void setLockedWidth(boolean lockedWidth) {
0956: this .lockedWidth = lockedWidth;
0957: }
0958:
0959: /**
0960: * Gets the split value.
0961: * @return true to split; false otherwise
0962: */
0963: public boolean isSplitRows() {
0964: return this .splitRows;
0965: }
0966:
0967: /**
0968: * When set the rows that won't fit in the page will be split.
0969: * Note that it takes at least twice the memory to handle a split table row
0970: * than a normal table. <CODE>true</CODE> by default.
0971: * @param splitRows true to split; false otherwise
0972: */
0973: public void setSplitRows(boolean splitRows) {
0974: this .splitRows = splitRows;
0975: }
0976:
0977: /**
0978: * Sets the spacing before this table.
0979: *
0980: * @param spacing the new spacing
0981: */
0982:
0983: public void setSpacingBefore(float spacing) {
0984: this .spacingBefore = spacing;
0985: }
0986:
0987: /**
0988: * Sets the spacing after this table.
0989: *
0990: * @param spacing the new spacing
0991: */
0992:
0993: public void setSpacingAfter(float spacing) {
0994: this .spacingAfter = spacing;
0995: }
0996:
0997: /**
0998: * Gets the spacing before this table.
0999: *
1000: * @return the spacing
1001: */
1002:
1003: public float spacingBefore() {
1004: return spacingBefore;
1005: }
1006:
1007: /**
1008: * Gets the spacing after this table.
1009: *
1010: * @return the spacing
1011: */
1012:
1013: public float spacingAfter() {
1014: return spacingAfter;
1015: }
1016:
1017: /**
1018: * Gets the value of the last row extension.
1019: * @return true if the last row will extend; false otherwise
1020: */
1021: public boolean isExtendLastRow() {
1022: return this .extendLastRow;
1023: }
1024:
1025: /**
1026: * When set the last row will be extended to fill all the remaining space to the
1027: * bottom boundary.
1028: * @param extendLastRow true to extend the last row; false otherwise
1029: */
1030: public void setExtendLastRow(boolean extendLastRow) {
1031: this .extendLastRow = extendLastRow;
1032: }
1033:
1034: /**
1035: * Gets the header status inclusion in PdfPTableEvent.
1036: * @return true if the headers are included; false otherwise
1037: */
1038: public boolean isHeadersInEvent() {
1039: return this .headersInEvent;
1040: }
1041:
1042: /**
1043: * When set the PdfPTableEvent will include the headers.
1044: * @param headersInEvent true to include the headers; false otherwise
1045: */
1046: public void setHeadersInEvent(boolean headersInEvent) {
1047: this .headersInEvent = headersInEvent;
1048: }
1049:
1050: /**
1051: * Gets the property splitLate.
1052: * @return the property splitLate
1053: */
1054: public boolean isSplitLate() {
1055: return this .splitLate;
1056: }
1057:
1058: /**
1059: * If true the row will only split if it's the first one in an empty page.
1060: * It's true by default.
1061: *<p>
1062: * It's only meaningful if setSplitRows(true).
1063: * @param splitLate the property value
1064: */
1065: public void setSplitLate(boolean splitLate) {
1066: this .splitLate = splitLate;
1067: }
1068:
1069: /**
1070: * If true the table will be kept on one page if it fits, by forcing a
1071: * new page if it doesn't fit on the current page. The default is to
1072: * split the table over multiple pages.
1073: *
1074: * @param p_KeepTogether whether to try to keep the table on one page
1075: */
1076: public void setKeepTogether(boolean p_KeepTogether) {
1077: keepTogether = p_KeepTogether;
1078: }
1079:
1080: public boolean getKeepTogether() {
1081: return keepTogether;
1082: }
1083:
1084: /**
1085: * Gets the number of rows in the footer.
1086: * @return the number of rows in the footer
1087: */
1088: public int getFooterRows() {
1089: return this .footerRows;
1090: }
1091:
1092: /**
1093: * Sets the number of rows to be used for the footer. The number
1094: * of footer rows are subtracted from the header rows. For
1095: * example, for a table with two header rows and one footer row the
1096: * code would be:
1097: * <p>
1098: * <PRE>
1099: * table.setHeaderRows(3);
1100: * table.setFooterRows(1);
1101: * </PRE>
1102: * <p>
1103: * Row 0 and 1 will be the header rows and row 2 will be the footer row.
1104: * @param footerRows the number of rows to be used for the footer
1105: */
1106: public void setFooterRows(int footerRows) {
1107: if (footerRows < 0)
1108: footerRows = 0;
1109: this .footerRows = footerRows;
1110: }
1111:
1112: /**
1113: * Completes the current row with the default cell. An incomplete row will be dropped
1114: * but calling this method will make sure that it will be present in the table.
1115: */
1116: public void completeRow() {
1117: while (currentRowIdx > 0) {
1118: addCell(defaultCell);
1119: }
1120: }
1121: }
|