nl.dykema.jxmlnote.report.pdf.PdfReport.java Source code

Java tutorial

Introduction

Here is the source code for nl.dykema.jxmlnote.report.pdf.PdfReport.java

Source

/* ******************************************************************************
 *
 *       Copyright 2008-2010 Hans Dijkema
 *
 *   JRichTextEditor 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 3 of 
 *   the License, or (at your option) any later version.
 *
 *   JRichTextEditor 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 JRichTextEditor.  If not, see <http://www.gnu.org/licenses/>.
 *   
 * ******************************************************************************/

package nl.dykema.jxmlnote.report.pdf;

import java.awt.Image;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.text.AttributeSet;
import javax.swing.text.StyleConstants;

import nl.dykema.jxmlnote.document.XMLNoteDocument;
import nl.dykema.jxmlnote.exceptions.DefaultXMLNoteErrorHandler;
import nl.dykema.jxmlnote.interfaces.MarkMarkupProviderMaker;
import nl.dykema.jxmlnote.report.Report;
import nl.dykema.jxmlnote.report.ReportException;
import nl.dykema.jxmlnote.report.XMLNoteToReport;
import nl.dykema.jxmlnote.report.ReportProgressBar.Progress;
import nl.dykema.jxmlnote.report.elements.Cell;
import nl.dykema.jxmlnote.report.elements.Chunk;
import nl.dykema.jxmlnote.report.elements.Paragraph;
import nl.dykema.jxmlnote.report.elements.Rectangle;
import nl.dykema.jxmlnote.report.elements.ReportElement;
import nl.dykema.jxmlnote.report.elements.Tab;
import nl.dykema.jxmlnote.report.elements.Table;
import nl.dykema.jxmlnote.styles.XMLNoteParStyle;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.FontMapper;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfPageEvent;
import com.lowagie.text.pdf.PdfWriter;

public class PdfReport extends Report {

    private PdfWriter _writer;
    private Document _doc;
    private ColumnText _text;
    private float _jpegQuality = 0.9f;
    private FontMapper _mapper;
    private com.lowagie.text.Rectangle _pdfPageSize;
    private Orientation _orientation = Orientation.PORTRAIT;
    private PageSize _pageSize = PageSize.A4;
    private boolean _canceled = false;
    private File fontmapcacheFile = null;
    private InputStream _fontmapcachein = null;
    private OutputStream _fontmapcacheout = null;

    private Hashtable<String, com.lowagie.text.Image> _imageInstances;

    // /////////////////////////////////////////////////////////////////////////////////
    // Support methods
    // /////////////////////////////////////////////////////////////////////////////////

    public com.lowagie.text.Image getImageInstance(String key) {
        return _imageInstances.get(key);
    }

    public void putImageInstance(String key, com.lowagie.text.Image inst) {
        _imageInstances.put(key, inst);
    }

    public boolean hasImageInstance(String key) {
        return _imageInstances.containsKey(key);
    }

    public String toString() {
        Rectangle pr = new Rectangle(0.0f, 0.0f, 0.0f, 0.0f);
        Rectangle mg = new Rectangle(0.0f, 0.0f, 0.0f, 0.0f);
        try {
            mg = getMargins();
            pr = getPageRect();
        } catch (ReportException E) {
        }
        return String.format("PdfReport: PageSize=%s, Margins=%s", pr.toString(), mg.toString());
    }

    public int getPdfAlign(Report.Align a) {
        if (a.equals(Align.LEFT)) {
            return Element.ALIGN_LEFT;
        } else if (a.equals(Align.RIGHT)) {
            return Element.ALIGN_RIGHT;
        } else if (a.equals(Align.CENTER)) {
            return Element.ALIGN_CENTER;
        } else if (a.equals(Align.JUSTIFY)) {
            return Element.ALIGN_JUSTIFIED;
        } else {
            return Element.ALIGN_LEFT;
        }
    }

    public int getAlign(AttributeSet s) {
        if (StyleConstants.getAlignment(s) == StyleConstants.ALIGN_LEFT) {
            return Element.ALIGN_LEFT;
        } else if (StyleConstants.getAlignment(s) == StyleConstants.ALIGN_CENTER) {
            return Element.ALIGN_CENTER;
        } else if (StyleConstants.getAlignment(s) == StyleConstants.ALIGN_RIGHT) {
            return Element.ALIGN_RIGHT;
        } else if (StyleConstants.getAlignment(s) == StyleConstants.ALIGN_JUSTIFIED) {
            return Element.ALIGN_JUSTIFIED;
        } else {
            return Element.ALIGN_LEFT;
        }
    }

    com.lowagie.text.Rectangle getPdfPageSize() {
        return _pdfPageSize;
    }

    public FontMapper getFontMapper() {
        if (_fontmapcacheout != null) {
            try {
                _mapper = PdfFontMapper.createPdfFontMapper(this, _fontmapcachein, _fontmapcacheout);
            } catch (IOException e) {
                DefaultXMLNoteErrorHandler.exception(e);
                _mapper = PdfFontMapper.createPdfFontMapper(this, null);
            }
        } else {
            _mapper = PdfFontMapper.createPdfFontMapper(this, fontmapcacheFile);
        }
        return _mapper;
    }

    public PdfWriter pdfWriter() {
        return _writer;
    }

    public ColumnText text() {
        return _text;
    }

    public Document document() {
        return _doc;
    }

    public float jpegQuality() {
        return _jpegQuality;
    }

    private void checkWriter() throws ReportException {
        if (_writer == null) {
            throw new ReportException("Begin report first");
        }
    }

    private void checkIsNotOpen() throws ReportException {
        checkWriter();
        if (_doc.isOpen()) {
            throw new ReportException(
                    "Implementation specific: Add meta information before the first ReportElement is added");
        }
    }

    private void checkDocOpen() {
        if (!_doc.isOpen()) {
            _doc.open();
        }
    }

    String informStatus(String msg) {
        Progress prg = (Progress) super.getProperty(Report.Property.PROGRESS);
        if (prg != null) {
            return prg.statusMessage(msg);
        } else {
            return msg;
        }
    }

    int informProgress(int p) {
        Progress prg = (Progress) super.getProperty(Report.Property.PROGRESS);
        if (prg != null) {
            return prg.progress(p);
        } else {
            return p;
        }
    }

    // /////////////////////////////////////////////////////////////////////////////////
    // Interface methods
    // /////////////////////////////////////////////////////////////////////////////////

    public void setMetaAuthor(String author) throws ReportException {
        checkIsNotOpen();
        _doc.addAuthor(author);
    }

    public void setMetaTitle(String title) throws ReportException {
        checkIsNotOpen();
        _doc.addTitle(title);
    }

    public void setMetaCreator(String creator) throws ReportException {
        checkIsNotOpen();
        _doc.addCreator(creator);
    }

    public void setMetaCreationDate() throws ReportException {
        checkIsNotOpen();
        _doc.addCreationDate();
    }

    public void setMetaDescription(String description) throws ReportException {
        checkIsNotOpen();
        _doc.addSubject(description);
    }

    public void setMetaKeywords(Vector<String> keys) throws ReportException {
        checkIsNotOpen();
        Iterator<String> it = keys.iterator();
        String comma = "";
        StringBuffer b = new StringBuffer();
        while (it.hasNext()) {
            b.append(comma);
            b.append(it.next());
            comma = ",";
        }
        _doc.addKeywords(b.toString());
    }

    public Chunk createChunk(String txt) {
        return new PdfChunk(this, txt);
    }

    public Chunk createChunk(String txt, boolean bold, boolean italic, boolean underline) throws ReportException {
        Chunk c = new PdfChunk(this, txt);
        c.setBold(bold);
        c.setItalic(italic);
        c.setUnderline(underline);
        return c;
    }

    public Tab createTab(Paragraph itpar) throws ReportException {
        checkWriter();
        return itpar.getNextTab();
    }

    public Chunk createChunk(Image img) throws ReportException {
        return createChunk(img, 100.0f);
    }

    public Chunk createChunk(File imageFile) throws ReportException {
        return createChunk(imageFile, 100.0f);
    }

    public Chunk createChunk(Image img, float scalePercentage) throws ReportException {
        checkWriter();
        return new PdfChunk(this, img, scalePercentage, -1);
    }

    public Chunk createChunk(File imageFile, float scalePercentage) throws ReportException {
        checkWriter();
        return new PdfChunk(this, imageFile, scalePercentage, -1);
    }

    public Chunk createChunkForWidth(Image img, float scaleToWidthInPt) throws ReportException {
        checkWriter();
        return new PdfChunk(this, img, -1.0f, scaleToWidthInPt);
    }

    public Chunk createChunkForWidth(File imageFile, float scaleToWidthInPt) throws ReportException {
        checkWriter();
        return new PdfChunk(this, imageFile, -1.0f, scaleToWidthInPt);
    }

    public Paragraph createParagraph(XMLNoteParStyle style) throws ReportException {
        checkWriter();
        return new PdfParagraph(this, style);
    }

    public Paragraph createParagraph() throws ReportException {
        return createParagraph(null);
    }

    public Table createTable(Report.Align align, float percentageOfWidth, float[] relativeWidths)
            throws ReportException {
        checkWriter();
        return new PdfTable(this, align, percentageOfWidth, relativeWidths);
    }

    public Cell createCell(ReportElement p) throws ReportException {
        checkWriter();
        return new PdfCell(this, p);
    }

    public Cell textCell(XMLNoteParStyle st, String txt) throws ReportException {
        return textCell(st, txt, Report.Align.LEFT);
    }

    public Cell textCell(XMLNoteParStyle st, String txt, Align a) throws ReportException {
        checkWriter();
        return createCell(createParagraph(st).setAlignment(a).add(createChunk(txt)));
    }

    public void beginReport(File output) throws ReportException {
        try {
            _canceled = false;
            _doc = new Document();
            _writer = PdfWriter.getInstance(_doc, new FileOutputStream(output));
            setPageSize(PageSize.A4);
            setOrientation(Orientation.PORTRAIT);
            setMargins(new Rectangle(72.0f, 72.0f, 72.0f, 72.0f));

            _writer.setPageEvent(new PdfPageEvent() {

                public void onChapter(PdfWriter arg0, Document arg1, float arg2, com.lowagie.text.Paragraph arg3) {
                }

                public void onChapterEnd(PdfWriter arg0, Document arg1, float arg2) {
                }

                public void onCloseDocument(PdfWriter arg0, Document arg1) {
                    PdfReport.super.getReportListeners().informEndReport(PdfReport.this);
                }

                public void onGenericTag(PdfWriter arg0, Document arg1, com.lowagie.text.Rectangle arg2,
                        String arg3) {
                }

                public void onOpenDocument(PdfWriter arg0, Document arg1) {
                }

                public void onParagraph(PdfWriter arg0, Document arg1, float arg2) {
                }

                public void onParagraphEnd(PdfWriter arg0, Document arg1, float arg2) {
                }

                public void onSection(PdfWriter arg0, Document arg1, float arg2, int arg3,
                        com.lowagie.text.Paragraph arg4) {
                }

                public void onSectionEnd(PdfWriter arg0, Document arg1, float arg2) {
                }

                public void onStartPage(PdfWriter wrt, Document doc) {
                }

                public void onEndPage(PdfWriter wrt, Document doc) {
                    try {
                        ReportListeners _listeners = PdfReport.super.getReportListeners();
                        _listeners.informNextPage(PdfReport.this);

                        Vector<ReportElement> vhdr = _listeners.getHeader(PdfReport.this);
                        Vector<ReportElement> vftr = _listeners.getFooter(PdfReport.this);

                        PdfContentByte cb = wrt.getDirectContent();

                        // write headers on top of each other
                        if (vhdr != null) {
                            Iterator<ReportElement> it = vhdr.iterator();

                            while (it.hasNext()) {
                                ReportElement hdr = it.next();

                                Rectangle pageSize = PdfReport.this.getPageRect();
                                Rectangle margins = PdfReport.this.getMargins();
                                float ytop = pageSize.top() - margins.top();
                                float hdrHeight = PdfReport.this.getHeight(hdr, null);
                                float rpos = (margins.top() - hdrHeight) / 2;
                                float hytop = ytop + rpos + hdrHeight;

                                if (hdr instanceof PdfTable) {
                                    int firstRow = 0, lastRow = -1;
                                    PdfTable phdr = (PdfTable) hdr;
                                    phdr.writeSelectedRows(firstRow, lastRow, margins.left(), hytop, cb);
                                } else if (hdr instanceof PdfParagraph) {
                                    PdfParagraph ppar = (PdfParagraph) hdr;
                                    ColumnText ct = new ColumnText(cb);
                                    float textWidth = PdfReport.this.getTextWidth();
                                    ct.addElement(ppar);
                                    ct.setSimpleColumn(margins.left(), ytop + rpos, margins.left() + textWidth,
                                            hytop);
                                    ct.go();
                                }
                            }
                        }

                        // write footers on top of each other

                        if (vftr != null) {
                            Iterator<ReportElement> it = vftr.iterator();

                            while (it.hasNext()) {
                                ReportElement ftr = it.next();

                                Rectangle margins = PdfReport.this.getMargins();
                                float ytop = margins.bottom();
                                float hdrHeight = PdfReport.this.getHeight(ftr, null);
                                float rpos = (margins.bottom() - hdrHeight) / 2;
                                float hytop = ytop - rpos;

                                if (ftr instanceof PdfTable) {
                                    int firstRow = 0, lastRow = -1;
                                    PdfTable pftr = (PdfTable) ftr;
                                    pftr.writeSelectedRows(firstRow, lastRow, margins.left(), hytop, cb);
                                } else if (ftr instanceof PdfParagraph) {
                                    PdfParagraph ppar = (PdfParagraph) ftr;
                                    ColumnText ct = new ColumnText(cb);
                                    float textWidth = PdfReport.this.getTextWidth();
                                    ct.addElement(ppar);
                                    ct.setSimpleColumn(margins.left(), rpos, margins.left() + textWidth, hytop);
                                    ct.go();
                                }
                            }
                        }

                    } catch (ReportException e) {
                        DefaultXMLNoteErrorHandler.exception(e);
                    } catch (DocumentException e) {
                        DefaultXMLNoteErrorHandler.exception(e);
                    }

                }

            });

        } catch (Exception e) {
            throw new ReportException(e);
        }
    }

    public void endReport() throws ReportException {
        try {
            if (keeps != null && !keeps.isEmpty()) {
                addToDocument(keeps);
            }
            _doc.close();
            _imageInstances.clear();
        } catch (Exception e) {
            throw new ReportException(e);
        }
    }

    private void setPageAndOrientation() throws ReportException {
        _pdfPageSize = (_pageSize.equals(PageSize.A4)) ? com.lowagie.text.PageSize.A4
                : com.lowagie.text.PageSize.LETTER;
        if (_orientation.equals(Orientation.PORTRAIT)) {
            _doc.setPageSize(_pdfPageSize);
        } else {
            _pdfPageSize = _pdfPageSize.rotate();
            _doc.setPageSize(_pdfPageSize);
        }
    }

    public void setPageSize(PageSize pg) throws ReportException {
        checkWriter();
        _pageSize = pg;
        setPageAndOrientation();
    }

    public void setOrientation(Orientation o) throws ReportException {
        checkWriter();
        _orientation = o;
        setPageAndOrientation();
    }

    public void setMargins(Rectangle m) throws ReportException {
        _doc.setMargins(m.left(), m.right(), m.top(), m.bottom());
    }

    public Rectangle getPageRect() throws ReportException {
        checkWriter();
        return new Rectangle(_pdfPageSize.getLeft(), _pdfPageSize.getTop(), _pdfPageSize.getRight(),
                _pdfPageSize.getBottom());
    }

    public Rectangle getMargins() throws ReportException {
        checkWriter();
        Rectangle pr = getPageRect();
        return new Rectangle(_doc.left(), pr.top() - _doc.top(), pr.right() - _doc.right(), _doc.bottom());
    }

    public float getTextWidth() throws ReportException {
        Rectangle m = getMargins();
        return getPageRect().width() - m.left() - m.right();
    }

    public int getCurrentPageNumber() throws ReportException {
        checkWriter();
        return _writer.getPageNumber();
    }

    private Vector<ReportElement> keeps = null;

    public void add(ReportElement el, boolean keepWithNext) throws ReportException {
        checkWriter();
        checkDocOpen();
        if (keeps == null) {
            keeps = new Vector<ReportElement>();
        }
        if (el instanceof PdfPageBreak) {
            addToDocument(keeps);
            _doc.newPage();
        } else if (el instanceof PdfParagraph) {
            PdfParagraph par = ((PdfParagraph) el);
            XMLNoteParStyle st = par.getStyle();
            //System.out.println("keepwithnext="+st.keepWithNext()+";"+par.getContent().substring(0,Math.min(15, par.getContent().length())).trim());
            if (keepWithNext || st.keepWithNext()) {
                keeps.add(par);
            } else {
                keeps.add(par);
                addToDocument(keeps);
            }
        } else if (el instanceof PdfTable) {
            PdfTable tbl = ((PdfTable) el);
            if (keepWithNext) {
                keeps.add(tbl);
            } else {
                keeps.add(tbl);
                addToDocument(keeps);
            }
        } else {
            throw new ReportException("You are trying to mix Report implementations");
        }
    }

    public void add(ReportElement el) throws ReportException {
        add(el, false);
    }

    public void addPageBreak() throws ReportException {
        add(new PdfPageBreak());
    }

    private void addToDocument(Vector<ReportElement> keeps) throws ReportException {
        float totalHeight = 0.0f;
        Iterator<ReportElement> it = keeps.iterator();
        ReportElement last = keeps.lastElement();
        while (it.hasNext()) {
            totalHeight += getHeight(it.next(), last);
        }
        if (!willFit(totalHeight)) {
            _doc.newPage();
        }
        it = keeps.iterator();
        while (it.hasNext()) {
            ReportElement el = it.next();
            try {
                if (el instanceof PdfParagraph) {
                    _doc.add((PdfParagraph) el);
                } else if (el instanceof PdfTable) {
                    _doc.add((PdfTable) el);
                } else {
                    throw new ReportException("Unknown ReportElement:" + el.getClass().getName());
                }
            } catch (Exception e) {
                throw new ReportException(e);
            }
        }

        keeps.clear();
    }

    private float getHeight(ReportElement el, ReportElement last) throws ReportException {
        try {
            ColumnText ct = new ColumnText(_writer.getDirectContent());
            if (el instanceof PdfParagraph) {
                PdfParagraph par = ((PdfParagraph) el);
                if ((el != last) || (el == last && par.hasImage())) {
                    int status = ColumnText.START_COLUMN;
                    Rectangle m = getMargins();//System.out.println(m);
                    Rectangle p = getPageRect();//System.out.println(p);
                    float leading = par.getLeading();
                    int align = par.getAlignment();
                    ct.setSimpleColumn(m.left(), m.bottom(), p.width() - m.right(), p.height() - m.top(), leading,
                            align); //,Element.ALIGN_JUSTIFIED);
                    ct.addElement(par);
                    float pos = ct.getYLine();
                    status = ct.go(true);
                    float npos = ct.getYLine();
                    return pos - npos;
                } else {
                    float lineheight = par.getFont().getSize() * par.getMultipliedLeading();
                    float threelines = 3 * lineheight;
                    //System.out.println("par:"+par+";lineheight:"+lineheight+";threelines:"+threelines);
                    return threelines;
                }
            } else if (el instanceof PdfTable) {
                PdfTable tbl = ((PdfTable) el);
                int status = ColumnText.START_COLUMN;
                Rectangle m = getMargins();//System.out.println(m);
                Rectangle p = getPageRect();//System.out.println(p);
                float leading = 0.0f; //tbl.getLeading();
                int align = tbl.getHorizontalAlignment();
                ct.setSimpleColumn(m.left(), m.bottom(), p.width() - m.right(), p.height() - m.top(), leading,
                        align); //,Element.ALIGN_JUSTIFIED);
                ct.addElement(tbl);
                float pos = ct.getYLine();
                status = ct.go(true);
                float npos = ct.getYLine();
                return pos - npos;
            } else {
                throw new ReportException("Unknown ReportElement:" + el.getClass().getName());
            }
        } catch (Exception e) {
            throw new ReportException(e);
        }
    }

    public boolean willFit(float height) throws ReportException {
        float ypos = _writer.getVerticalPosition(false);
        float bottomMargin = this.getMargins().bottom();
        if ((ypos - bottomMargin) < height) {
            return false;
        } else {
            return true;
        }
    }

    public void addXMLNote(XMLNoteDocument doc, MarkMarkupProviderMaker maker,
            XMLNoteToReport.MarkTextProvider prov) throws ReportException {
        checkWriter();
        XMLNoteToReport cvt = new XMLNoteToReport(this);
        cvt.addXMLNote(doc, maker, prov);
    }

    public void cancel() throws ReportException {
        checkWriter();
        _canceled = true;
    }

    public boolean canceled() throws ReportException {
        checkWriter();
        return _canceled;
    }

    // /////////////////////////////////////////////////////////////////////////////////
    // Constructors
    // /////////////////////////////////////////////////////////////////////////////////

    public PdfReport(File fontmapcache) {
        fontmapcacheFile = fontmapcache;
        _fontmapcachein = null;
        _fontmapcacheout = null;
        _imageInstances = new Hashtable<String, com.lowagie.text.Image>();
    }

    public PdfReport(InputStream fontmapCacheIn, OutputStream fontmapCacheOut) {
        fontmapcacheFile = null;
        _fontmapcachein = fontmapCacheIn;
        _fontmapcacheout = fontmapCacheOut;
        _imageInstances = new Hashtable<String, com.lowagie.text.Image>();
    }

}