Save This Page
Home » iText-src-2.1.3 » com.lowagie » text » [javadoc | source]
    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   }

Save This Page
Home » iText-src-2.1.3 » com.lowagie » text » [javadoc | source]