com.aryjr.nheengatu.pdf.PDFTable.java Source code

Java tutorial

Introduction

Here is the source code for com.aryjr.nheengatu.pdf.PDFTable.java

Source

/*
 * The Nheengatu Project : a free Java library for HTML  abstraction.
 *
 * Project Info:  http://www.aryjr.com/nheengatu/
 * Project Lead:  Ary Rodrigues Ferreira Junior
 *
 * (C) Copyright 2005, 2006 by Ary Junior
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package com.aryjr.nheengatu.pdf;

import java.util.ArrayList;
import java.util.Iterator;

import com.aryjr.nheengatu.html.Tag;
import com.aryjr.nheengatu.html.Text;
import com.aryjr.nheengatu.util.TagsManager;
import com.lowagie.text.Chunk;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Image;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import java.awt.Color;

/**
 * 
 * A HTML table in a PDF document.
 * 
 * @version $Id: PDFTable.java,v 1.3 2009/08/05 19:02:03 kpf Exp $
 * @author <a href="mailto:junior@aryjr.com">Ary Junior </a>
 * 
 */
public class PDFTable extends PdfPTable {
    private static final String CELLSPACING = "cellspacing";
    private static final String CELLPADDING = "cellpadding";

    private static final String ROWSPAN = "rowspan";

    private static final String COLSPAN = "colspan";

    public PDFTable(final int cols) {
        super(cols);
    }

    public static PDFTable createTable(final Tag htmlTable) throws DocumentException {
        // TODO Do not use <tfoot> tag !!! Inside a <table> only <thead>,
        // <tbody> and <tr>.
        // TODO If you are using a <thead>, you can use only <tbody> inside a
        // <table>.
        // TODO If you do not use <thead>, you can use only <tr>
        int headerRowCount = 0;
        if (htmlTable.getFirstTag("thead") != null || htmlTable.getFirstTag("tbody") != null) {
            // Before I will remove the <thead> and <tbody> tags
            headerRowCount = PDFTable.removeTheadTbody(htmlTable);
        }
        // Now, I will remove all rowspans from table and convert it to
        // nestedTables
        headerRowCount -= PDFTable.removeAllRowspans(htmlTable);
        // Creating the iText table
        PDFTable table;
        final TagsManager tm = TagsManager.getInstance();
        int maxCols = 0;// The max number of cells in this table
        final Iterator rows = htmlTable.tags();
        Tag row;
        while (rows.hasNext()) {
            row = (Tag) rows.next();
            if (maxCols < row.tagsCollection().size()) {
                maxCols = row.tagsCollection().size();
            }
        }
        table = new PDFTable(maxCols);
        table.setHeaderRows(headerRowCount < 0 ? 0 : headerRowCount);
        tm.checkTag(htmlTable);
        final CellWidths cws = new CellWidths();
        PDFTable.createTableRows(htmlTable, htmlTable, table, cws);
        tm.back();
        String align = htmlTable.getPropertyValue("align");
        if (align != null) {
            align = align.toLowerCase();
            if (align.equals("left"))
                table.setHorizontalAlignment(Element.ALIGN_LEFT);
            else if (align.equals("right"))
                table.setHorizontalAlignment(Element.ALIGN_RIGHT);
            else if (align.equals("center"))
                table.setHorizontalAlignment(Element.ALIGN_CENTER);
        }
        final String width = htmlTable.getPropertyValue("width");
        // table.setLockedWidth(true);
        if (width != null && width.indexOf('%') > 0) {
            // TODO what is the reference for the % here? See the method
            // table.setWidthPercentage(float[] , Rectangle).
            table.setWidthPercentage(Float.parseFloat(width.substring(0, width.length() - 1)));
        } else if (width != null) {
            table.setTotalWidth(Float.parseFloat(width));
        }
        return table;
    }

    private static void createTableRows(final Tag htmlTable, final Tag content, final PDFTable table,
            final CellWidths cws) throws DocumentException {
        final TagsManager tm = TagsManager.getInstance();
        final ArrayList rows = content.tagsCollection();
        Tag row;
        ArrayList suggestedCellWidths;
        boolean fCellWidthsAreSet = false;
        for (int inc = 0; inc < rows.size(); inc++) {
            suggestedCellWidths = new ArrayList();
            row = (Tag) rows.get(inc);
            // Inside a "table" only "tr", "tbody" or "thead"!!! Please!!!
            if (!row.getName().equalsIgnoreCase("tr")) {
                continue;
            }
            row.setPropertyValue(PDFTable.CELLSPACING, content.getPropertyValue(PDFTable.CELLSPACING));
            row.setPropertyValue(PDFTable.CELLPADDING, content.getPropertyValue(PDFTable.CELLPADDING));
            tm.checkTag(row);
            PDFTable.createTableRow(table, row, suggestedCellWidths);
            // The columns widths are defined by the first row without colspan
            if (PDFTable.checkRowspanOrColspan(row, PDFTable.COLSPAN) == 0 && !fCellWidthsAreSet) {
                Tag cell = null;
                String width = null;
                int cww = 0;// Cells Without Width
                float sumWidths = 0f;
                if (cws.size() == 0) {
                    for (int i = 0; i < row.tagsCollection().size(); i++) {
                        cws.add(new Float(0f));
                    }
                }
                // All cells with percentage widths or all cells with widths in
                // pixels. It's a iText requirement.
                final Iterator cells = row.tags();
                boolean percentage = false;
                for (int i = 0; i < cws.size() && cells.hasNext(); i++) {
                    cell = (Tag) cells.next();
                    width = cell.getPropertyValue("width");
                    if (width == null) {
                        cww++;
                    } else {
                        if (!percentage) {
                            percentage = width.indexOf('%') > 0;
                        }
                        cws.set(i,
                                new Float(width == null ? 0f
                                        : percentage ? Float.parseFloat(width.substring(0, width.length() - 1))
                                                : Float.parseFloat(width)));
                        sumWidths += ((Float) cws.get(i)).floatValue();
                    }
                }
                // Checking the cells without the width property
                float value;
                if (percentage) {
                    value = (100 - sumWidths) / cww;
                } else {
                    value = 1;
                }
                for (int ic = 0; ic < cws.size(); ic++) {
                    if (((Float) cws.get(ic)).floatValue() == 0f) {
                        cws.set(ic, new Float(value));
                    }
                }
                /*
                 * for (int icc = 0; icc < suggestedCellWidths.size(); icc++) {
                 * if (((Float) cws.get(icc)).floatValue() < ((Float)
                 * suggestedCellWidths.get(icc)).floatValue()) { cws.set(icc,
                 * (Float) suggestedCellWidths.get(icc)); } }
                 */
                // TODO problems here yet
                table.setWidths(cws.toFloatArray());
                fCellWidthsAreSet = true;
            }
            tm.back();
        }
    }

    private static int removeTheadTbody(final Tag table) {
        // Removes the <thead> and <tbody> from a table and returns the number
        // of rows in <thead>
        final Tag thead = table.removeFirstTag("thead");
        final Tag tbody = table.removeFirstTag("tbody");

        Iterator rows;
        Tag row;
        int rowspan = 0;
        if (thead != null) {
            rows = thead.tags();
            while (rows.hasNext()) {
                row = (Tag) rows.next();
                if (thead.getPropertyValue("style") != null) {
                    row.setPropertyValue("style", thead.getPropertyValue("style"));
                }
                table.addTag(row);
                if (PDFTable.checkRowspanOrColspan(row, PDFTable.ROWSPAN) > rowspan) {
                    rowspan = PDFTable.checkRowspanOrColspan(row, PDFTable.ROWSPAN);
                }
            }
        }

        if (tbody != null) {
            rows = tbody.tags();
            while (rows.hasNext()) {
                row = (Tag) rows.next();
                if (tbody.getPropertyValue("style") != null) {
                    row.setPropertyValue("style", tbody.getPropertyValue("style"));
                }
                table.addTag(row);
            }
        }
        return rowspan == 0 ? 1 : rowspan;
    }

    private static int removeAllRowspans(final Tag table) {
        final ArrayList rows = table.tagsCollection();
        // TODO the major rowspan ever on the first row, for now
        final int indRow = 0;
        final Tag row = (Tag) rows.get(indRow);
        final ArrayList cells = row.tagsCollection();
        int rowspan = 0, colspan = 0;
        final int majorRowspan = PDFTable.checkRowspanOrColspan(row, PDFTable.ROWSPAN);
        if (majorRowspan == 0)
            return majorRowspan;
        Tag auxRow, ntdTable, ntdRow;
        final Tag newRow = row.getEmptyCopy();
        Tag cell, newCell, ntdCell;
        ArrayList ntdCells;
        // iterate all <td> tags of the first row
        final int cellsCount = cells.size();
        for (int inc = 0; inc < cellsCount; inc++) {
            cell = row.removeTag(0);
            rowspan = cell.getPropertyValue(PDFTable.ROWSPAN) == null ? 0
                    : Integer.parseInt(cell.getPropertyValue(PDFTable.ROWSPAN));
            // if the <td> tag have the major rowspan
            if (rowspan == majorRowspan) {
                // it will be a <td> of the new line
                cell.removeProperty(PDFTable.ROWSPAN);
                newRow.addTag(cell);
            } else {
                // creating the nested table
                ntdTable = table.getEmptyCopy();
                ntdTable.setPropertyValue("width", "100%");
                ntdRow = row.getEmptyCopy();
                colspan += cell.getPropertyValue(PDFTable.COLSPAN) == null ? 1
                        : Integer.parseInt(cell.getPropertyValue(PDFTable.COLSPAN));
                ntdRow.addTag(cell);
                cells: for (inc++; inc < cellsCount; inc++) {
                    cell = row.removeTag(0);
                    if (cell.getPropertyValue(PDFTable.ROWSPAN) != null
                            && Integer.parseInt(cell.getPropertyValue(PDFTable.ROWSPAN)) == majorRowspan) {
                        row.addTag(cell, 0);
                        inc--;
                        break cells;
                    } else {
                        colspan += cell.getPropertyValue(PDFTable.COLSPAN) == null ? 1
                                : Integer.parseInt(cell.getPropertyValue(PDFTable.COLSPAN));
                        ntdRow.addTag(cell);
                    }
                }
                ntdTable.addTag(ntdRow);
                for (int i = indRow + 1; i < majorRowspan; i++) {
                    ntdRow = row.getEmptyCopy();
                    auxRow = (Tag) rows.get(i);
                    ntdCells = auxRow.tagsCollection();
                    final int ntdCellsCount = ntdCells.size();
                    ntdCells: for (int ic = 0, colspanSum = 0; ic < ntdCellsCount; ic++) {
                        ntdCell = auxRow.removeTag(0);
                        if (colspanSum == colspan) {
                            auxRow.addTag(ntdCell, 0);
                            break ntdCells;
                        } else {
                            colspanSum += ntdCell.getPropertyValue(PDFTable.COLSPAN) == null ? 1
                                    : Integer.parseInt(ntdCell.getPropertyValue(PDFTable.COLSPAN));
                            ntdRow.addTag(ntdCell);
                        }
                    }
                    ntdTable.addTag(ntdRow);
                }
                PDFTable.adjustColspan(ntdTable);
                PDFTable.removeAllRowspans(ntdTable);
                // put the nested table inside a <td> of the new line
                newCell = cell.getEmptyCopy();
                newCell.removeProperty(PDFTable.ROWSPAN);
                newCell.addTag(ntdTable);
                newCell.setPropertyValue("itext-padding", "5f");
                newCell.setPropertyValue("colspan", String.valueOf(colspan));
                newRow.addTag(newCell);
                colspan = 0;
            }
        }
        // removing all rows of rowspan and put the new line
        for (int inc = 0; inc < majorRowspan; inc++) {
            table.removeTag(indRow);
        }
        table.addTag(newRow, indRow);
        return majorRowspan - 1;
    }

    private static void adjustColspan(final Tag table) {
        // Finding the row with the major number of cells
        ArrayList rows = table.tagsCollection();
        int maxCells = 0, ind = 0;
        for (int inc = 0; inc < rows.size(); inc++) {
            if (maxCells < ((Tag) rows.get(inc)).tagsCollection().size()) {
                maxCells = ((Tag) rows.get(inc)).tagsCollection().size();
                ind = inc;
            }
        }
        // Check if that row have colspan
        if (PDFTable.checkRowspanOrColspan((Tag) rows.get(ind), PDFTable.COLSPAN) == 0
                || PDFTable.checkRowspanOrColspan((Tag) rows.get(ind), PDFTable.ROWSPAN) > 0)
            return;
        // Now, reducing the colspan values
        rows = table.tagsCollection();
        Iterator cells;
        Tag cell;
        for (int inc = 0; inc < rows.size(); inc++) {
            cells = ((Tag) rows.get(inc)).tags();
            while (cells.hasNext()) {
                cell = (Tag) cells.next();
                if (cell.getPropertyValue(PDFTable.COLSPAN) != null) {
                    cell.setPropertyValue(PDFTable.COLSPAN,
                            String.valueOf(Integer.parseInt(cell.getPropertyValue(PDFTable.COLSPAN)) / 2));
                    if (Integer.parseInt(cell.getPropertyValue(PDFTable.COLSPAN)) <= 1) {
                        cell.removeProperty(PDFTable.COLSPAN);
                    }
                }
            }
        }
    }

    private static void createTableRow(final PDFTable table, final Tag row, final ArrayList suggestedCellWidths) {
        final TagsManager tm = TagsManager.getInstance();
        final Iterator cells = row.tags();
        Tag htmlCell;
        PdfPCell cell;
        Paragraph pCell;
        try {
            int inc = 0;
            // TODO suggested cell widths only without rowspan
            while (cells.hasNext()) {
                htmlCell = (Tag) cells.next();
                htmlCell.setPropertyValue(PDFTable.CELLSPACING, row.getPropertyValue(PDFTable.CELLSPACING));
                htmlCell.setPropertyValue(PDFTable.CELLPADDING, row.getPropertyValue(PDFTable.CELLPADDING));
                cell = PDFTable.createCell(htmlCell);
                tm.checkTag(htmlCell);
                pCell = new Paragraph();
                // TODO Cell heights problem solved!!! Waiting for a iText
                // solution.
                pCell.setLeading((pCell.getLeading() / 2) + 2);
                //pCell.setLeading((pCell.leading() / 2));
                cell.addElement(pCell);
                if (htmlCell.getPropertyValue("itext-padding") != null) {
                    cell.setPadding(Float.valueOf(htmlCell.getPropertyValue("itext-padding")).floatValue());
                }
                if (htmlCell.getPropertyValue("cellpadding") != null) {
                    cell.setPadding(Float.valueOf(htmlCell.getPropertyValue("cellpadding")).floatValue());
                }
                if (htmlCell.getPropertyValue("cellspacing") != null) {
                    cell.setBorderWidth(Float.valueOf(htmlCell.getPropertyValue("cellspacing")).floatValue());
                }
                final float cellWidth = PDFTable.extractVisibleComponents(htmlCell, cell, pCell, 0f);
                // TODO compare the size of anothers widths
                suggestedCellWidths.add(new Float(cellWidth));
                tm.back();
                table.addCell(cell);
                inc++;
            }
        } catch (final Exception e) {
            e.printStackTrace();
        }
    }

    // TODO for each cell I have a paragraph associated
    private static float extractVisibleComponents(final Tag tag, final PdfPCell cell, final Paragraph paragraph,
            float cellWidth) throws DocumentException {
        final Iterator tags = tag.tags();// tags inside the cell
        Object component;
        final TagsManager tm = TagsManager.getInstance();
        // Seting the HTML row or table background color
        if (tag.getName().equalsIgnoreCase("TD")) {
            cell.setBorderColor(tm.getPreviousState(2).getBgcolor());
            cell.setBorderWidth(tag.getPropertyValue(PDFTable.CELLSPACING) == null ? 1
                    : Integer.parseInt(tag.getPropertyValue(PDFTable.CELLSPACING)));
            //cell.setBackgroundColor(tm.getBgcolor());
            cell.setBackgroundColor(new Color(255, 255, 255));
            cell.setVerticalAlignment(tm.getValign());
            cell.setHorizontalAlignment(tm.getAlign());
            paragraph.setAlignment(tm.getAlign());
        }
        while (tags.hasNext()) {
            component = tags.next();
            if (component instanceof Text) {
                String s = ((Text) component).getText();
                if (s.contains("\\\"")) {
                    s = s.replace("\\\"", "\"");
                    ((Text) component).setText(s);
                }
                // If it's a text, create a iText text component for it
                paragraph.add(PDFText.createChunk((Text) component));
                cellWidth += PDFText.getWidth((Text) component);
            } else if (component instanceof Tag && ((Tag) component).getName().equalsIgnoreCase("br")) {
                // If it's a HTML line break
                paragraph.add("\n");
            } else if (component instanceof Tag && ((Tag) component).getName().equalsIgnoreCase("img")) {
                // If it's a HTML image, create a iText image component for it
                try {
                    final Image img = PDFImage.createImage((Tag) component);
                    //Nato: paragraph.add(new Chunk(img, 0, -2));
                    paragraph.add(new Chunk(img, 0, 0));
                    cellWidth += img.getScaledWidth();
                    // TODO Is there an iText bug here?
                    //if (img.scaledHeight() == 1f) {
                    //cell.setFixedHeight(img.getScaledHeight());
                    //}
                } catch (final Exception e) {
                    e.printStackTrace();
                }
            } else if (component instanceof Tag && ((Tag) component).getName().equalsIgnoreCase("table")) {
                // If it's a HTML table, create a iText table component for it
                try {
                    // TODO the default value of nowrap here will be true or
                    // false??? If true, there is a problem with the cell width
                    cell.setNoWrap(false);
                    final PDFTable t = PDFTable.createTable((Tag) component);
                    cell.addElement(t);
                    final float[] cw = t.getWidths();
                    for (final float element : cw) {
                        cellWidth += element;
                    }
                } catch (final Exception e) {
                    e.printStackTrace();
                }
            } else if (component instanceof Tag && ((Tag) component).getName().equalsIgnoreCase("select")) {
                // If it's a HTML select field, I will get only the selected
                // option
                final Tag select = (Tag) component;
                Tag opt;
                tm.checkTag(select);
                final Iterator opts = select.tags();
                boolean selected = false;
                while (opts.hasNext()) {
                    opt = (Tag) opts.next();
                    if (opt.getPropertyValue("selected") != null) {
                        tm.checkTag(opt);
                        cellWidth = PDFTable.extractVisibleComponents(opt, cell, paragraph, cellWidth);
                        selected = true;
                        break;
                    }
                }
                if (!selected) {
                    // if none option have the selected attribute the first will
                    // be shown
                    opt = select.getFirstTag("option");
                    tm.checkTag(opt);
                    cellWidth = PDFTable.extractVisibleComponents(opt, cell, paragraph, cellWidth);
                }
            } else {
                // If it's an another tag, check the name and call this method
                // again
                tm.checkTag((Tag) component);
                cellWidth = PDFTable.extractVisibleComponents((Tag) component, cell, paragraph, cellWidth);
                tm.back();
            }
        }
        return cellWidth;
    }

    private static PdfPCell createCell(final Tag ref) {
        final PdfPCell cell = new PdfPCell();
        cell.setBorderWidth(ref.getPropertyValue(PDFTable.CELLSPACING) == null ? 1
                : Integer.parseInt(ref.getPropertyValue(PDFTable.CELLSPACING)));
        cell.setPadding(ref.getPropertyValue(PDFTable.CELLPADDING) == null ? 1
                : Integer.parseInt(ref.getPropertyValue(PDFTable.CELLPADDING)));
        cell.setColspan(Integer.parseInt(
                ref.getPropertyValue(PDFTable.COLSPAN) == null ? "0" : ref.getPropertyValue(PDFTable.COLSPAN)));
        cell.setNoWrap(ref.getPropertyValue("nowrap") != null);
        return cell;
    }

    private static int checkRowspanOrColspan(final Tag row, final String which) {
        // Returns the major rowspan
        final Iterator cells = row.tags();
        int rowspan = 0, next;
        Tag cell;
        while (cells.hasNext()) {
            cell = (Tag) cells.next();
            next = cell.getPropertyValue(which) == null ? 0 : Integer.parseInt(cell.getPropertyValue(which));
            if (rowspan < next) {
                rowspan = next;
            }
        }
        return rowspan;
    }

    public float[] getWidths() {
        return relativeWidths;
    }

}
/**
 * 
 * $Log: PDFTable.java,v $
 * Revision 1.3  2009/08/05 19:02:03  kpf
 * Esta atualizao resolve o seuinte problema:
 *
 * - O braso no est aparecendo quando se pede para visualizar a impresso de um memorando recm criado.
 *
 * Revision 1.2  2009/07/30 14:43:36  kpf
 * Mudana de pacote: itext v.1.4 para itext v 2.1.5.
 *
 * Alteraes para suportar a nova  verso do text 2.1.5
 *
 * Revision 1.1  2007/12/26 15:57:41  tah
 * *** empty log message ***
 *
 * Revision 1.10  2007/06/29 16:20:45  tah
 * *** empty log message ***
 *
 * Revision 1.9  2006/12/12 20:23:27  tah
 * *** empty log message ***
 *
 * Revision 1.8  2006/10/20 15:48:13  tah
 * *** empty log message ***
 *
 * Revision 1.7  2006/08/04 17:30:54  tah
 * *** empty log message ***
 *
 * Revision 1.6  2006/07/05 16:00:47  nts
 * Refatorando para melhorar qualidade do cdigo
 *
 * Revision 1.5  2006/05/23 19:35:06  tah
 * *** empty log message ***
 *
 * Revision 1.4  2006/05/22 19:29:49  tah
 * *** empty log message ***
 *
 * Revision 1.3  2006/04/11 19:43:46  tah
 * *** empty log message ***
 * Revision 1.2 2006/04/05 17:55:53 tah *** empty log
 * message ***
 * 
 * Revision 1.1 2006/04/03 21:30:42 tah Utilizando o nheengatu Revision 1.46
 * 2006/01/06 15:49:38 aryjr <thead> and rowspan together OK!!!
 * 
 * Revision 1.45 2006/01/06 14:13:19 aryjr Cell widths OK!!!
 * 
 * Revision 1.44 2006/01/06 13:02:18 aryjr ROWSPAN working OK. Now I will solve
 * the cell widths problem.
 * 
 * Revision 1.43 2006/01/06 03:28:33 aryjr ROWSPAN!!!
 * 
 * Revision 1.42 2006/01/05 15:29:22 aryjr Working with ROWSPAN again!!!
 * 
 * Revision 1.41 2006/01/04 01:21:37 aryjr Bugs
 * 
 * Revision 1.40 2006/01/03 15:38:39 aryjr Fixing many bugs.
 * 
 * Revision 1.39 2006/01/03 13:37:13 aryjr Rowspan OK!!! I think... :-P
 * 
 * Revision 1.38 2006/01/03 03:24:49 aryjr *** empty log message ***
 * 
 * Revision 1.37 2006/01/02 15:24:23 aryjr ROWSPAN!!!!!
 * 
 * Revision 1.36 2006/01/02 02:44:52 aryjr ROWSPAN!!!
 * 
 * Revision 1.35 2006/01/01 13:37:17 aryjr Rowspan is almost finished.
 * 
 * Revision 1.34 2005/12/31 19:24:31 aryjr Rowspan is almost ready.
 * 
 * Revision 1.33 2005/12/30 20:39:32 aryjr Rowspan!!!!
 * 
 * Revision 1.32 2005/12/22 20:28:11 aryjr Working with the "rowspan" support.
 * 
 * Revision 1.31 2005/12/22 15:15:19 aryjr Fixed many bugs.
 * 
 * Revision 1.30 2005/12/21 15:00:28 aryjr The "br" HTML tag support is OK.
 * 
 * Revision 1.29 2005/12/21 13:34:55 aryjr Nested tables OK and nowrap not OK
 * yet.
 * 
 * Revision 1.28 2005/12/21 13:29:20 aryjr Nested table OK! The new problem is
 * the "nowrap" on cells.
 * 
 * Revision 1.27 2005/12/20 15:11:13 aryjr Nested tables!!!
 * 
 * Revision 1.26 2005/12/20 13:26:20 aryjr Fixed a bug with rowspan.
 * 
 * Revision 1.25 2005/12/19 15:17:07 aryjr Breaking lines when Images and text
 * are inside the same paragraphs not yet solved.
 * 
 * Revision 1.24 2005/12/19 12:34:46 aryjr Fixed a bug related with the cell
 * width.
 * 
 * Revision 1.23 2005/12/16 20:38:12 aryjr Cell widths without rowspan OK!!!
 * 
 * Revision 1.22 2005/12/16 14:07:39 aryjr Problem with cell heights solved!!!
 * 
 * Revision 1.21 2005/12/16 14:06:31 aryjr Problem with cell heights solved!!!
 * 
 * Revision 1.20 2005/12/15 14:09:15 aryjr Cell heights.
 * 
 * Revision 1.19 2005/12/15 13:42:29 aryjr Back to 1.16 version of
 * PDFTable.java.
 * 
 * Revision 1.18 2005/12/15 12:12:12 aryjr Correcting many bugs.
 * 
 * Revision 1.17 2005/12/10 13:53:20 aryjr *** empty log message ***
 * 
 * Revision 1.16 2005/12/09 20:42:22 aryjr Cell heights!!!
 * 
 * Revision 1.15 2005/12/08 14:02:54 aryjr Fighting with the cell height!!!
 * 
 * Revision 1.14 2005/12/07 17:34:01 aryjr Fighting with the cell height!!!
 * 
 * Revision 1.13 2005/12/07 16:24:30 aryjr Working with the select HTML form
 * field.
 * 
 * Revision 1.12 2005/12/07 14:49:50 aryjr Bugs with the relatorio.jsp HTML
 * code.
 * 
 * Revision 1.11 2005/12/07 00:48:09 aryjr *** empty log message ***
 * 
 * Revision 1.10 2005/12/01 14:34:17 aryjr Problems with inner tables.
 * 
 * Revision 1.9 2005/11/30 15:42:45 aryjr Problems with inner tables.
 * 
 * Revision 1.8 2005/11/25 18:18:41 aryjr Page break OK!!!
 * 
 * Revision 1.7 2005/11/22 14:51:59 aryjr Problemas com os formularios do site
 * assetline.
 * 
 * Revision 1.6 2005/11/18 18:53:57 aryjr Rowspan OK!!! By now :-).
 * 
 * Revision 1.5 2005/11/18 15:10:53 aryjr Problems with rowspan. Revision 1.4
 * 2005/11/17 14:49:30 aryjr Cell widths OK!!! By now :-P
 * 
 * Revision 1.3 2005/11/16 15:37:13 aryjr Larguras das celulas.
 * 
 * Revision 1.2 2005/11/14 14:37:34 aryjr Grouping components inside a div tag.
 * 
 * Revision 1.1 2005/11/14 12:17:30 aryjr Renomeando os pacotes.
 * 
 * Revision 1.2 2005/09/26 19:41:13 aryjr Aproveitando a greve para voltar a
 * atividade.
 * 
 * Revision 1.1 2005/09/10 23:43:40 aryjr Passando para o java.net.
 * 
 * Revision 1.12 2005/07/02 01:18:56 aryjunior Site do projeto.
 * 
 * Revision 1.11 2005/06/11 17:40:33 aryjunior Larguras das celulas OK!!!
 * 
 * Revision 1.10 2005/06/05 04:21:17 aryjunior Larguras das celulas +- OK!!! O
 * snapshot ainda esta com problemas.
 * 
 * Revision 1.9 2005/06/05 00:20:31 aryjunior Tentando melhorar o algoritmo de
 * criacao da tabela,
 * 
 * Revision 1.8 2005/06/04 13:29:25 aryjunior LGPL.
 * 
 * Revision 1.7 2005/06/04 04:29:55 aryjunior Largura das tabelas e celulas,
 * ainda nao terminei.
 * 
 * Revision 1.6 2005/06/04 02:24:35 aryjunior Testes com o snapshot. Um .jsp com
 * um HTML mais complexo.
 * 
 * Revision 1.5 2005/05/30 05:28:48 aryjunior Ajustando alguns javadocs.
 * 
 * Revision 1.4 2005/05/30 05:08:25 aryjunior Testes com tabelas aninhadas e
 * cellspacing OK!!!
 * 
 * Revision 1.3 2005/05/30 01:55:56 aryjunior Alguns detalhes no cabecalho dos
 * arquivos e fazendo alguns testes com tabelas ainhadas.
 * 
 * Revision 1.2 2005/05/28 23:21:41 aryjunior Corrigindo o cabecalho.
 * 
 * Revision 1.1.1.1 2005/05/28 21:10:32 aryjunior Initial import.
 * 
 */