1 /*
2 * $Id: Table.java 3373 2008-05-12 16:21:24Z xlv $
3 *
4 * Copyright 1999, 2000, 2001, 2002 by Bruno Lowagie.
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * (the "License"); you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the License.
13 *
14 * The Original Code is 'iText, a free JAVA-PDF library'.
15 *
16 * The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
17 * the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
18 * All Rights Reserved.
19 * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
20 * are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
21 *
22 * Contributor(s): all the names of the contributors are added in the source code
23 * where applicable.
24 *
25 * Alternatively, the contents of this file may be used under the terms of the
26 * LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
27 * provisions of LGPL are applicable instead of those above. If you wish to
28 * allow use of your version of this file only under the terms of the LGPL
29 * License and not to allow others to use your version of this file under
30 * the MPL, indicate your decision by deleting the provisions above and
31 * replace them with the notice and other provisions required by the LGPL.
32 * If you do not delete the provisions above, a recipient may use your version
33 * of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE
34 *
35 * This library is free software; you can redistribute it and/or modify it
36 * under the terms of the MPL as stated above or under the terms of the GNU
37 * Library General Public License as published by the Free Software Foundation;
38 * either version 2 of the License, or any later version.
39 *
40 * This library is distributed in the hope that it will be useful, but WITHOUT
41 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
42 * FOR A PARTICULAR PURPOSE. See the GNU LIBRARY GENERAL PUBLIC LICENSE for more
43 * details.
44 *
45 * If you didn't download this code from the following link, you should check if
46 * you aren't using an obsolete version:
47 * http://www.lowagie.com/iText/
48 *
49 * Some methods in this class were contributed by Geert Poels, Kris Jespers and
50 * Steve Ogryzek. Check the CVS repository.
51 */
52
53 package com.lowagie.text;
54
55 import java.awt.Dimension;
56 import java.awt.Point;
57 import java.util.ArrayList;
58 import java.util.Iterator;
59
60 import com.lowagie.text.pdf.PdfPCell;
61 import com.lowagie.text.pdf.PdfPTable;
62
63 /**
64 * A <CODE>Table</CODE> is a <CODE>Rectangle</CODE> that contains <CODE>Cell</CODE>s,
65 * ordered in some kind of matrix.
66 * <P>
67 * Tables that span multiple pages are cut into different parts automatically.
68 * If you want a table header to be repeated on every page, you may not forget to
69 * mark the end of the header section by using the method <CODE>endHeaders()</CODE>.
70 * <P>
71 * The matrix of a table is not necessarily an m x n-matrix. It can contain holes
72 * or cells that are bigger than the unit. Believe me or not, but it took some serious
73 * thinking to make this as user friendly as possible. I hope you will find the result
74 * quite simple (I love simple solutions, especially for complex problems).
75 * I didn't want it to be something as complex as the Java <CODE>GridBagLayout</CODE>.
76 * <P>
77 * Example:
78 * <BLOCKQUOTE><PRE>
79 * // Remark: You MUST know the number of columns when constructing a Table.
80 * // The number of rows is not important.
81 * <STRONG>Table table = new Table(3);</STRONG>
82 * <STRONG>table.setBorderWidth(1);</STRONG>
83 * <STRONG>table.setBorderColor(new Color(0, 0, 255));</STRONG>
84 * <STRONG>table.setPadding(5);</STRONG>
85 * <STRONG>table.setSpacing(5);</STRONG>
86 * Cell cell = new Cell("header");
87 * cell.setHeader(true);
88 * cell.setColspan(3);
89 * <STRONG>table.addCell(cell);</STRONG>
90 * <STRONG>table.endHeaders();</STRONG>
91 * cell = new Cell("example cell with colspan 1 and rowspan 2");
92 * cell.setRowspan(2);
93 * cell.setBorderColor(new Color(255, 0, 0));
94 * <STRONG>table.addCell(cell);</STRONG>
95 * <STRONG>table.addCell("1.1");</STRONG>
96 * <STRONG>table.addCell("2.1");</STRONG>
97 * <STRONG>table.addCell("1.2");</STRONG>
98 * <STRONG>table.addCell("2.2");</STRONG>
99 * <STRONG>table.addCell("cell test1");</STRONG>
100 * cell = new Cell("big cell");
101 * cell.setRowspan(2);
102 * cell.setColspan(2);
103 * <STRONG>table.addCell(cell);</STRONG>
104 * <STRONG>table.addCell("cell test2");</STRONG>
105 * </PRE></BLOCKQUOTE>
106 * The result of this code is a table:
107 * <TABLE ALIGN="Center" BORDER="1" BORDERCOLOR="#0000ff" CELLPADDING="5" CELLSPACING="5">
108 * <TR ALIGN="Left" VALIGN="Left">
109 * <TH ALIGN="Left" COLSPAN="3" VALIGN="Left">
110 * header
111 * </TH>
112 * </TR>
113 * <TR ALIGN="Left" VALIGN="Left">
114 * <TD ALIGN="Left" BORDERCOLOR="#ff0000" ROWSPAN="2" VALIGN="Left">
115 * example cell with colspan 1 and rowspan 2
116 * </TD>
117 * <TD ALIGN="Left" VALIGN="Left">
118 * 1.1
119 * </TD>
120 * <TD ALIGN="Left" VALIGN="Left">
121 * 2.1
122 * </TD>
123 * </TR>
124 * <TR ALIGN="Left" VALIGN="Left">
125 * <TD ALIGN="Left" VALIGN="Left">
126 * 1.2
127 * </TD>
128 * <TD ALIGN="Left" VALIGN="Left">
129 * 2.2
130 * </TD>
131 * </TR>
132 * <TR ALIGN="Left" VALIGN="Left">
133 * <TD ALIGN="Left" VALIGN="Left">
134 * cell test1
135 * </TD>
136 * <TD ALIGN="Left" COLSPAN="2" ROWSPAN="2" VALIGN="Left">
137 * big cell
138 * </TD>
139 * </TR>
140 * <TR ALIGN="Left" VALIGN="Left">
141 * <TD ALIGN="Left" VALIGN="Left">
142 * cell test2
143 * </TD>
144 * </TR>
145 * </TABLE>
146 *
147 * @see Rectangle
148 * @see Element
149 * @see Row
150 * @see Cell
151 */
152
153 public class Table extends Rectangle implements LargeElement {
154
155 // membervariables
156
157 /** This is the number of columns in the <CODE>Table</CODE>. */
158 private int columns;
159
160 /** This is the list of <CODE>Row</CODE>s. */
161 private ArrayList rows = new ArrayList();
162
163 /** The current Position in the table. */
164 private Point curPosition = new Point(0, 0);
165
166 /** This Empty Cell contains the DEFAULT layout of each Cell added with the method addCell(String content). */
167 private Cell defaultCell = new Cell(true);
168
169 /** This is the number of the last row of the table headers. */
170 private int lastHeaderRow = -1;
171
172 /** This is the horizontal alignment. */
173 private int alignment = Element.ALIGN_CENTER;
174
175 /** This is cellpadding. */
176 private float cellpadding;
177
178 /** This is cellspacing. */
179 private float cellspacing;
180
181 /** This is the width of the table (in percent of the available space). */
182 private float width = 80;
183
184 /** Is the width a percentage (false) or an absolute width (true)? */
185 private boolean locked = false;
186
187 /** This is an array containing the widths (in percentages) of every column. */
188 private float[] widths;
189
190 /** Boolean to track if a table was inserted (to avoid unnecessary computations afterwards) */
191 private boolean mTableInserted = false;
192
193 /**
194 * Boolean to automatically fill empty cells before a table is rendered
195 * (takes CPU so may be set to false in case of certainty)
196 */
197 protected boolean autoFillEmptyCells = false;
198
199 /** If true this table may not be split over two pages. */
200 boolean tableFitsPage = false;
201
202 /** If true cells may not be split over two pages. */
203 boolean cellsFitPage = false;
204
205 /** This is the offset of the table. */
206 float offset = Float.NaN;
207
208 /** if you want to generate tables the old way, set this value to false. */
209 protected boolean convert2pdfptable = false;
210
211 /**
212 * Indicates if this is the first time the section was added.
213 * @since iText 2.0.8
214 */
215 protected boolean notAddedYet = true;
216
217 /**
218 * Indicates if the PdfPTable is complete once added to the document.
219 * @since iText 2.0.8
220 */
221 protected boolean complete = true;
222
223 // constructors
224
225 /**
226 * Constructs a <CODE>Table</CODE> with a certain number of columns.
227 *
228 * @param columns The number of columns in the table
229 * @throws BadElementException if the creator was called with less than 1 column
230 */
231 public Table(int columns) throws BadElementException {
232 this(columns, 1);
233 }
234
235 /**
236 * Constructs a <CODE>Table</CODE> with a certain number of columns
237 * and a certain number of <CODE>Row</CODE>s.
238 *
239 * @param columns The number of columns in the table
240 * @param rows The number of rows
241 * @throws BadElementException if the creator was called with less than 1 column
242 */
243 public Table(int columns, int rows) throws BadElementException {
244 // a Rectangle is create with BY DEFAULT a border with a width of 1
245 super(0, 0, 0, 0);
246 setBorder(BOX);
247 setBorderWidth(1);
248 defaultCell.setBorder(BOX);
249
250 // a table should have at least 1 column
251 if (columns <= 0) {
252 throw new BadElementException("A table should have at least 1 column.");
253 }
254 this.columns = columns;
255
256 // a certain number of rows are created
257 for (int i = 0; i < rows; i++) {
258 this.rows.add(new Row(columns));
259 }
260 curPosition = new Point(0, 0);
261
262 // the DEFAULT widths are calculated
263 widths = new float[columns];
264 float width = 100f / columns;
265 for (int i = 0; i < columns; i++) {
266 widths[i] = width;
267 }
268 }
269
270 /**
271 * Copy constructor (shallow copy).
272 * @throws BadElementException
273 */
274 public Table(Table t) {
275 super(0, 0, 0, 0);
276 this.cloneNonPositionParameters(t);
277 this.columns = t.columns;
278 this.rows = t.rows;
279 this.curPosition = t.curPosition;
280 this.defaultCell = t.defaultCell;
281 this.lastHeaderRow = t.lastHeaderRow;
282 this.alignment = t.alignment;
283 this.cellpadding = t.cellpadding;
284 this.cellspacing = t.cellspacing;
285 this.width = t.width;
286 this.widths = t.widths;
287 this.autoFillEmptyCells = t.autoFillEmptyCells;
288 this.tableFitsPage = t.tableFitsPage;
289 this.cellsFitPage = t.cellsFitPage;
290 this.offset = t.offset;
291 this.convert2pdfptable = t.convert2pdfptable;
292 }
293
294 // implementation of the Element-methods
295
296 /**
297 * Processes the element by adding it (or the different parts) to an
298 * <CODE>ElementListener</CODE>.
299 *
300 * @param listener an <CODE>ElementListener</CODE>
301 * @return <CODE>true</CODE> if the element was processed successfully
302 */
303 public boolean process(ElementListener listener) {
304 try {
305 return listener.add(this);
306 }
307 catch(DocumentException de) {
308 return false;
309 }
310 }
311
312 /**
313 * Gets the type of the text element.
314 *
315 * @return a type
316 */
317 public int type() {
318 return Element.TABLE;
319 }
320
321 /**
322 * Gets all the chunks in this element.
323 *
324 * @return an <CODE>ArrayList</CODE>
325 */
326
327 public ArrayList getChunks() {
328 return new ArrayList();
329 }
330
331 /**
332 * @see com.lowagie.text.Element#isNestable()
333 * @since iText 2.0.8
334 */
335 public boolean isNestable() {
336 return true;
337 }
338
339 // getters and setters
340
341 /**
342 * Gets the number of columns.
343 *
344 * @return a value
345 */
346 public int getColumns() {
347 return columns;
348 }
349
350 /**
351 * Gets the number of rows in this <CODE>Table</CODE>.
352 *
353 * @return the number of rows in this <CODE>Table</CODE>
354 */
355 public int size() {
356 return rows.size();
357 }
358
359 /**
360 * Gets the dimension of this table
361 *
362 * @return dimension
363 */
364 public Dimension getDimension() {
365 return new Dimension(columns, size());
366 }
367
368 /**
369 * Gets the default layout of the Table.
370 * @return a cell with all the defaults
371 * @since 2.0.7
372 */
373 public Cell getDefaultCell() {
374 return defaultCell;
375 }
376
377 /**
378 * Sets the default layout of the Table to
379 * the provided Cell
380 * @param value a cell with all the defaults
381 * @since 2.0.7
382 */
383 public void setDefaultCell(Cell value) {
384 defaultCell = value;
385 }
386
387 /**
388 * Gets the last number of the rows that contain headers.
389 *
390 * @return a rownumber
391 */
392 public int getLastHeaderRow() {
393 return this.lastHeaderRow;
394 }
395
396 /**
397 * Sets the horizontal alignment.
398 *
399 * @param value the new value
400 */
401 public void setLastHeaderRow(int value) {
402 lastHeaderRow = value;
403 }
404
405 /**
406 * Marks the last row of the table headers.
407 *
408 * @return the number of the last row of the table headers
409 */
410 public int endHeaders() {
411 lastHeaderRow = curPosition.x - 1;
412 return lastHeaderRow;
413 }
414
415 /**
416 * Gets the horizontal alignment.
417 *
418 * @return a value
419 */
420 public int getAlignment() {
421 return alignment;
422 }
423
424 /**
425 * Sets the horizontal alignment.
426 *
427 * @param value the new value
428 */
429 public void setAlignment(int value) {
430 alignment = value;
431 }
432
433 /**
434 * Sets the alignment of this paragraph.
435 *
436 * @param alignment the new alignment as a <CODE>String</CODE>
437 */
438 public void setAlignment(String alignment) {
439 if (ElementTags.ALIGN_LEFT.equalsIgnoreCase(alignment)) {
440 this.alignment = Element.ALIGN_LEFT;
441 return;
442 }
443 if (ElementTags.RIGHT.equalsIgnoreCase(alignment)) {
444 this.alignment = Element.ALIGN_RIGHT;
445 return;
446 }
447 this.alignment = Element.ALIGN_CENTER;
448 }
449
450 /**
451 * Gets the cellpadding.
452 *
453 * @return a value
454 */
455 public float getPadding() {
456 return cellpadding;
457 }
458
459 /**
460 * Sets the cellpadding.
461 *
462 * @param value the new value
463 */
464 public void setPadding(float value) {
465 cellpadding = value;
466 }
467
468 /**
469 * Gets the cellspacing.
470 *
471 * @return a value
472 */
473 public float getSpacing() {
474 return cellspacing;
475 }
476
477 /**
478 * Sets the cellspacing.
479 *
480 * @param value the new value
481 */
482 public void setSpacing(float value) {
483 cellspacing = value;
484 }
485
486 /**
487 * Enables/disables automatic insertion of empty cells before table is rendered. (default = false)
488 * As some people may want to create a table, fill only a couple of the cells and don't bother with
489 * investigating which empty ones need to be added, this default behavior may be very welcome.
490 * Disabling is recommended to increase speed. (empty cells should be added through extra code then)
491 *
492 * @param aDoAutoFill enable/disable autofill
493 */
494 public void setAutoFillEmptyCells(boolean aDoAutoFill) {
495 autoFillEmptyCells = aDoAutoFill;
496 }
497
498 /**
499 * Gets the table width (a percentage).
500 *
501 * @return the table width
502 */
503 public float getWidth() {
504 return width;
505 }
506
507 /**
508 * Sets the width of this table (in percentage of the available space).
509 *
510 * @param width the width
511 */
512 public void setWidth(float width) {
513 this.width = width;
514 }
515
516 /**
517 * @return the locked
518 */
519 public boolean isLocked() {
520 return locked;
521 }
522
523 /**
524 * @param locked the locked to set
525 */
526 public void setLocked(boolean locked) {
527 this.locked = locked;
528 }
529
530 /**
531 * Gets the proportional widths of the columns in this <CODE>Table</CODE>.
532 *
533 * @return the proportional widths of the columns in this <CODE>Table</CODE>
534 */
535 public float[] getProportionalWidths() {
536 return widths;
537 }
538
539 /**
540 * Sets the widths of the different columns (percentages).
541 * <P>
542 * You can give up relative values of borderwidths.
543 * The sum of these values will be considered 100%.
544 * The values will be recalculated as percentages of this sum.
545 * <P>
546 * example:
547 * <BLOCKQUOTE><PRE>
548 * float[] widths = {2, 1, 1};
549 * <STRONG>table.setWidths(widths)</STRONG>
550 * </PRE></BLOCKQUOTE>
551 * The widths will be: a width of 50% for the first column,
552 * 25% for the second and third column.
553 *
554 * @param widths an array with values
555 * @throws BadElementException
556 */
557 public void setWidths(float[] widths) throws BadElementException {
558 if (widths.length != columns) {
559 throw new BadElementException("Wrong number of columns.");
560 }
561
562 // The sum of all values is 100%
563 float hundredPercent = 0;
564 for (int i = 0; i < columns; i++) {
565 hundredPercent += widths[i];
566 }
567
568 // The different percentages are calculated
569 float width;
570 this.widths[columns - 1] = 100;
571 for (int i = 0; i < columns - 1; i++) {
572 width = (100.0f * widths[i]) / hundredPercent;
573 this.widths[i] = width;
574 this.widths[columns - 1] -= width;
575 }
576 }
577
578 /**
579 * Sets the widths of the different columns (percentages).
580 * <P>
581 * You can give up relative values of borderwidths.
582 * The sum of these values will be considered 100%.
583 * The values will be recalculated as percentages of this sum.
584 *
585 * @param widths an array with values
586 * @throws DocumentException
587 */
588 public void setWidths(int[] widths) throws DocumentException {
589 float tb[] = new float[widths.length];
590 for (int k = 0; k < widths.length; ++k)
591 tb[k] = widths[k];
592 setWidths(tb);
593 }
594
595 /**
596 * Checks if this <CODE>Table</CODE> has to fit a page.
597 *
598 * @return true if the table may not be split
599 */
600 public boolean isTableFitsPage() {
601 return tableFitsPage;
602 }
603
604 /**
605 * Allows you to control when a page break occurs.
606 * <P>
607 * When a table doesn't fit a page, it is split in two parts.
608 * If you want to avoid this, you should set the <VAR>tableFitsPage</VAR> value to true.
609 *
610 * @param fitPage enter true if you don't want to split cells
611 */
612 public void setTableFitsPage(boolean fitPage) {
613 this.tableFitsPage = fitPage;
614 if (fitPage) setCellsFitPage(true);
615 }
616
617 /**
618 * Checks if the cells of this <CODE>Table</CODE> have to fit a page.
619 *
620 * @return true if the cells may not be split
621 */
622 public boolean isCellsFitPage() {
623 return cellsFitPage;
624 }
625
626 /**
627 * Allows you to control when a page break occurs.
628 * <P>
629 * When a cell doesn't fit a page, it is split in two parts.
630 * If you want to avoid this, you should set the <VAR>cellsFitPage</VAR> value to true.
631 *
632 * @param fitPage enter true if you don't want to split cells
633 */
634 public void setCellsFitPage(boolean fitPage) {
635 this.cellsFitPage = fitPage;
636 }
637
638 /**
639 * Sets the offset of this table.
640 *
641 * Normally a newline is added before you add a Table object.
642 * This newline uses the current leading.
643 * If you want to control the space between the table and the previous
644 * element yourself, you have to set the offset of this table.
645 *
646 * @param offset the space between this table and the previous object.
647 */
648 public void setOffset(float offset) {
649 this.offset = offset;
650 }
651
652 /**
653 * Gets the offset of this table.
654 *
655 * @return the space between this table and the previous element.
656 */
657 public float getOffset() {
658 return offset;
659 }
660
661 /**
662 * Method to check if the Table should be converted to a PdfPTable or not.
663 * @return false if the table should be handled the old fashioned way.
664 */
665 public boolean isConvert2pdfptable() {
666 return convert2pdfptable;
667 }
668 /**
669 * If set to true, iText will try to convert the Table to a PdfPTable.
670 * @param convert2pdfptable true if you want iText to try to convert the Table to a PdfPTable
671 */
672 public void setConvert2pdfptable(boolean convert2pdfptable) {
673 this.convert2pdfptable = convert2pdfptable;
674 }
675
676 // methods to add content to the table
677
678 /**
679 * Adds a <CODE>Cell</CODE> to the <CODE>Table</CODE> at a certain row and column.
680 *
681 * @param aCell The <CODE>Cell</CODE> to add
682 * @param row The row where the <CODE>Cell</CODE> will be added
683 * @param column The column where the <CODE>Cell</CODE> will be added
684 * @throws BadElementException
685 */
686 public void addCell(Cell aCell, int row, int column) throws BadElementException {
687 addCell(aCell, new Point(row,column));
688 }
689
690 /**
691 * Adds a <CODE>Cell</CODE> to the <CODE>Table</CODE> at a certain location.
692 *
693 * @param aCell The <CODE>Cell</CODE> to add
694 * @param aLocation The location where the <CODE>Cell</CODE> will be added
695 * @throws BadElementException
696 */
697 public void addCell(Cell aCell, Point aLocation) throws BadElementException {
698 if (aCell == null) throw new NullPointerException("addCell - cell has null-value");
699 if (aLocation == null) throw new NullPointerException("addCell - point has null-value");
700 if (aCell.isTable()) insertTable((Table)aCell.getElements().next(), aLocation);
701
702 if (aLocation.x < 0) throw new BadElementException("row coordinate of location must be >= 0");
703 if ((aLocation.y <= 0) && (aLocation.y > columns)) throw new BadElementException("column coordinate of location must be >= 0 and < nr of columns");
704 if (!isValidLocation(aCell, aLocation)) throw new BadElementException("Adding a cell at the location (" + aLocation.x + "," + aLocation.y + ") with a colspan of " + aCell.getColspan() + " and a rowspan of " + aCell.getRowspan() + " is illegal (beyond boundaries/overlapping).");
705
706 if (aCell.getBorder() == UNDEFINED) aCell.setBorder(defaultCell.getBorder());
707 aCell.fill();
708 placeCell(rows, aCell, aLocation);
709 setCurrentLocationToNextValidPosition(aLocation);
710 }
711
712 /**
713 * Adds a <CODE>Cell</CODE> to the <CODE>Table</CODE>.
714 *
715 * @param cell a <CODE>Cell</CODE>
716 */
717 public void addCell(Cell cell) {
718 try {
719 addCell(cell, curPosition);
720 }
721 catch(BadElementException bee) {
722 // don't add the cell
723 }
724 }
725
726 /**
727 * Adds a <CODE>Cell</CODE> to the <CODE>Table</CODE>.
728 * <P>
729 * This is a shortcut for <CODE>addCell(Cell cell)</CODE>.
730 * The <CODE>Phrase</CODE> will be converted to a <CODE>Cell</CODE>.
731 *
732 * @param content a <CODE>Phrase</CODE>
733 * @throws BadElementException this should never happen
734 */
735 public void addCell(Phrase content) throws BadElementException {
736 addCell(content, curPosition);
737 }
738
739 /**
740 * Adds a <CODE>Cell</CODE> to the <CODE>Table</CODE>.
741 * <P>
742 * This is a shortcut for <CODE>addCell(Cell cell, Point location)</CODE>.
743 * The <CODE>Phrase</CODE> will be converted to a <CODE>Cell</CODE>.
744 *
745 * @param content a <CODE>Phrase</CODE>
746 * @param location a <CODE>Point</CODE>
747 * @throws BadElementException this should never happen
748 */
749 public void addCell(Phrase content, Point location) throws BadElementException {
750 Cell cell = new Cell(content);
751 cell.setBorder(defaultCell.getBorder());
752 cell.setBorderWidth(defaultCell.getBorderWidth());
753 cell.setBorderColor(defaultCell.getBorderColor());
754 cell.setBackgroundColor(defaultCell.getBackgroundColor());
755 cell.setHorizontalAlignment(defaultCell.getHorizontalAlignment());
756 cell.setVerticalAlignment(defaultCell.getVerticalAlignment());
757 cell.setColspan(defaultCell.getColspan());
758 cell.setRowspan(defaultCell.getRowspan());
759 addCell(cell, location);
760 }
761
762 /**
763 * Adds a <CODE>Cell</CODE> to the <CODE>Table</CODE>.
764 * <P>
765 * This is a shortcut for <CODE>addCell(Cell cell)</CODE>.
766 * The <CODE>String</CODE> will be converted to a <CODE>Cell</CODE>.
767 *
768 * @param content a <CODE>String</CODE>
769 * @throws BadElementException this should never happen
770 */
771
772 public void addCell(String content) throws BadElementException {
773 addCell(new Phrase(content), curPosition);
774 }
775
776 /**
777 * Adds a <CODE>Cell</CODE> to the <CODE>Table</CODE>.
778 * <P>
779 * This is a shortcut for <CODE>addCell(Cell cell, Point location)</CODE>.
780 * The <CODE>String</CODE> will be converted to a <CODE>Cell</CODE>.
781 *
782 * @param content a <CODE>String</CODE>
783 * @param location a <CODE>Point</CODE>
784 * @throws BadElementException this should never happen
785 */
786 public void addCell(String content, Point location) throws BadElementException {
787 addCell(new Phrase(content), location);
788 }
789
790 /**
791 * To put a table within the existing table at the current position
792 * generateTable will of course re-arrange the widths of the columns.
793 *
794 * @param aTable the table you want to insert
795 */
796 public void insertTable(Table aTable) {
797 if (aTable == null) throw new NullPointerException("insertTable - table has null-value");
798 insertTable(aTable, curPosition);
799 }
800
801 /**
802 * To put a table within the existing table at the given position
803 * generateTable will of course re-arrange the widths of the columns.
804 *
805 * @param aTable The <CODE>Table</CODE> to add
806 * @param row The row where the <CODE>Cell</CODE> will be added
807 * @param column The column where the <CODE>Cell</CODE> will be added
808 */
809 public void insertTable(Table aTable, int row, int column) {
810 if (aTable == null) throw new NullPointerException("insertTable - table has null-value");
811 insertTable(aTable, new Point(row, column));
812 }
813
814 /**
815 * To put a table within the existing table at the given position
816 * generateTable will of course re-arrange the widths of the columns.
817 *
818 * @param aTable the table you want to insert
819 * @param aLocation a <CODE>Point</CODE>
820 */
821 public void insertTable(Table aTable, Point aLocation) {
822
823 if (aTable == null) throw new NullPointerException("insertTable - table has null-value");
824 if (aLocation == null) throw new NullPointerException("insertTable - point has null-value");
825 mTableInserted = true;
826 aTable.complete();
827
828 if (aLocation.y > columns) {
829 throw new IllegalArgumentException("insertTable -- wrong columnposition("+ aLocation.y + ") of location; max =" + columns);
830 }
831
832 int rowCount = aLocation.x + 1 - rows.size();
833 int i = 0;
834 if ( rowCount > 0 ) { //create new rows ?
835 for (; i < rowCount; i++) {
836 rows.add(new Row(columns));
837 }
838 }
839
840 ((Row) rows.get(aLocation.x)).setElement(aTable,aLocation.y);
841
842 setCurrentLocationToNextValidPosition(aLocation);
843 }
844
845 /**
846 * Gives you the possibility to add columns.
847 *
848 * @param aColumns the number of columns to add
849 */
850 public void addColumns(int aColumns) {
851 ArrayList newRows = new ArrayList(rows.size());
852
853 int newColumns = columns + aColumns;
854 Row row;
855 for (int i = 0; i < rows.size(); i++) {
856 row = new Row(newColumns);
857 for (int j = 0; j < columns; j++) {
858 row.setElement(((Row) rows.get(i)).getCell(j) ,j);
859 }
860 for (int j = columns; j < newColumns && i < curPosition.x; j++) {
861 row.setElement(null, j);
862 }
863 newRows.add(row);
864 }
865 // applied 1 column-fix; last column needs to have a width of 0
866 float [] newWidths = new float[newColumns];
867 System.arraycopy(widths, 0, newWidths, 0, columns);
868 for (int j = columns; j < newColumns ; j++) {
869 newWidths[j] = 0;
870 }
871 columns = newColumns;
872 widths = newWidths;
873 rows = newRows;
874 }
875
876 /**
877 * Deletes a column in this table.
878 *
879 * @param column the number of the column that has to be deleted
880 * @throws BadElementException
881 */
882 public void deleteColumn(int column) throws BadElementException {
883 float newWidths[] = new float[--columns];
884 System.arraycopy(widths, 0, newWidths, 0, column);
885 System.arraycopy(widths, column + 1, newWidths, column, columns - column);
886 setWidths(newWidths);
887 System.arraycopy(widths, 0, newWidths, 0, columns);
888 widths = newWidths;
889 Row row;
890 int size = rows.size();
891 for (int i = 0; i < size; i++) {
892 row = (Row) rows.get(i);
893 row.deleteColumn(column);
894 rows.set(i, row);
895 }
896 if (column == columns) {
897 curPosition.setLocation(curPosition.x+1, 0);
898 }
899 }
900
901 /**
902 * Deletes a row.
903 *
904 * @param row the number of the row to delete
905 * @return boolean <CODE>true</CODE> if the row was deleted; <CODE>false</CODE> if not
906 */
907 public boolean deleteRow(int row) {
908 if (row < 0 || row >= rows.size()) {
909 return false;
910 }
911 rows.remove(row);
912 curPosition.setLocation(curPosition.x-1, curPosition.y);
913 return true;
914 }
915
916 /**
917 * Deletes all rows in this table.
918 * (contributed by dperezcar@fcc.es)
919 */
920 public void deleteAllRows() {
921 rows.clear();
922 rows.add(new Row(columns));
923 curPosition.setLocation(0, 0);
924 lastHeaderRow = -1;
925 }
926
927 /**
928 * Deletes the last row in this table.
929 *
930 * @return boolean <CODE>true</CODE> if the row was deleted; <CODE>false</CODE> if not
931 */
932 public boolean deleteLastRow() {
933 return deleteRow(rows.size() - 1);
934 }
935
936 /**
937 * Will fill empty cells with valid blank <CODE>Cell</CODE>s
938 */
939 public void complete() {
940 if (mTableInserted) {
941 mergeInsertedTables(); // integrate tables in the table
942 mTableInserted = false;
943 }
944 if (autoFillEmptyCells) {
945 fillEmptyMatrixCells();
946 }
947 }
948
949 // private helper classes
950
951 /**
952 * returns the element at the position row, column
953 * (Cast to Cell or Table)
954 *
955 * @param row
956 * @param column
957 * @return dimension
958 * @since 2.1.0 (was made private in 2.0.3)
959 */
960 public Object getElement(int row, int column) {
961 return ((Row) rows.get(row)).getCell(column);
962 }
963
964 /**
965 * Integrates all added tables and recalculates column widths.
966 */
967 private void mergeInsertedTables() {
968 int i=0, j=0;
969 float [] lNewWidths = null;
970 int [] lDummyWidths = new int[columns]; // to keep track in how many new cols this one will be split
971 float[][] lDummyColumnWidths = new float[columns][]; // bugfix Tony Copping
972 int [] lDummyHeights = new int[rows.size()]; // to keep track in how many new rows this one will be split
973 ArrayList newRows = null;
974 boolean isTable=false;
975 int lTotalRows = 0, lTotalColumns = 0;
976 int lNewMaxRows = 0, lNewMaxColumns = 0;
977
978 Table lDummyTable = null;
979
980 // first we'll add new columns when needed
981 // check one column at a time, find maximum needed nr of cols
982 // Search internal tables and find one with max columns
983 for (j=0; j < columns; j++) {
984 lNewMaxColumns = 1; // value to hold in how many columns the current one will be split
985 float [] tmpWidths = null;
986 for (i=0; i < rows.size(); i++) {
987 if ( Table.class.isInstance(((Row) rows.get(i)).getCell(j)) ) {
988 isTable=true;
989 lDummyTable = ((Table) ((Row) rows.get(i)).getCell(j));
990 if( tmpWidths == null) {
991 tmpWidths = lDummyTable.widths;
992 lNewMaxColumns=tmpWidths.length;
993 }
994 else {
995 int cols = lDummyTable.getDimension().width;
996 float [] tmpWidthsN = new float[ cols * tmpWidths.length];
997 float tpW=0, btW=0, totW=0;
998 int tpI=0, btI=0, totI=0;
999 tpW+=tmpWidths[0];
1000 btW+=lDummyTable.widths[0];
1001 while( tpI<tmpWidths.length && btI<cols) {
1002 if( btW>tpW) {
1003 tmpWidthsN[totI] = tpW-totW;
1004 tpI++;
1005 if(tpI<tmpWidths.length) {
1006 tpW+=tmpWidths[tpI];
1007 }
1008 }
1009 else {
1010 tmpWidthsN[totI] = btW-totW;
1011 btI++;
1012 if(Math.abs(btW - tpW) < 0.0001) {
1013 tpI++;
1014 if(tpI<tmpWidths.length) {
1015 tpW+=tmpWidths[tpI];
1016 }
1017 }
1018 if(btI<cols) {
1019 btW+=lDummyTable.widths[btI];
1020 }
1021 }
1022 totW+=tmpWidthsN[totI];
1023 totI++;
1024 }
1025 /*if( tpI<tmpWidths.length)
1026 {
1027 System.arraycopy(tmpWidths, tpI, tmpWidthsN, totI, tmpWidths.length-tpI);
1028 totI +=tmpWidths.length-tpI;
1029 }
1030 else if(btI<cols)
1031 {
1032 System.arraycopy(lDummyTable.widths, btI, tmpWidthsN, totI, lDummyTable.widths.length-btI);
1033 totI +=lDummyTable.widths.length-btI; }*/
1034 tmpWidths = new float[totI];
1035 System.arraycopy(tmpWidthsN, 0, tmpWidths, 0, totI);
1036 lNewMaxColumns=totI;
1037 }
1038 /*if ( lDummyTable.getDimension().width > lNewMaxColumns )
1039 {
1040 lNewMaxColumns = lDummyTable.getDimension().width;
1041 lDummyColumnWidths[j] = lDummyTable.widths; // bugfix Tony Copping
1042 }*/
1043 }
1044 }
1045 lDummyColumnWidths[j] = tmpWidths;
1046 lTotalColumns += lNewMaxColumns;
1047 lDummyWidths [j] = lNewMaxColumns;
1048 }
1049
1050 // next we'll add new rows when needed
1051 for (i=0; i < rows.size(); i++) {
1052 lNewMaxRows = 1; // holds value in how many rows the current one will be split
1053 for (j=0; j < columns; j++) {
1054 if ( Table.class.isInstance(((Row) rows.get(i)).getCell(j)) ) {
1055 isTable=true;
1056 lDummyTable = (Table) ((Row) rows.get(i)).getCell(j);
1057 if ( lDummyTable.getDimension().height > lNewMaxRows ) {
1058 lNewMaxRows = lDummyTable.getDimension().height;
1059 }
1060 }
1061 }
1062 lTotalRows += lNewMaxRows;
1063 lDummyHeights [i] = lNewMaxRows;
1064 }
1065
1066 if ( (lTotalColumns != columns) || (lTotalRows != rows.size()) || isTable) // NO ADJUSTMENT
1067 {
1068 // ** WIDTH
1069 // set correct width for new columns
1070 // divide width over new nr of columns
1071 // Take new max columns of internal table and work out widths for each col
1072 lNewWidths = new float [lTotalColumns];
1073 int lDummy = 0;
1074 for (int tel=0; tel < widths.length;tel++) {
1075 if ( lDummyWidths[tel] != 1) {
1076 // divide
1077 for (int tel2 = 0; tel2 < lDummyWidths[tel]; tel2++) {
1078 // lNewWidths[lDummy] = widths[tel] / lDummyWidths[tel];
1079 lNewWidths[lDummy] = widths[tel] * lDummyColumnWidths[tel][tel2] / 100f; // bugfix Tony Copping
1080 lDummy++;
1081 }
1082 }
1083 else {
1084 lNewWidths[lDummy] = widths[tel];
1085 lDummy++;
1086 }
1087 }
1088
1089 // ** FILL OUR NEW TABLE
1090 // generate new table
1091 // set new widths
1092 // copy old values
1093 newRows = new ArrayList(lTotalRows);
1094 for (i = 0; i < lTotalRows; i++) {
1095 newRows.add(new Row(lTotalColumns));
1096 }
1097 int lDummyRow = 0, lDummyColumn = 0; // to remember where we are in the new, larger table
1098 Object lDummyElement = null;
1099 for (i=0; i < rows.size(); i++) {
1100 lDummyColumn = 0;
1101 lNewMaxRows = 1;
1102 for (j=0; j < columns; j++) {
1103 if ( Table.class.isInstance(((Row) rows.get(i)).getCell(j)) ) // copy values from embedded table
1104 {
1105 lDummyTable = (Table) ((Row) rows.get(i)).getCell(j);
1106
1107 // Work out where columns in table table correspond to columns in current table
1108 int colMap[] = new int[lDummyTable.widths.length+1];
1109 int cb=0, ct=0;
1110
1111 for( ; cb<lDummyTable.widths.length;cb++) {
1112 colMap[cb] = lDummyColumn+ct;
1113
1114 float wb;
1115 wb = lDummyTable.widths[cb];
1116
1117 float wt=0;
1118 while( ct<lDummyWidths[j]) {
1119 wt+=lDummyColumnWidths[j][ct++];
1120 if(Math.abs(wb - wt) < 0.0001) break;
1121 }
1122 }
1123 colMap[cb] = lDummyColumn+ct;
1124
1125 // need to change this to work out how many cols to span
1126 for (int k=0; k < lDummyTable.getDimension().height; k++) {
1127 for (int l=0; l < lDummyTable.getDimension().width; l++) {
1128 lDummyElement = lDummyTable.getElement(k,l);
1129 if (lDummyElement != null) {
1130 int col=lDummyColumn+l;
1131
1132 if ( Cell.class.isInstance(lDummyElement) ) {
1133 Cell lDummyC = (Cell)lDummyElement;
1134 // Find col to add cell in and set col span
1135 col = colMap[l];
1136 int ot = colMap[l+lDummyC.getColspan()];
1137
1138 lDummyC.setColspan(ot-col);
1139 }
1140
1141 ((Row) newRows.get(k + lDummyRow)).addElement(lDummyElement,col); // use addElement to set reserved status ok in row
1142 }
1143 }
1144 }
1145 }
1146 else // copy others values
1147 {
1148 Object aElement = getElement(i,j);
1149
1150 if ( Cell.class.isInstance(aElement) ) {
1151
1152 // adjust spans for cell
1153 ((Cell) aElement).setRowspan(((Cell) ((Row) rows.get(i)).getCell(j)).getRowspan() + lDummyHeights[i] - 1);
1154 ((Cell) aElement).setColspan(((Cell) ((Row) rows.get(i)).getCell(j)).getColspan() + lDummyWidths[j] - 1);
1155
1156 // most likely this cell covers a larger area because of the row/cols splits : define not-to-be-filled cells
1157 placeCell(newRows,((Cell) aElement), new Point(lDummyRow,lDummyColumn));
1158 }
1159 }
1160 lDummyColumn += lDummyWidths[j];
1161 }
1162 lDummyRow += lDummyHeights[i];
1163 }
1164
1165 // Set our new matrix
1166 columns = lTotalColumns;
1167 rows = newRows;
1168 this.widths = lNewWidths;
1169 }
1170 }
1171
1172 /**
1173 * adds new<CODE>Cell</CODE>'s to empty/null spaces.
1174 */
1175 private void fillEmptyMatrixCells() {
1176 try {
1177 for (int i=0; i < rows.size(); i++) {
1178 for (int j=0; j < columns; j++) {
1179 if (!((Row) rows.get(i)).isReserved(j)) {
1180 addCell(defaultCell, new Point(i, j));
1181 }
1182 }
1183 }
1184 }
1185 catch(BadElementException bee) {
1186 throw new ExceptionConverter(bee);
1187 }
1188 }
1189
1190 /**
1191 * check if <CODE>Cell</CODE> 'fits' the table.
1192 * <P>
1193 * <UL><LI>rowspan/colspan not beyond borders
1194 * <LI>spanned cell don't overlap existing cells</UL>
1195 *
1196 * @param aCell the cell that has to be checked
1197 * @param aLocation the location where the cell has to be placed
1198 * @return true if the location was valid
1199 */
1200 private boolean isValidLocation(Cell aCell, Point aLocation) {
1201 // rowspan not beyond last column
1202 if ( aLocation.x < rows.size() ) // if false : new location is already at new, not-yet-created area so no check
1203 {
1204 if ((aLocation.y + aCell.getColspan()) > columns) {
1205 return false;
1206 }
1207
1208 int difx = ((rows.size() - aLocation.x) > aCell.getRowspan()) ? aCell.getRowspan() : rows.size() - aLocation.x;
1209 int dify = ((columns - aLocation.y) > aCell.getColspan()) ? aCell.getColspan() : columns - aLocation.y;
1210 // no other content at cells targeted by rowspan/colspan
1211 for (int i=aLocation.x; i < (aLocation.x + difx); i++) {
1212 for (int j=aLocation.y; j < (aLocation.y + dify); j++) {
1213 if (((Row) rows.get(i)).isReserved(j)) {
1214 return false;
1215 }
1216 }
1217 }
1218 }
1219 else {
1220 if ((aLocation.y + aCell.getColspan()) > columns) {
1221 return false;
1222 }
1223 }
1224
1225 return true;
1226 }
1227
1228 /**
1229 * Sets the unset cell properties to be the table defaults.
1230 *
1231 * @param aCell The cell to set to table defaults as necessary.
1232 */
1233 private void assumeTableDefaults(Cell aCell) {
1234
1235 if (aCell.getBorder() == Rectangle.UNDEFINED) {
1236 aCell.setBorder(defaultCell.getBorder());
1237 }
1238 if (aCell.getBorderWidth() == Rectangle.UNDEFINED) {
1239 aCell.setBorderWidth(defaultCell.getBorderWidth());
1240 }
1241 if (aCell.getBorderColor() == null) {
1242 aCell.setBorderColor(defaultCell.getBorderColor());
1243 }
1244 if (aCell.getBackgroundColor() == null) {
1245 aCell.setBackgroundColor(defaultCell.getBackgroundColor());
1246 }
1247 if (aCell.getHorizontalAlignment() == Element.ALIGN_UNDEFINED) {
1248 aCell.setHorizontalAlignment(defaultCell.getHorizontalAlignment());
1249 }
1250 if (aCell.getVerticalAlignment() == Element.ALIGN_UNDEFINED) {
1251 aCell.setVerticalAlignment(defaultCell.getVerticalAlignment());
1252 }
1253 }
1254
1255 /**
1256 * Inserts a Cell in a cell-array and reserves cells defined by row-/colspan.
1257 *
1258 * @param someRows some rows
1259 * @param aCell the cell that has to be inserted
1260 * @param aPosition the position where the cell has to be placed
1261 */
1262 private void placeCell(ArrayList someRows, Cell aCell, Point aPosition) {
1263 int i;
1264 Row row = null;
1265 int rowCount = aPosition.x + aCell.getRowspan() - someRows.size();
1266 assumeTableDefaults(aCell);
1267 if ( (aPosition.x + aCell.getRowspan()) > someRows.size() ) {
1268 for (i = 0; i < rowCount; i++) {
1269 row = new Row(columns);
1270 someRows.add(row);
1271 }
1272 }
1273
1274 // reserve cell in rows below
1275 for (i = aPosition.x + 1; i < (aPosition.x + aCell.getRowspan()); i++) {
1276 if ( !((Row) someRows.get(i)).reserve(aPosition.y, aCell.getColspan())) {
1277
1278 // should be impossible to come here :-)
1279 throw new RuntimeException("addCell - error in reserve");
1280 }
1281 }
1282 row = (Row) someRows.get(aPosition.x);
1283 row.addElement(aCell, aPosition.y);
1284
1285 }
1286
1287 /**
1288 * Sets current col/row to valid(empty) pos after addCell/Table
1289 * @param aLocation a location in the Table
1290 */
1291 private void setCurrentLocationToNextValidPosition(Point aLocation) {
1292 // set latest location to next valid position
1293 int i, j;
1294 i = aLocation.x;
1295 j = aLocation.y;
1296 do {
1297 if ( (j + 1) == columns ) { // goto next row
1298 i++;
1299 j = 0;
1300 }
1301 else {
1302 j++;
1303 }
1304 }
1305 while (
1306 (i < rows.size()) && (j < columns) && (((Row) rows.get(i)).isReserved(j))
1307 );
1308 curPosition = new Point(i, j);
1309 }
1310
1311 // public helper methods
1312
1313 /**
1314 * Gets an array with the positions of the borders between every column.
1315 * <P>
1316 * This method translates the widths expressed in percentages into the
1317 * x-coordinate of the borders of the columns on a real document.
1318 *
1319 * @param left this is the position of the first border at the left (cellpadding not included)
1320 * @param totalWidth this is the space between the first border at the left
1321 * and the last border at the right (cellpadding not included)
1322 * @return an array with border positions
1323 */
1324 public float[] getWidths(float left, float totalWidth) {
1325 // for x columns, there are x+1 borders
1326 float[] w = new float[columns + 1];
1327 float wPercentage;
1328 if (locked) {
1329 wPercentage = 100 * width / totalWidth;
1330 }
1331 else {
1332 wPercentage = width;
1333 }
1334 // the border at the left is calculated
1335 switch(alignment) {
1336 case Element.ALIGN_LEFT:
1337 w[0] = left;
1338 break;
1339 case Element.ALIGN_RIGHT:
1340 w[0] = left + (totalWidth * (100 - wPercentage)) / 100;
1341 break;
1342 case Element.ALIGN_CENTER:
1343 default:
1344 w[0] = left + (totalWidth * (100 - wPercentage)) / 200;
1345 }
1346 // the total available width is changed
1347 totalWidth = (totalWidth * wPercentage) / 100;
1348 // the inner borders are calculated
1349 for (int i = 1; i < columns; i++) {
1350 w[i] = w[i - 1] + (widths[i - 1] * totalWidth / 100);
1351 }
1352 // the border at the right is calculated
1353 w[columns] = w[0] + totalWidth;
1354 return w;
1355 }
1356
1357 /**
1358 * Gets an <CODE>Iterator</CODE> of all the <CODE>Row</CODE>s.
1359 *
1360 * @return an <CODE>Iterator</CODE>
1361 */
1362 public Iterator iterator() {
1363 return rows.iterator();
1364 }
1365
1366 /**
1367 * Create a PdfPTable based on this Table object.
1368 * @return a PdfPTable object
1369 * @throws BadElementException
1370 */
1371 public PdfPTable createPdfPTable() throws BadElementException {
1372 if (!convert2pdfptable) {
1373 throw new BadElementException("No error, just an old style table");
1374 }
1375 setAutoFillEmptyCells(true);
1376 complete();
1377 PdfPTable pdfptable = new PdfPTable(widths);
1378 pdfptable.setComplete(complete);
1379 if (isNotAddedYet())
1380 pdfptable.setSkipFirstHeader(true);
1381 pdfptable.setTableEvent(SimpleTable.getDimensionlessInstance(this, cellspacing));
1382 pdfptable.setHeaderRows(lastHeaderRow + 1);
1383 pdfptable.setSplitLate(cellsFitPage);
1384 pdfptable.setKeepTogether(tableFitsPage);
1385 if (!Float.isNaN(offset)) {
1386 pdfptable.setSpacingBefore(offset);
1387 }
1388 pdfptable.setHorizontalAlignment(alignment);
1389 if (locked) {
1390 pdfptable.setTotalWidth(width);
1391 pdfptable.setLockedWidth(true);
1392 }
1393 else {
1394 pdfptable.setWidthPercentage(width);
1395 }
1396 Row row;
1397 for (Iterator iterator = iterator(); iterator.hasNext(); ) {
1398 row = (Row) iterator.next();
1399 Element cell;
1400 PdfPCell pcell;
1401 for (int i = 0; i < row.getColumns(); i++) {
1402 if ((cell = (Element)row.getCell(i)) != null) {
1403 if (cell instanceof Table) {
1404 pcell = new PdfPCell(((Table)cell).createPdfPTable());
1405 }
1406 else if (cell instanceof Cell) {
1407 pcell = ((Cell)cell).createPdfPCell();
1408 pcell.setPadding(cellpadding + cellspacing / 2f);
1409 pcell.setCellEvent(SimpleCell.getDimensionlessInstance((Cell)cell, cellspacing));
1410 }
1411 else {
1412 pcell = new PdfPCell();
1413 }
1414 pdfptable.addCell(pcell);
1415 }
1416 }
1417 }
1418 return pdfptable;
1419 }
1420
1421 /**
1422 * Indicates if this is the first time the section is added.
1423 * @since iText2.0.8
1424 * @return true if the section wasn't added yet
1425 */
1426 public boolean isNotAddedYet() {
1427 return notAddedYet;
1428 }
1429
1430 /**
1431 * Sets the indication if the section was already added to
1432 * the document.
1433 * @since iText2.0.8
1434 * @param notAddedYet
1435 */
1436 public void setNotAddedYet(boolean notAddedYet) {
1437 this.notAddedYet = notAddedYet;
1438 }
1439
1440 /**
1441 * @since iText 2.0.8
1442 * @see com.lowagie.text.LargeElement#flushContent()
1443 */
1444 public void flushContent() {
1445 this.setNotAddedYet(false);
1446 ArrayList headerrows = new ArrayList();
1447 for (int i = 0; i < getLastHeaderRow() + 1; i++) {
1448 headerrows.add(rows.get(i));
1449 }
1450 rows = headerrows;
1451 }
1452
1453 /**
1454 * @since iText 2.0.8
1455 * @see com.lowagie.text.LargeElement#isComplete()
1456 */
1457 public boolean isComplete() {
1458 return complete;
1459 }
1460
1461 /**
1462 * @since iText 2.0.8
1463 * @see com.lowagie.text.LargeElement#setComplete(boolean)
1464 */
1465 public void setComplete(boolean complete) {
1466 this.complete = complete;
1467 }
1468
1469 /**
1470 * Gets the default layout of the Table.
1471 * @return a cell with all the defaults
1472 * @deprecated As of iText 2.0.7, replaced by {@link #getDefaultCell()},
1473 * scheduled for removal at 2.2.0
1474 */
1475 public Cell getDefaultLayout() {
1476 return getDefaultCell();
1477 }
1478
1479 /**
1480 * Sets the default layout of the Table to
1481 * the provided Cell
1482 * @param value a cell with all the defaults
1483 * @deprecated As of iText 2.0.7, replaced by {@link #setDefaultCell(Cell)},
1484 * scheduled for removal at 2.2.0
1485 */
1486 public void setDefaultLayout(Cell value) {
1487 defaultCell = value;
1488 }
1489 }