/*
* Copyright 2008-2017 by Emeric Vernat
*
* This file is part of Java Melody.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.bull.javamelody.swing.print;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.table.TableColumnModel;
import com.lowagie.text.BadElementException;
import com.lowagie.text.DocWriter;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.FontFactory;
import com.lowagie.text.HeaderFooter;
import com.lowagie.text.PageSize;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.Table;
import com.lowagie.text.pdf.PdfWriter;
import net.bull.javamelody.I18NAdapter;
import net.bull.javamelody.swing.table.MBasicTable;
/**
* Objet d'impression/export pour Pdf (portrait ou paysage) en utilisant iText.
*
* @author Emeric Vernat
*/
public class MPdfWriter extends MPrinter {
/**
* Icône Adobe Reader.
*/
public static final ImageIcon ADOBE_READER_ICON = new ImageIcon(
MPdfWriter.class.getResource("/icons/adobe acrobat.png"));
private final boolean landscape;
/**
* Objet d'impression/export pour Pdf paysage.
*
* @author Emeric Vernat
*/
public static class LandscapePdfWriter extends MPdfWriter {
/** Constructeur. */
public LandscapePdfWriter() {
super(true);
}
}
/**
* Constructeur.
*/
public MPdfWriter() {
this(false);
}
/**
* Constructeur.
*
* @param myLandscape
* boolean
*/
public MPdfWriter(final boolean myLandscape) {
super();
this.landscape = myLandscape;
}
/**
* Retourne un booléen selon que l'export est en paysage ou en portrait.
*
* @return boolean
*/
public boolean isLandscape() {
return landscape;
}
/**
* Lance l'impression (Méthode abstraite assurant le polymorphisme des instances.).
*
* @param table
* MBasicTable
* @param out
* OutputStream
* @throws IOException
* Erreur disque
*/
@Override
public void print(final MBasicTable table, final OutputStream out) throws IOException {
writePdf(table, out);
}
/**
* Méthode abstraite : les instances doivent renvoyer l'extension du fichier exporté.
*
* @return String
*/
@Override
public String getFileExtension() {
return "pdf";
}
/**
* Méthode abstraite : les instances doivent renvoyer l'icône représentant le type.
*
* @return Icon
*/
@Override
public Icon getIcon() {
return ADOBE_READER_ICON;
}
/**
* Méthode abstraite : les instances doivent renvoyer leur nom.
*
* @return String
*/
@Override
public String getName() {
return I18NAdapter.getString(landscape ? "export_pdf_landscape" : "export_pdf");
}
/**
* Ecrit le pdf.
*
* @param table
* MBasicTable
* @param out
* OutputStream
* @throws IOException
* e
*/
protected void writePdf(final MBasicTable table, final OutputStream out) throws IOException {
try {
// step 1: creation of a document-object
final Rectangle pageSize = landscape ? PageSize.A4.rotate() : PageSize.A4;
final Document document = new Document(pageSize, 50, 50, 50, 50);
// step 2: we create a writer that listens to the document and directs a PDF-stream to out
createWriter(table, document, out);
// we add some meta information to the document, and we open it
document.addAuthor(System.getProperty("user.name"));
document.addCreator("JavaMelody");
final String title = buildTitle(table);
if (title != null) {
document.addTitle(title);
}
document.open();
// ouvre la boîte de dialogue Imprimer de Adobe Reader
// if (writer instanceof PdfWriter) {
// ((PdfWriter) writer).addJavaScript("this.print(true);", false);
// }
// table
final Table datatable = new Table(table.getColumnCount());
datatable.setCellsFitPage(true);
datatable.setPadding(4);
datatable.setSpacing(0);
// headers
renderHeaders(table, datatable);
// data rows
renderList(table, datatable);
document.add(datatable);
// we close the document
document.close();
} catch (final DocumentException e) {
// on ne peut déclarer d'exception autre que IOException en throws
throw new IOException(e);
}
}
/**
* We create a writer that listens to the document and directs a PDF-stream to out
*
* @param table
* MBasicTable
* @param document
* Document
* @param out
* OutputStream
* @return DocWriter
* @throws DocumentException
* e
*/
protected DocWriter createWriter(final MBasicTable table, final Document document,
final OutputStream out) throws DocumentException {
final PdfWriter writer = PdfWriter.getInstance(document, out);
// writer.setViewerPreferences(PdfWriter.PageLayoutTwoColumnLeft);
// title
if (table.getName() != null) {
final HeaderFooter header = new HeaderFooter(new Phrase(table.getName()), false);
header.setAlignment(Element.ALIGN_LEFT);
header.setBorder(Rectangle.NO_BORDER);
document.setHeader(header);
document.addTitle(table.getName());
}
// simple page numbers : x
// HeaderFooter footer = new HeaderFooter(new Phrase(), true);
// footer.setAlignment(Element.ALIGN_RIGHT);
// footer.setBorder(Rectangle.TOP);
// document.setFooter(footer);
// add the event handler for advanced page numbers : x/y
writer.setPageEvent(new AdvancedPageNumberEvents());
return writer;
}
/**
* Effectue le rendu des headers.
*
* @param table
* MBasicTable
* @param datatable
* Table
* @throws BadElementException
* e
*/
protected void renderHeaders(final MBasicTable table, final Table datatable)
throws BadElementException {
final int columnCount = table.getColumnCount();
final TableColumnModel columnModel = table.getColumnModel();
// size of columns
float totalWidth = 0;
for (int i = 0; i < columnCount; i++) {
totalWidth += columnModel.getColumn(i).getWidth();
}
final float[] headerwidths = new float[columnCount];
for (int i = 0; i < columnCount; i++) {
headerwidths[i] = 100f * columnModel.getColumn(i).getWidth() / totalWidth;
}
datatable.setWidths(headerwidths);
datatable.setWidth(100f);
// table header
final com.lowagie.text.Font font = FontFactory.getFont(FontFactory.HELVETICA, 12,
Font.BOLD);
datatable.getDefaultCell().setBorderWidth(2);
datatable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_CENTER);
// datatable.setDefaultCellGrayFill(0.75f);
String text;
Object value;
for (int i = 0; i < columnCount; i++) {
value = columnModel.getColumn(i).getHeaderValue();
text = value != null ? value.toString() : "";
datatable.addCell(new Phrase(text, font));
}
// end of the table header
datatable.endHeaders();
}
/**
* Effectue le rendu de la liste.
*
* @param table
* MBasicTable
* @param datatable
* Table
* @throws BadElementException
* e
*/
protected void renderList(final MBasicTable table, final Table datatable)
throws BadElementException {
final int columnCount = table.getColumnCount();
final int rowCount = table.getRowCount();
// data rows
final Font font = FontFactory.getFont(FontFactory.HELVETICA, 10, Font.NORMAL);
datatable.getDefaultCell().setBorderWidth(1);
datatable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_LEFT);
// datatable.setDefaultCellGrayFill(0);
Object value;
String text;
int horizontalAlignment;
for (int k = 0; k < rowCount; k++) {
for (int i = 0; i < columnCount; i++) {
value = getValueAt(table, k, i);
if (value instanceof Number || value instanceof Date) {
horizontalAlignment = Element.ALIGN_RIGHT;
} else if (value instanceof Boolean) {
horizontalAlignment = Element.ALIGN_CENTER;
} else {
horizontalAlignment = Element.ALIGN_LEFT;
}
datatable.getDefaultCell().setHorizontalAlignment(horizontalAlignment);
text = getTextAt(table, k, i);
datatable.addCell(new Phrase(8, text != null ? text : "", font));
}
}
}
}