Java tutorial
/* ****************************************************************************** * * 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>(); } }