001/* 002 * $Id: PdfPTable.java 4862 2011-05-11 15:57:42Z redlab_b $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf; 045 046import java.util.ArrayList; 047import java.util.List; 048 049import com.itextpdf.text.Chunk; 050import com.itextpdf.text.DocumentException; 051import com.itextpdf.text.Element; 052import com.itextpdf.text.ElementListener; 053import com.itextpdf.text.Image; 054import com.itextpdf.text.LargeElement; 055import com.itextpdf.text.Phrase; 056import com.itextpdf.text.Rectangle; 057import com.itextpdf.text.api.Spaceable; 058import com.itextpdf.text.error_messages.MessageLocalization; 059import com.itextpdf.text.pdf.events.PdfPTableEventForwarder; 060 061/** 062 * This is a table that can be put at an absolute position but can also 063 * be added to the document as the class <CODE>Table</CODE>. 064 * <P> 065 * A PdfPTableEvent can be associated to the table to do custom drawing 066 * when the table is rendered. 067 * @author Paulo Soares 068 */ 069 070public class PdfPTable implements LargeElement, Spaceable{ 071 072 /** 073 * The index of the original <CODE>PdfcontentByte</CODE>. 074 */ 075 public static final int BASECANVAS = 0; 076 077 /** 078 * The index of the duplicate <CODE>PdfContentByte</CODE> where the background will be drawn. 079 */ 080 public static final int BACKGROUNDCANVAS = 1; 081 082 /** 083 * The index of the duplicate <CODE>PdfContentByte</CODE> where the border lines will be drawn. 084 */ 085 public static final int LINECANVAS = 2; 086 087 /** 088 * The index of the duplicate <CODE>PdfContentByte</CODE> where the text will be drawn. 089 */ 090 public static final int TEXTCANVAS = 3; 091 092 protected ArrayList<PdfPRow> rows = new ArrayList<PdfPRow>(); 093 protected float totalHeight = 0; 094 protected PdfPCell currentRow[]; 095 /** 096 * The current column index. 097 * @since 5.1.0 renamed from currentRowIdx 098 */ 099 protected int currentColIdx = 0; 100 protected PdfPCell defaultCell = new PdfPCell((Phrase)null); 101 protected float totalWidth = 0; 102 protected float relativeWidths[]; 103 protected float absoluteWidths[]; 104 protected PdfPTableEvent tableEvent; 105 106 /** 107 * Holds value of property headerRows. 108 */ 109 protected int headerRows; 110 111 /** 112 * Holds value of property widthPercentage. 113 */ 114 protected float widthPercentage = 80; 115 116 /** 117 * Holds value of property horizontalAlignment. 118 */ 119 private int horizontalAlignment = Element.ALIGN_CENTER; 120 121 /** 122 * Holds value of property skipFirstHeader. 123 */ 124 private boolean skipFirstHeader = false; 125 /** 126 * Holds value of property skipLastFooter. 127 * @since 2.1.6 128 */ 129 private boolean skipLastFooter = false; 130 131 protected boolean isColspan = false; 132 133 protected int runDirection = PdfWriter.RUN_DIRECTION_DEFAULT; 134 135 /** 136 * Holds value of property lockedWidth. 137 */ 138 private boolean lockedWidth = false; 139 140 /** 141 * Holds value of property splitRows. 142 */ 143 private boolean splitRows = true; 144 145 /** 146 * The spacing before the table. 147 */ 148 protected float spacingBefore; 149 150 /** 151 * The spacing after the table. 152 */ 153 protected float spacingAfter; 154 155 /** 156 * Holds value of property extendLastRow. 157 */ 158 private boolean[] extendLastRow = { false, false }; 159 160 /** 161 * Holds value of property headersInEvent. 162 */ 163 private boolean headersInEvent; 164 165 /** 166 * Holds value of property splitLate. 167 */ 168 private boolean splitLate = true; 169 170 /** 171 * Defines if the table should be kept 172 * on one page if possible 173 */ 174 private boolean keepTogether; 175 176 /** 177 * Indicates if the PdfPTable is complete once added to the document. 178 * 179 * @since iText 2.0.8 180 */ 181 protected boolean complete = true; 182 183 /** 184 * Holds value of property footerRows. 185 */ 186 private int footerRows; 187 188 /** 189 * Keeps track of the completeness of the current row. 190 * @since 2.1.6 191 */ 192 protected boolean rowCompleted = true; 193 194 protected PdfPTable() { 195 } 196 197 /** 198 * Constructs a <CODE>PdfPTable</CODE> with the relative column widths. 199 * 200 * @param relativeWidths the relative column widths 201 */ 202 public PdfPTable(final float relativeWidths[]) { 203 if (relativeWidths == null) 204 throw new NullPointerException(MessageLocalization.getComposedMessage("the.widths.array.in.pdfptable.constructor.can.not.be.null")); 205 if (relativeWidths.length == 0) 206 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.widths.array.in.pdfptable.constructor.can.not.have.zero.length")); 207 this.relativeWidths = new float[relativeWidths.length]; 208 System.arraycopy(relativeWidths, 0, this.relativeWidths, 0, relativeWidths.length); 209 absoluteWidths = new float[relativeWidths.length]; 210 calculateWidths(); 211 currentRow = new PdfPCell[absoluteWidths.length]; 212 keepTogether = false; 213 } 214 215 /** 216 * Constructs a <CODE>PdfPTable</CODE> with <CODE>numColumns</CODE> columns. 217 * 218 * @param numColumns the number of columns 219 */ 220 public PdfPTable(final int numColumns) { 221 if (numColumns <= 0) 222 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.number.of.columns.in.pdfptable.constructor.must.be.greater.than.zero")); 223 relativeWidths = new float[numColumns]; 224 for (int k = 0; k < numColumns; ++k) 225 relativeWidths[k] = 1; 226 absoluteWidths = new float[relativeWidths.length]; 227 calculateWidths(); 228 currentRow = new PdfPCell[absoluteWidths.length]; 229 keepTogether = false; 230 } 231 232 /** 233 * Constructs a copy of a <CODE>PdfPTable</CODE>. 234 * 235 * @param table the <CODE>PdfPTable</CODE> to be copied 236 */ 237 public PdfPTable(final PdfPTable table) { 238 copyFormat(table); 239 for (int k = 0; k < currentRow.length; ++k) { 240 if (table.currentRow[k] == null) 241 break; 242 currentRow[k] = new PdfPCell(table.currentRow[k]); 243 } 244 for (int k = 0; k < table.rows.size(); ++k) { 245 PdfPRow row = table.rows.get(k); 246 if (row != null) 247 row = new PdfPRow(row); 248 rows.add(row); 249 } 250 } 251 252 /** 253 * Makes a shallow copy of a table (format without content). 254 * 255 * @param table 256 * @return a shallow copy of the table 257 */ 258 public static PdfPTable shallowCopy(final PdfPTable table) { 259 PdfPTable nt = new PdfPTable(); 260 nt.copyFormat(table); 261 return nt; 262 } 263 264 /** 265 * Copies the format of the sourceTable without copying the content. 266 * 267 * @param sourceTable 268 * @since 2.1.6 private is now protected 269 */ 270 protected void copyFormat(final PdfPTable sourceTable) { 271 relativeWidths = new float[sourceTable.getNumberOfColumns()]; 272 absoluteWidths = new float[sourceTable.getNumberOfColumns()]; 273 System.arraycopy(sourceTable.relativeWidths, 0, relativeWidths, 0, getNumberOfColumns()); 274 System.arraycopy(sourceTable.absoluteWidths, 0, absoluteWidths, 0, getNumberOfColumns()); 275 totalWidth = sourceTable.totalWidth; 276 totalHeight = sourceTable.totalHeight; 277 currentColIdx = 0; 278 tableEvent = sourceTable.tableEvent; 279 runDirection = sourceTable.runDirection; 280 defaultCell = new PdfPCell(sourceTable.defaultCell); 281 currentRow = new PdfPCell[sourceTable.currentRow.length]; 282 isColspan = sourceTable.isColspan; 283 splitRows = sourceTable.splitRows; 284 spacingAfter = sourceTable.spacingAfter; 285 spacingBefore = sourceTable.spacingBefore; 286 headerRows = sourceTable.headerRows; 287 footerRows = sourceTable.footerRows; 288 lockedWidth = sourceTable.lockedWidth; 289 extendLastRow = sourceTable.extendLastRow; 290 headersInEvent = sourceTable.headersInEvent; 291 widthPercentage = sourceTable.widthPercentage; 292 splitLate = sourceTable.splitLate; 293 skipFirstHeader = sourceTable.skipFirstHeader; 294 skipLastFooter = sourceTable.skipLastFooter; 295 horizontalAlignment = sourceTable.horizontalAlignment; 296 keepTogether = sourceTable.keepTogether; 297 complete = sourceTable.complete; 298 } 299 300 /** 301 * Sets the relative widths of the table. 302 * 303 * @param relativeWidths the relative widths of the table. 304 * @throws DocumentException if the number of widths is different than the number 305 * of columns 306 */ 307 public void setWidths(final float relativeWidths[]) throws DocumentException { 308 if (relativeWidths.length != getNumberOfColumns()) 309 throw new DocumentException(MessageLocalization.getComposedMessage("wrong.number.of.columns")); 310 this.relativeWidths = new float[relativeWidths.length]; 311 System.arraycopy(relativeWidths, 0, this.relativeWidths, 0, relativeWidths.length); 312 absoluteWidths = new float[relativeWidths.length]; 313 totalHeight = 0; 314 calculateWidths(); 315 calculateHeights(); 316 } 317 318 /** 319 * Sets the relative widths of the table. 320 * 321 * @param relativeWidths the relative widths of the table. 322 * @throws DocumentException if the number of widths is different than the number 323 * of columns 324 */ 325 public void setWidths(final int relativeWidths[]) throws DocumentException { 326 float tb[] = new float[relativeWidths.length]; 327 for (int k = 0; k < relativeWidths.length; ++k) 328 tb[k] = relativeWidths[k]; 329 setWidths(tb); 330 } 331 332 /** 333 * @since 2.1.6 private is now protected 334 */ 335 protected void calculateWidths() { 336 if (totalWidth <= 0) 337 return; 338 float total = 0; 339 int numCols = getNumberOfColumns(); 340 for (int k = 0; k < numCols; ++k) 341 total += relativeWidths[k]; 342 for (int k = 0; k < numCols; ++k) 343 absoluteWidths[k] = totalWidth * relativeWidths[k] / total; 344 } 345 346 /** 347 * Sets the full width of the table. 348 * 349 * @param totalWidth the full width of the table. 350 */ 351 public void setTotalWidth(final float totalWidth) { 352 if (this.totalWidth == totalWidth) 353 return; 354 this.totalWidth = totalWidth; 355 totalHeight = 0; 356 calculateWidths(); 357 calculateHeights(); 358 } 359 360 /** 361 * Sets the full width of the table from the absolute column width. 362 * 363 * @param columnWidth the absolute width of each column 364 * @throws DocumentException if the number of widths is different than the number 365 * of columns 366 */ 367 public void setTotalWidth(final float columnWidth[]) throws DocumentException { 368 if (columnWidth.length != getNumberOfColumns()) 369 throw new DocumentException(MessageLocalization.getComposedMessage("wrong.number.of.columns")); 370 totalWidth = 0; 371 for (int k = 0; k < columnWidth.length; ++k) 372 totalWidth += columnWidth[k]; 373 setWidths(columnWidth); 374 } 375 376 /** 377 * Sets the percentage width of the table from the absolute column width. 378 * 379 * @param columnWidth the absolute width of each column 380 * @param pageSize the page size 381 * @throws DocumentException 382 */ 383 public void setWidthPercentage(final float columnWidth[], final Rectangle pageSize) throws DocumentException { 384 if (columnWidth.length != getNumberOfColumns()) 385 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("wrong.number.of.columns")); 386 float totalWidth = 0; 387 for (int k = 0; k < columnWidth.length; ++k) 388 totalWidth += columnWidth[k]; 389 widthPercentage = totalWidth / (pageSize.getRight() - pageSize.getLeft()) * 100f; 390 setWidths(columnWidth); 391 } 392 393 /** 394 * Gets the full width of the table. 395 * 396 * @return the full width of the table 397 */ 398 public float getTotalWidth() { 399 return totalWidth; 400 } 401 402 /** 403 * Calculates the heights of the table. 404 * 405 * @return the total height of the table. Note that it will be 0 if you didn't 406 * specify the width of the table with setTotalWidth(). 407 * and made it public 408 */ 409 public float calculateHeights() { 410 if (totalWidth <= 0) 411 return 0; 412 totalHeight = 0; 413 for (int k = 0; k < rows.size(); ++k) { 414 totalHeight += getRowHeight(k, true); 415 } 416 return totalHeight; 417 } 418 419 /** 420 * Changes the number of columns. Any existing rows will be deleted. 421 * @param newColCount the new number of columns 422 * @since 5.0.2 423 */ 424 public void resetColumnCount(final int newColCount) { 425 if (newColCount <= 0) 426 throw new IllegalArgumentException(MessageLocalization.getComposedMessage("the.number.of.columns.in.pdfptable.constructor.must.be.greater.than.zero")); 427 relativeWidths = new float[newColCount]; 428 for (int k = 0; k < newColCount; ++k) 429 relativeWidths[k] = 1; 430 absoluteWidths = new float[relativeWidths.length]; 431 calculateWidths(); 432 currentRow = new PdfPCell[absoluteWidths.length]; 433 totalHeight = 0; 434 } 435 436 /** 437 * Gets the default <CODE>PdfPCell</CODE> that will be used as 438 * reference for all the <CODE>addCell</CODE> methods except 439 * <CODE>addCell(PdfPCell)</CODE>. 440 * 441 * @return default <CODE>PdfPCell</CODE> 442 */ 443 public PdfPCell getDefaultCell() { 444 return defaultCell; 445 } 446 447 /** 448 * Adds a cell element. 449 * 450 * @param cell the cell element 451 */ 452 public void addCell(final PdfPCell cell) { 453 rowCompleted = false; 454 PdfPCell ncell = new PdfPCell(cell); 455 456 int colspan = ncell.getColspan(); 457 colspan = Math.max(colspan, 1); 458 colspan = Math.min(colspan, currentRow.length - currentColIdx); 459 ncell.setColspan(colspan); 460 461 if (colspan != 1) 462 isColspan = true; 463 int rdir = ncell.getRunDirection(); 464 if (rdir == PdfWriter.RUN_DIRECTION_DEFAULT) 465 ncell.setRunDirection(runDirection); 466 467 skipColsWithRowspanAbove(); 468 469 boolean cellAdded = false; 470 if (currentColIdx < currentRow.length) { 471 currentRow[currentColIdx] = ncell; 472 currentColIdx += colspan; 473 cellAdded = true; 474 } 475 476 skipColsWithRowspanAbove(); 477 478 while (currentColIdx >= currentRow.length) { 479 int numCols = getNumberOfColumns(); 480 if (runDirection == PdfWriter.RUN_DIRECTION_RTL) { 481 PdfPCell rtlRow[] = new PdfPCell[numCols]; 482 int rev = currentRow.length; 483 for (int k = 0; k < currentRow.length; ++k) { 484 PdfPCell rcell = currentRow[k]; 485 int cspan = rcell.getColspan(); 486 rev -= cspan; 487 rtlRow[rev] = rcell; 488 k += cspan - 1; 489 } 490 currentRow = rtlRow; 491 } 492 PdfPRow row = new PdfPRow(currentRow); 493 if (totalWidth > 0) { 494 row.setWidths(absoluteWidths); 495 totalHeight += row.getMaxHeights(); 496 } 497 rows.add(row); 498 currentRow = new PdfPCell[numCols]; 499 currentColIdx = 0; 500 skipColsWithRowspanAbove(); 501 rowCompleted = true; 502 } 503 504 if (!cellAdded) { 505 currentRow[currentColIdx] = ncell; 506 currentColIdx += colspan; 507 } 508 } 509 510 /** 511 * When updating the row index, cells with rowspan should be taken into account. 512 * This is what happens in this method. 513 * @since 2.1.6 514 */ 515 private void skipColsWithRowspanAbove() { 516 int direction = 1; 517 if (runDirection == PdfWriter.RUN_DIRECTION_RTL) 518 direction = -1; 519 while (rowSpanAbove(rows.size(), currentColIdx)) 520 currentColIdx += direction; 521 } 522 523 /** 524 * Added by timmo3. This will return the correct cell taking it's cellspan into account 525 * @param row the row index 526 * @param col the column index 527 * @return PdfPCell at the given row and position or null otherwise 528 */ 529 PdfPCell cellAt(final int row, final int col) { 530 PdfPCell[] cells = rows.get(row).getCells(); 531 for (int i = 0; i < cells.length; i++) { 532 if (cells[i] != null) { 533 if (col >= i && col < (i + cells[i].getColspan())) { 534 return cells[i]; 535 } 536 } 537 } 538 return null; 539 } 540 541 /** 542 * Checks if there are rows above belonging to a rowspan. 543 * @param currRow the current row to check 544 * @param currCol the current column to check 545 * @return true if there's a cell above that belongs to a rowspan 546 * @since 2.1.6 547 */ 548 boolean rowSpanAbove(final int currRow, final int currCol) { 549 if (currCol >= getNumberOfColumns() 550 || currCol < 0 551 || currRow < 1) 552 return false; 553 int row = currRow - 1; 554 PdfPRow aboveRow = rows.get(row); 555 if (aboveRow == null) 556 return false; 557 PdfPCell aboveCell = cellAt(row, currCol); 558 while (aboveCell == null && row > 0) { 559 aboveRow = rows.get(--row); 560 if (aboveRow == null) 561 return false; 562 aboveCell = cellAt(row, currCol); 563 } 564 565 int distance = currRow - row; 566 567 if (aboveCell.getRowspan() == 1 && distance > 1) { 568 int col = currCol - 1; 569 aboveRow = rows.get(row + 1); 570 distance--; 571 aboveCell = aboveRow.getCells()[col]; 572 while (aboveCell == null && col > 0) 573 aboveCell = aboveRow.getCells()[--col]; 574 } 575 576 return aboveCell != null && aboveCell.getRowspan() > distance; 577 } 578 579 580 /** 581 * Adds a cell element. 582 * 583 * @param text the text for the cell 584 */ 585 public void addCell(final String text) { 586 addCell(new Phrase(text)); 587 } 588 589 /** 590 * Adds a nested table. 591 * 592 * @param table the table to be added to the cell 593 */ 594 public void addCell(final PdfPTable table) { 595 defaultCell.setTable(table); 596 addCell(defaultCell); 597 defaultCell.setTable(null); 598 } 599 600 /** 601 * Adds an Image as Cell. 602 * 603 * @param image the <CODE>Image</CODE> to add to the table. 604 * This image will fit in the cell 605 */ 606 public void addCell(final Image image) { 607 defaultCell.setImage(image); 608 addCell(defaultCell); 609 defaultCell.setImage(null); 610 } 611 612 /** 613 * Adds a cell element. 614 * 615 * @param phrase the <CODE>Phrase</CODE> to be added to the cell 616 */ 617 public void addCell(final Phrase phrase) { 618 defaultCell.setPhrase(phrase); 619 addCell(defaultCell); 620 defaultCell.setPhrase(null); 621 } 622 623 /** 624 * Writes the selected rows to the document. 625 * <CODE>canvases</CODE> is obtained from <CODE>beginWritingRows()</CODE>. 626 * 627 * @param rowStart the first row to be written, zero index 628 * @param rowEnd the last row to be written + 1. If it is -1 all the 629 * rows to the end are written 630 * @param xPos the x write coordinate 631 * @param yPos the y write coordinate 632 * @param canvases an array of 4 <CODE>PdfContentByte</CODE> obtained from 633 * <CODE>beginWrittingRows()</CODE> 634 * @return the y coordinate position of the bottom of the last row 635 * @see #beginWritingRows(com.itextpdf.text.pdf.PdfContentByte) 636 */ 637 public float writeSelectedRows(final int rowStart, final int rowEnd, final float xPos, final float yPos, final PdfContentByte[] canvases) { 638 return writeSelectedRows(0, -1, rowStart, rowEnd, xPos, yPos, canvases); 639 } 640 641 /** 642 * Writes the selected rows and columns to the document. 643 * This method does not clip the columns; this is only important 644 * if there are columns with colspan at boundaries. 645 * <CODE>canvases</CODE> is obtained from <CODE>beginWritingRows()</CODE>. 646 * The table event is only fired for complete rows. 647 * 648 * @param colStart the first column to be written, zero index 649 * @param colEnd the last column to be written + 1. If it is -1 all the 650 * columns to the end are written 651 * @param rowStart the first row to be written, zero index 652 * @param rowEnd the last row to be written + 1. If it is -1 all the 653 * rows to the end are written 654 * @param xPos the x write coordinate 655 * @param yPos the y write coordinate 656 * @param canvases an array of 4 <CODE>PdfContentByte</CODE> obtained from 657 * <CODE>beginWritingRows()</CODE> 658 * @return the y coordinate position of the bottom of the last row 659 * @see #beginWritingRows(com.itextpdf.text.pdf.PdfContentByte) 660 */ 661 public float writeSelectedRows(final int colStart, final int colEnd, final int rowStart, final int rowEnd, final float xPos, final float yPos, final PdfContentByte[] canvases) { 662 return writeSelectedRows(colStart, colEnd, rowStart, rowEnd, xPos, yPos, canvases, true); 663 } 664 665 /** 666 * Writes the selected rows and columns to the document. 667 * This method does not clip the columns; this is only important 668 * if there are columns with colspan at boundaries. 669 * <CODE>canvases</CODE> is obtained from <CODE>beginWritingRows()</CODE>. 670 * The table event is only fired for complete rows. 671 * 672 * @param colStart the first column to be written, zero index 673 * @param colEnd the last column to be written + 1. If it is -1 all the 674 * columns to the end are written 675 * @param rowStart the first row to be written, zero index 676 * @param rowEnd the last row to be written + 1. If it is -1 all the 677 * rows to the end are written 678 * @param xPos the x write coordinate 679 * @param yPos the y write coordinate 680 * @param canvases an array of 4 <CODE>PdfContentByte</CODE> obtained from 681 * <CODE>beginWritingRows()</CODE> 682 * @param reusable if set to false, the content in the cells is "consumed"; 683 * if true, you can reuse the cells, the row, the parent table as many times you want. 684 * @return the y coordinate position of the bottom of the last row 685 * @see #beginWritingRows(com.itextpdf.text.pdf.PdfContentByte) 686 * @since 5.1.0 added the reusable parameter 687 */ 688 public float writeSelectedRows(int colStart, int colEnd, int rowStart, int rowEnd, final float xPos, float yPos, final PdfContentByte[] canvases, final boolean reusable) { 689 if (totalWidth <= 0) 690 throw new RuntimeException(MessageLocalization.getComposedMessage("the.table.width.must.be.greater.than.zero")); 691 692 int totalRows = rows.size(); 693 if (rowStart < 0) 694 rowStart = 0; 695 if (rowEnd < 0) 696 rowEnd = totalRows; 697 else 698 rowEnd = Math.min(rowEnd, totalRows); 699 if (rowStart >= rowEnd) 700 return yPos; 701 702 int totalCols = getNumberOfColumns(); 703 if (colStart < 0) 704 colStart = 0; 705 else 706 colStart = Math.min(colStart, totalCols); 707 if (colEnd < 0) 708 colEnd = totalCols; 709 else 710 colEnd = Math.min(colEnd, totalCols); 711 712 float yPosStart = yPos; 713 for (int k = rowStart; k < rowEnd; ++k) { 714 PdfPRow row = rows.get(k); 715 if (row != null) { 716 row.writeCells(colStart, colEnd, xPos, yPos, canvases, reusable); 717 yPos -= row.getMaxHeights(); 718 } 719 } 720 721 if (tableEvent != null && colStart == 0 && colEnd == totalCols) { 722 float heights[] = new float[rowEnd - rowStart + 1]; 723 heights[0] = yPosStart; 724 for (int k = rowStart; k < rowEnd; ++k) { 725 PdfPRow row = rows.get(k); 726 float hr = 0; 727 if (row != null) 728 hr = row.getMaxHeights(); 729 heights[k - rowStart + 1] = heights[k - rowStart] - hr; 730 } 731 tableEvent.tableLayout(this, getEventWidths(xPos, rowStart, rowEnd, headersInEvent), heights, headersInEvent ? headerRows : 0, rowStart, canvases); 732 } 733 734 return yPos; 735 } 736 737 /** 738 * Writes the selected rows to the document. 739 * 740 * @param rowStart the first row to be written, zero index 741 * @param rowEnd the last row to be written + 1. If it is -1 all the 742 * rows to the end are written 743 * @param xPos the x write coordinate 744 * @param yPos the y write coordinate 745 * @param canvas the <CODE>PdfContentByte</CODE> where the rows will 746 * be written to 747 * @return the y coordinate position of the bottom of the last row 748 */ 749 public float writeSelectedRows(final int rowStart, final int rowEnd, final float xPos, final float yPos, final PdfContentByte canvas) { 750 return writeSelectedRows(0, -1, rowStart, rowEnd, xPos, yPos, canvas); 751 } 752 753 /** 754 * Writes the selected rows and columns to the document. 755 * This method clips the columns; this is only important 756 * if there are columns with colspan at boundaries. 757 * The table event is only fired for complete rows. 758 * 759 * @param colStart the first column to be written, zero index 760 * @param colEnd the last column to be written + 1. If it is -1 all the 761 * columns to the end are written 762 * @param rowStart the first row to be written, zero index 763 * @param rowEnd the last row to be written + 1. If it is -1 all the 764 * rows to the end are written 765 * @param xPos the x write coordinate 766 * @param yPos the y write coordinate 767 * @param canvas the <CODE>PdfContentByte</CODE> where the rows will 768 * be written to 769 * @return the y coordinate position of the bottom of the last row 770 */ 771 public float writeSelectedRows(final int colStart, final int colEnd, final int rowStart, final int rowEnd, final float xPos, final float yPos, final PdfContentByte canvas) { 772 return writeSelectedRows(colStart, colEnd, rowStart, rowEnd, xPos, yPos, canvas, true); 773 } 774 775 776 /** 777 * Writes the selected rows and columns to the document. 778 * This method clips the columns; this is only important 779 * if there are columns with colspan at boundaries. 780 * The table event is only fired for complete rows. 781 * 782 * @param colStart the first column to be written, zero index 783 * @param colEnd the last column to be written + 1. If it is -1 all the 784 * columns to the end are written 785 * @param rowStart the first row to be written, zero index 786 * @param rowEnd the last row to be written + 1. If it is -1 all the 787 * rows to the end are written 788 * @param xPos the x write coordinate 789 * @param yPos the y write coordinate 790 * @param canvas the <CODE>PdfContentByte</CODE> where the rows will 791 * be written to 792 * @param reusable if set to false, the content in the cells is "consumed"; 793 * if true, you can reuse the cells, the row, the parent table as many times you want. 794 * @return the y coordinate position of the bottom of the last row 795 * @since 5.1.0 added the reusable parameter 796 */ 797 public float writeSelectedRows(int colStart, int colEnd, final int rowStart, final int rowEnd, final float xPos, final float yPos, final PdfContentByte canvas, final boolean reusable) { 798 int totalCols = getNumberOfColumns(); 799 if (colStart < 0) 800 colStart = 0; 801 else 802 colStart = Math.min(colStart, totalCols); 803 804 if (colEnd < 0) 805 colEnd = totalCols; 806 else 807 colEnd = Math.min(colEnd, totalCols); 808 809 boolean clip = colStart != 0 || colEnd != totalCols; 810 811 if (clip) { 812 float w = 0; 813 for (int k = colStart; k < colEnd; ++k) 814 w += absoluteWidths[k]; 815 canvas.saveState(); 816 float lx = colStart == 0 ? 10000 : 0; 817 float rx = colEnd == totalCols ? 10000 : 0; 818 canvas.rectangle(xPos - lx, -10000, w + lx + rx, PdfPRow.RIGHT_LIMIT); 819 canvas.clip(); 820 canvas.newPath(); 821 } 822 823 PdfContentByte[] canvases = beginWritingRows(canvas); 824 float y = writeSelectedRows(colStart, colEnd, rowStart, rowEnd, xPos, yPos, canvases, reusable); 825 endWritingRows(canvases); 826 827 if (clip) 828 canvas.restoreState(); 829 830 return y; 831 } 832 833 /** 834 * Gets and initializes the 4 layers where the table is written to. The text or graphics are added to 835 * one of the 4 <CODE>PdfContentByte</CODE> returned with the following order:<p> 836 * <ul> 837 * <li><CODE>PdfPtable.BASECANVAS</CODE> - the original <CODE>PdfContentByte</CODE>. Anything placed here 838 * will be under the table. 839 * <li><CODE>PdfPtable.BACKGROUNDCANVAS</CODE> - the layer where the background goes to. 840 * <li><CODE>PdfPtable.LINECANVAS</CODE> - the layer where the lines go to. 841 * <li><CODE>PdfPtable.TEXTCANVAS</CODE> - the layer where the text go to. Anything placed here 842 * will be over the table. 843 * </ul><p> 844 * The layers are placed in sequence on top of each other. 845 * 846 * @param canvas the <CODE>PdfContentByte</CODE> where the rows will 847 * be written to 848 * @return an array of 4 <CODE>PdfContentByte</CODE> 849 * @see #writeSelectedRows(int, int, float, float, PdfContentByte[]) 850 */ 851 public static PdfContentByte[] beginWritingRows(final PdfContentByte canvas) { 852 return new PdfContentByte[]{ 853 canvas, 854 canvas.getDuplicate(), 855 canvas.getDuplicate(), 856 canvas.getDuplicate(), 857 }; 858 } 859 860 /** 861 * Finishes writing the table. 862 * 863 * @param canvases the array returned by <CODE>beginWritingRows()</CODE> 864 */ 865 public static void endWritingRows(final PdfContentByte[] canvases) { 866 PdfContentByte canvas = canvases[BASECANVAS]; 867 canvas.saveState(); 868 canvas.add(canvases[BACKGROUNDCANVAS]); 869 canvas.restoreState(); 870 canvas.saveState(); 871 canvas.setLineCap(2); 872 canvas.resetRGBColorStroke(); 873 canvas.add(canvases[LINECANVAS]); 874 canvas.restoreState(); 875 canvas.add(canvases[TEXTCANVAS]); 876 } 877 878 /** 879 * Gets the number of rows in this table. 880 * 881 * @return the number of rows in this table 882 */ 883 public int size() { 884 return rows.size(); 885 } 886 887 /** 888 * Gets the total height of the table. 889 * 890 * @return the total height of the table 891 */ 892 public float getTotalHeight() { 893 return totalHeight; 894 } 895 896 /** 897 * Gets the height of a particular row. 898 * 899 * @param idx the row index (starts at 0) 900 * @return the height of a particular row 901 */ 902 public float getRowHeight(final int idx) { 903 return getRowHeight(idx, false); 904 } 905 /** 906 * Gets the height of a particular row. 907 * 908 * @param idx the row index (starts at 0) 909 * @param firsttime is this the first time the row heigh is calculated? 910 * @return the height of a particular row 911 * @since 5.0.0 912 */ 913 protected float getRowHeight(final int idx, final boolean firsttime) { 914 if (totalWidth <= 0 || idx < 0 || idx >= rows.size()) 915 return 0; 916 PdfPRow row = rows.get(idx); 917 if (row == null) 918 return 0; 919 if (firsttime) 920 row.setWidths(absoluteWidths); 921 float height = row.getMaxHeights(); 922 PdfPCell cell; 923 PdfPRow tmprow; 924 for (int i = 0; i < relativeWidths.length; i++) { 925 if(!rowSpanAbove(idx, i)) 926 continue; 927 int rs = 1; 928 while (rowSpanAbove(idx - rs, i)) { 929 rs++; 930 } 931 tmprow = rows.get(idx - rs); 932 cell = tmprow.getCells()[i]; 933 float tmp = 0; 934 if (cell != null && cell.getRowspan() == rs + 1) { 935 tmp = cell.getMaxHeight(); 936 while (rs > 0) { 937 tmp -= getRowHeight(idx - rs); 938 rs--; 939 } 940 } 941 if (tmp > height) 942 height = tmp; 943 } 944 row.setMaxHeights(height); 945 return height; 946 } 947 948 /** 949 * Gets the maximum height of a cell in a particular row (will only be different 950 * from getRowHeight is one of the cells in the row has a rowspan > 1). 951 * 952 * @param rowIndex the row index 953 * @param cellIndex the cell index 954 * @return the height of a particular row including rowspan 955 * @since 2.1.6 956 */ 957 public float getRowspanHeight(final int rowIndex, final int cellIndex) { 958 if (totalWidth <= 0 || rowIndex < 0 || rowIndex >= rows.size()) 959 return 0; 960 PdfPRow row = rows.get(rowIndex); 961 if (row == null || cellIndex >= row.getCells().length) 962 return 0; 963 PdfPCell cell = row.getCells()[cellIndex]; 964 if (cell == null) 965 return 0; 966 float rowspanHeight = 0; 967 for (int j = 0; j < cell.getRowspan(); j++) { 968 rowspanHeight += getRowHeight(rowIndex + j); 969 } 970 return rowspanHeight; 971 } 972 973 /** 974 * Checks if a cell in a row has a rowspan greater than 1. 975 * @since 5.1.0 976 */ 977 public boolean hasRowspan(final int rowIdx) { 978 if (rowIdx < rows.size() && getRow(rowIdx).hasRowspan()) { 979 return true; 980 } 981 for (int i = 0; i < getNumberOfColumns(); i++) { 982 if (rowSpanAbove(rowIdx - 1, i)) 983 return true; 984 } 985 return false; 986 } 987 988 /** 989 * Makes sure the footers value is lower than the headers value. 990 * @since 5.0.1 991 */ 992 public void normalizeHeadersFooters() { 993 if (footerRows > headerRows) 994 footerRows = headerRows; 995 } 996 997 /** 998 * Gets the height of the rows that constitute the header as defined by 999 * <CODE>setHeaderRows()</CODE>. 1000 * 1001 * @return the height of the rows that constitute the header and footer 1002 */ 1003 public float getHeaderHeight() { 1004 float total = 0; 1005 int size = Math.min(rows.size(), headerRows); 1006 for (int k = 0; k < size; ++k) { 1007 PdfPRow row = rows.get(k); 1008 if (row != null) 1009 total += row.getMaxHeights(); 1010 } 1011 return total; 1012 } 1013 1014 /** 1015 * Gets the height of the rows that constitute the footer as defined by 1016 * <CODE>setFooterRows()</CODE>. 1017 * 1018 * @return the height of the rows that constitute the footer 1019 * @since 2.1.1 1020 */ 1021 public float getFooterHeight() { 1022 float total = 0; 1023 int start = Math.max(0, headerRows - footerRows); 1024 int size = Math.min(rows.size(), headerRows); 1025 for (int k = start; k < size; ++k) { 1026 PdfPRow row = rows.get(k); 1027 if (row != null) 1028 total += row.getMaxHeights(); 1029 } 1030 return total; 1031 } 1032 1033 /** 1034 * Deletes a row from the table. 1035 * 1036 * @param rowNumber the row to be deleted 1037 * @return <CODE>true</CODE> if the row was deleted 1038 */ 1039 public boolean deleteRow(final int rowNumber) { 1040 if (rowNumber < 0 || rowNumber >= rows.size()) 1041 return false; 1042 if (totalWidth > 0) { 1043 PdfPRow row = rows.get(rowNumber); 1044 if (row != null) 1045 totalHeight -= row.getMaxHeights(); 1046 } 1047 rows.remove(rowNumber); 1048 if (rowNumber < headerRows) { 1049 --headerRows; 1050 if (rowNumber >= headerRows - footerRows) 1051 --footerRows; 1052 } 1053 return true; 1054 } 1055 1056 /** 1057 * Deletes the last row in the table. 1058 * 1059 * @return <CODE>true</CODE> if the last row was deleted 1060 */ 1061 public boolean deleteLastRow() { 1062 return deleteRow(rows.size() - 1); 1063 } 1064 1065 /** 1066 * Removes all of the rows except headers 1067 */ 1068 public void deleteBodyRows() { 1069 ArrayList<PdfPRow> rows2 = new ArrayList<PdfPRow>(); 1070 for (int k = 0; k < headerRows; ++k) 1071 rows2.add(rows.get(k)); 1072 rows = rows2; 1073 totalHeight = 0; 1074 if (totalWidth > 0) 1075 totalHeight = getHeaderHeight(); 1076 } 1077 1078 /** 1079 * Returns the number of columns. 1080 * 1081 * @return the number of columns. 1082 * @since 2.1.1 1083 */ 1084 public int getNumberOfColumns() { 1085 return relativeWidths.length; 1086 } 1087 1088 /** 1089 * Gets the number of the rows that constitute the header. 1090 * 1091 * @return the number of the rows that constitute the header 1092 */ 1093 public int getHeaderRows() { 1094 return headerRows; 1095 } 1096 1097 /** 1098 * Sets the number of the top rows that constitute the header. 1099 * This header has only meaning if the table is added to <CODE>Document</CODE> 1100 * and the table crosses pages. 1101 * 1102 * @param headerRows the number of the top rows that constitute the header 1103 */ 1104 public void setHeaderRows(int headerRows) { 1105 if (headerRows < 0) 1106 headerRows = 0; 1107 this.headerRows = headerRows; 1108 } 1109 1110 /** 1111 * Gets all the chunks in this element. 1112 * 1113 * @return an <CODE>ArrayList</CODE> 1114 */ 1115 public List<Chunk> getChunks() { 1116 return new ArrayList<Chunk>(); 1117 } 1118 1119 /** 1120 * Gets the type of the text element. 1121 * 1122 * @return a type 1123 */ 1124 public int type() { 1125 return Element.PTABLE; 1126 } 1127 1128 /** 1129 * @see com.itextpdf.text.Element#isContent() 1130 * @since iText 2.0.8 1131 */ 1132 public boolean isContent() { 1133 return true; 1134 } 1135 1136 /** 1137 * @see com.itextpdf.text.Element#isNestable() 1138 * @since iText 2.0.8 1139 */ 1140 public boolean isNestable() { 1141 return true; 1142 } 1143 1144 /** 1145 * Processes the element by adding it (or the different parts) to an 1146 * <CODE>ElementListener</CODE>. 1147 * 1148 * @param listener an <CODE>ElementListener</CODE> 1149 * @return <CODE>true</CODE> if the element was processed successfully 1150 */ 1151 public boolean process(final ElementListener listener) { 1152 try { 1153 return listener.add(this); 1154 } 1155 catch(DocumentException de) { 1156 return false; 1157 } 1158 } 1159 1160 /** 1161 * Gets the width percentage that the table will occupy in the page. 1162 * 1163 * @return the width percentage that the table will occupy in the page 1164 */ 1165 public float getWidthPercentage() { 1166 return widthPercentage; 1167 } 1168 1169 /** 1170 * Sets the width percentage that the table will occupy in the page. 1171 * 1172 * @param widthPercentage the width percentage that the table will occupy in the page 1173 */ 1174 public void setWidthPercentage(final float widthPercentage) { 1175 this.widthPercentage = widthPercentage; 1176 } 1177 1178 /** 1179 * Gets the horizontal alignment of the table relative to the page. 1180 * 1181 * @return the horizontal alignment of the table relative to the page 1182 */ 1183 public int getHorizontalAlignment() { 1184 return horizontalAlignment; 1185 } 1186 1187 /** 1188 * Sets the horizontal alignment of the table relative to the page. 1189 * It only has meaning if the width percentage is less than 100%. 1190 * 1191 * @param horizontalAlignment the horizontal alignment of the table 1192 * relative to the page 1193 */ 1194 public void setHorizontalAlignment(final int horizontalAlignment) { 1195 this.horizontalAlignment = horizontalAlignment; 1196 } 1197 1198 /** 1199 * Gets a row with a given index. 1200 * 1201 * @param idx 1202 * @return the row at position idx 1203 */ 1204 public PdfPRow getRow(final int idx) { 1205 return rows.get(idx); 1206 } 1207 1208 /** 1209 * Gets an arraylist with all the rows in the table. 1210 * 1211 * @return an arraylist 1212 */ 1213 public ArrayList<PdfPRow> getRows() { 1214 return rows; 1215 } 1216 1217 /** 1218 * Gets an arraylist with a selection of rows. 1219 * @param start the first row in the selection 1220 * @param end the first row that isn't part of the selection 1221 * @return a selection of rows 1222 * @since 2.1.6 1223 */ 1224 public ArrayList<PdfPRow> getRows(final int start, final int end) { 1225 ArrayList<PdfPRow> list = new ArrayList<PdfPRow>(); 1226 if (start < 0 || end > size()) { 1227 return list; 1228 } 1229 for (int i = start; i < end; i++) { 1230 list.add(adjustCellsInRow(i, end)); 1231 } 1232 return list; 1233 } 1234 1235 /** 1236 * Calculates the extra height needed in a row because of rowspans. 1237 * @param start the index of the start row (the one to adjust) 1238 * @param end the index of the end row on the page 1239 * @since 2.1.6 1240 */ 1241 protected PdfPRow adjustCellsInRow(final int start, final int end) { 1242 PdfPRow row = new PdfPRow(getRow(start)); 1243 PdfPCell cell; 1244 PdfPCell[] cells = row.getCells(); 1245 for (int i = 0; i < cells.length; i++) { 1246 cell = cells[i]; 1247 if (cell == null || cell.getRowspan() == 1) 1248 continue; 1249 int stop = Math.min(end, start + cell.getRowspan()); 1250 float extra = 0; 1251 for (int k = start + 1; k < stop; k++) { 1252 extra += getRow(k).getMaxHeights(); 1253 } 1254 row.setExtraHeight(i, extra); 1255 } 1256 return row; 1257 } 1258 1259 /** Sets the table event for this table. 1260 * @param event the table event for this table 1261 */ 1262 public void setTableEvent(final PdfPTableEvent event) { 1263 if (event == null) 1264 this.tableEvent = null; 1265 else if (this.tableEvent == null) 1266 this.tableEvent = event; 1267 else if (this.tableEvent instanceof PdfPTableEventForwarder) 1268 ((PdfPTableEventForwarder)this.tableEvent).addTableEvent(event); 1269 else { 1270 PdfPTableEventForwarder forward = new PdfPTableEventForwarder(); 1271 forward.addTableEvent(this.tableEvent); 1272 forward.addTableEvent(event); 1273 this.tableEvent = forward; 1274 } 1275 } 1276 1277 /** 1278 * Gets the table event for this page. 1279 * 1280 * @return the table event for this page 1281 */ 1282 public PdfPTableEvent getTableEvent() { 1283 return tableEvent; 1284 } 1285 1286 /** 1287 * Gets the absolute sizes of each column width. 1288 * 1289 * @return he absolute sizes of each column width 1290 */ 1291 public float[] getAbsoluteWidths() { 1292 return absoluteWidths; 1293 } 1294 1295 float [][] getEventWidths(final float xPos, int firstRow, int lastRow, final boolean includeHeaders) { 1296 if (includeHeaders) { 1297 firstRow = Math.max(firstRow, headerRows); 1298 lastRow = Math.max(lastRow, headerRows); 1299 } 1300 float widths[][] = new float[(includeHeaders ? headerRows : 0) + lastRow - firstRow][]; 1301 if (isColspan) { 1302 int n = 0; 1303 if (includeHeaders) { 1304 for (int k = 0; k < headerRows; ++k) { 1305 PdfPRow row = rows.get(k); 1306 if (row == null) 1307 ++n; 1308 else 1309 widths[n++] = row.getEventWidth(xPos, absoluteWidths); 1310 } 1311 } 1312 for (; firstRow < lastRow; ++firstRow) { 1313 PdfPRow row = rows.get(firstRow); 1314 if (row == null) 1315 ++n; 1316 else 1317 widths[n++] = row.getEventWidth(xPos, absoluteWidths); 1318 } 1319 } 1320 else { 1321 int numCols = getNumberOfColumns(); 1322 float width[] = new float[numCols + 1]; 1323 width[0] = xPos; 1324 for (int k = 0; k < numCols; ++k) 1325 width[k + 1] = width[k] + absoluteWidths[k]; 1326 for (int k = 0; k < widths.length; ++k) 1327 widths[k] = width; 1328 } 1329 return widths; 1330 } 1331 1332 1333 /** 1334 * Tells you if the first header needs to be skipped 1335 * (for instance if the header says "continued from the previous page"). 1336 * 1337 * @return Value of property skipFirstHeader. 1338 */ 1339 public boolean isSkipFirstHeader() { 1340 return skipFirstHeader; 1341 } 1342 1343 1344 /** 1345 * Tells you if the last footer needs to be skipped 1346 * (for instance if the footer says "continued on the next page") 1347 * 1348 * @return Value of property skipLastFooter. 1349 * @since 2.1.6 1350 */ 1351 public boolean isSkipLastFooter() { 1352 return skipLastFooter; 1353 } 1354 1355 /** 1356 * Skips the printing of the first header. Used when printing 1357 * tables in succession belonging to the same printed table aspect. 1358 * 1359 * @param skipFirstHeader New value of property skipFirstHeader. 1360 */ 1361 public void setSkipFirstHeader(final boolean skipFirstHeader) { 1362 this.skipFirstHeader = skipFirstHeader; 1363 } 1364 1365 /** 1366 * Skips the printing of the last footer. Used when printing 1367 * tables in succession belonging to the same printed table aspect. 1368 * 1369 * @param skipLastFooter New value of property skipLastFooter. 1370 * @since 2.1.6 1371 */ 1372 public void setSkipLastFooter(final boolean skipLastFooter) { 1373 this.skipLastFooter = skipLastFooter; 1374 } 1375 1376 /** 1377 * Sets the run direction of the contents of the table. 1378 * 1379 * @param runDirection One of the following values: 1380 * PdfWriter.RUN_DIRECTION_DEFAULT, PdfWriter.RUN_DIRECTION_NO_BIDI, 1381 * PdfWriter.RUN_DIRECTION_LTR or PdfWriter.RUN_DIRECTION_RTL. 1382 */ 1383 public void setRunDirection(final int runDirection) { 1384 switch (runDirection) { 1385 case PdfWriter.RUN_DIRECTION_DEFAULT: 1386 case PdfWriter.RUN_DIRECTION_NO_BIDI: 1387 case PdfWriter.RUN_DIRECTION_LTR: 1388 case PdfWriter.RUN_DIRECTION_RTL: 1389 this.runDirection = runDirection; 1390 break; 1391 default: 1392 throw new RuntimeException(MessageLocalization.getComposedMessage("invalid.run.direction.1", runDirection)); 1393 } 1394 } 1395 1396 /** 1397 * Returns the run direction of the contents in the table. 1398 * 1399 * @return One of the following values: 1400 * PdfWriter.RUN_DIRECTION_DEFAULT, PdfWriter.RUN_DIRECTION_NO_BIDI, 1401 * PdfWriter.RUN_DIRECTION_LTR or PdfWriter.RUN_DIRECTION_RTL. 1402 */ 1403 public int getRunDirection() { 1404 return runDirection; 1405 } 1406 1407 /** 1408 * Getter for property lockedWidth. 1409 * 1410 * @return Value of property lockedWidth. 1411 */ 1412 public boolean isLockedWidth() { 1413 return this.lockedWidth; 1414 } 1415 1416 /** 1417 * Uses the value in <CODE>setTotalWidth()</CODE> in <CODE>Document.add()</CODE>. 1418 * 1419 * @param lockedWidth <CODE>true</CODE> to use the value in <CODE>setTotalWidth()</CODE> in <CODE>Document.add()</CODE> 1420 */ 1421 public void setLockedWidth(final boolean lockedWidth) { 1422 this.lockedWidth = lockedWidth; 1423 } 1424 1425 /** 1426 * Gets the split value. 1427 * 1428 * @return true to split; false otherwise 1429 */ 1430 public boolean isSplitRows() { 1431 return this.splitRows; 1432 } 1433 1434 /** 1435 * When set the rows that won't fit in the page will be split. 1436 * Note that it takes at least twice the memory to handle a split table row 1437 * than a normal table. <CODE>true</CODE> by default. 1438 * 1439 * @param splitRows true to split; false otherwise 1440 */ 1441 public void setSplitRows(final boolean splitRows) { 1442 this.splitRows = splitRows; 1443 } 1444 1445 /** 1446 * Sets the spacing before this table. 1447 * 1448 * @param spacing the new spacing 1449 */ 1450 public void setSpacingBefore(final float spacing) { 1451 this.spacingBefore = spacing; 1452 } 1453 1454 /** 1455 * Sets the spacing after this table. 1456 * 1457 * @param spacing the new spacing 1458 */ 1459 public void setSpacingAfter(final float spacing) { 1460 this.spacingAfter = spacing; 1461 } 1462 1463 /** 1464 * Gets the spacing before this table. 1465 * 1466 * @return the spacing 1467 */ 1468 public float spacingBefore() { 1469 return spacingBefore; 1470 } 1471 1472 /** 1473 * Gets the spacing after this table. 1474 * 1475 * @return the spacing 1476 */ 1477 public float spacingAfter() { 1478 return spacingAfter; 1479 } 1480 1481 /** 1482 * Gets the value of the last row extension. 1483 * 1484 * @return true if the last row will extend; false otherwise 1485 */ 1486 public boolean isExtendLastRow() { 1487 return extendLastRow[0]; 1488 } 1489 1490 /** 1491 * When set the last row on every page will be extended to fill 1492 * all the remaining space to the bottom boundary. 1493 * 1494 * @param extendLastRows true to extend the last row; false otherwise 1495 */ 1496 public void setExtendLastRow(final boolean extendLastRows) { 1497 extendLastRow[0] = extendLastRows; 1498 extendLastRow[1] = extendLastRows; 1499 } 1500 1501 /** 1502 * When set the last row on every page will be extended to fill 1503 * all the remaining space to the bottom boundary; except maybe the 1504 * final row. 1505 * 1506 * @param extendLastRows true to extend the last row on each page; false otherwise 1507 * @param extendFinalRow false if you don't want to extend the final row of the complete table 1508 * @since iText 5.0.0 1509 */ 1510 public void setExtendLastRow(final boolean extendLastRows, final boolean extendFinalRow) { 1511 extendLastRow[0] = extendLastRows; 1512 extendLastRow[1] = extendFinalRow; 1513 } 1514 1515 /** 1516 * Gets the value of the last row extension, taking into account 1517 * if the final row is reached or not. 1518 * 1519 * @return true if the last row will extend; false otherwise 1520 * @since iText 5.0.0 1521 */ 1522 public boolean isExtendLastRow(final boolean newPageFollows) { 1523 if (newPageFollows) { 1524 return extendLastRow[0]; 1525 } 1526 return extendLastRow[1]; 1527 } 1528 1529 /** 1530 * Gets the header status inclusion in PdfPTableEvent. 1531 * 1532 * @return true if the headers are included; false otherwise 1533 */ 1534 public boolean isHeadersInEvent() { 1535 return headersInEvent; 1536 } 1537 1538 /** 1539 * When set the PdfPTableEvent will include the headers. 1540 * 1541 * @param headersInEvent true to include the headers; false otherwise 1542 */ 1543 public void setHeadersInEvent(final boolean headersInEvent) { 1544 this.headersInEvent = headersInEvent; 1545 } 1546 1547 /** 1548 * Gets the property splitLate. 1549 * 1550 * @return the property splitLate 1551 */ 1552 public boolean isSplitLate() { 1553 return splitLate; 1554 } 1555 1556 /** 1557 * If true the row will only split if it's the first one in an empty page. 1558 * It's true by default. 1559 * It's only meaningful if setSplitRows(true). 1560 * 1561 * @param splitLate the property value 1562 */ 1563 public void setSplitLate(final boolean splitLate) { 1564 this.splitLate = splitLate; 1565 } 1566 1567 /** 1568 * If true the table will be kept on one page if it fits, by forcing a 1569 * new page if it doesn't fit on the current page. The default is to 1570 * split the table over multiple pages. 1571 * 1572 * @param keepTogether whether to try to keep the table on one page 1573 */ 1574 public void setKeepTogether(final boolean keepTogether) { 1575 this.keepTogether = keepTogether; 1576 } 1577 1578 /** 1579 * Getter for property keepTogether 1580 * 1581 * @return true if it is tried to keep the table on one page; 1582 * false otherwise 1583 */ 1584 public boolean getKeepTogether() { 1585 return keepTogether; 1586 } 1587 1588 /** 1589 * Gets the number of rows in the footer. 1590 * 1591 * @return the number of rows in the footer 1592 */ 1593 public int getFooterRows() { 1594 return this.footerRows; 1595 } 1596 1597 /** 1598 * Sets the number of rows to be used for the footer. The number 1599 * of footer rows are subtracted from the header rows. For 1600 * example, for a table with two header rows and one footer row the 1601 * code would be: 1602 * <pre> 1603 * table.setHeaderRows(3); 1604 * table.setFooterRows(1); 1605 * </pre> 1606 * Row 0 and 1 will be the header rows and row 2 will be the footer row. 1607 * 1608 * @param footerRows the number of rows to be used for the footer 1609 */ 1610 public void setFooterRows(int footerRows) { 1611 if (footerRows < 0) 1612 footerRows = 0; 1613 this.footerRows = footerRows; 1614 } 1615 1616 /** 1617 * Completes the current row with the default cell. An incomplete row will 1618 * be dropped but calling this method will make sure that it will be 1619 * present in the table. 1620 */ 1621 public void completeRow() { 1622 while (!rowCompleted) { 1623 addCell(defaultCell); 1624 } 1625 } 1626 1627 /** 1628 * @since iText 2.0.8 1629 * @see com.itextpdf.text.LargeElement#flushContent() 1630 */ 1631 public void flushContent() { 1632 deleteBodyRows(); 1633 setSkipFirstHeader(true); 1634 } 1635 1636 /** 1637 * @since iText 2.0.8 1638 * @see com.itextpdf.text.LargeElement#isComplete() 1639 */ 1640 public boolean isComplete() { 1641 return complete; 1642 } 1643 1644 /** 1645 * @since iText 2.0.8 1646 * @see com.itextpdf.text.LargeElement#setComplete(boolean) 1647 */ 1648 public void setComplete(final boolean complete) { 1649 this.complete = complete; 1650 } 1651 1652 /* (non-Javadoc) 1653 * @see com.itextpdf.text.api.Spaceable#getSpacingBefore() 1654 */ 1655 public float getSpacingBefore() { 1656 return spacingBefore; 1657 } 1658 1659 /* (non-Javadoc) 1660 * @see com.itextpdf.text.api.Spaceable#getSpacingAfter() 1661 */ 1662 public float getSpacingAfter() { 1663 return spacingAfter; 1664 } 1665}