Export Tree to PDF or Excel
Neil Lee, Engineer, Potix Corporation
January 14, 2014
ZK 6.0 and later
Introduction
In an earlier small talk, PdfExporter and ExcelExporter utilities were introduced to demonstrate how developers can convert ZK Grid or Listbox to a PDF/Excel document.
This small talk is going to extend that library to handle conversions from ZK Tree to PDF/Excel documents as well.
Demo
Let's first take a look at the source Tree and the resulting output before diving into the codes.
We are exporting the Tree below to PDF and Excel
Usage
The two utilities, PdfExporter and ExcelExporter, have been extended from the previous small talk to also handle ZK Tree. Exporting a Tree to PDF or Excel has similar usage to that of ZK Grid/Listbox. There are two ways that can be utilized to export a tree: either by traversing the Tree component directly, or by using a custom RowRenderer.
Export tree data via traversing the component hierarchy
PdfExporter and ExcelExporter both provide an export method that would take the Tree component as a parameter. The resulting outputs are illustrated in the previous section.
@Command
public void exportTreeToPdf(@BindingParam("ref") Tree tree) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PdfExporter exporter = new PdfExporter();
exporter.export(tree, out);
AMedia amedia = new AMedia("FirstReport.pdf", "pdf", "application/pdf", out.toByteArray());
Filedownload.save(amedia);
out.close();
}
Excel
@Command
public void exportTreeToExcel(@BindingParam("ref") Tree tree) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ExcelExporter exporter = new ExcelExporter();
exporter.export(tree, out);
AMedia amedia = new AMedia("FirstReport.xlsx", "xls", "application/file", out.toByteArray());
Filedownload.save(amedia);
out.close();
}
Export data model via custom renderer
Although exporting data via traversing the component hierarchy is quite straightforward, it does have several limitations. For instance, when ROD (Render on Demand) is enabled, only the expanded part of the tree gets exported as can be seen from the screenshots above. If you need to export the tree in its entirety when ROD is enabled, or if you wish to customize the rendered result, you can use a custom renderer to render the data model to PDF/Excel directly. In the following subsections I will demonstrate the use of a renderer to export the tree.
PdfExporter is based on iText library to create PDF documents, hence, you would need to be familiar with the iText API in order to write a custom renderer effectively. In addition, some wrapper methods are created to assist in writing a custom renderer. Please see the previous small talk for more details.
- Render header/footer using Interceptor interface
@Command
public void exportTreeToPdfByDataModel() throws Exception {
final PdfExporter exporter = new PdfExporter();
...
final String[] headers = new String[]{"Path", "Description", "Size" };
final String[] footers = new String[]{"footer1", "footer2", "footer3" };
exporter.setInterceptor(new Interceptor <PdfPTable> () {
// Render header
@Override
public void beforeRendering(PdfPTable table) {
for (int i = 0; i < headers.length; i++) {
String header = headers[i];
Font font = exporter.getFontFactory().getFont(FontFactory.FONT_TYPE_HEADER);
PdfPCell cell = exporter.getPdfPCellFactory().getHeaderCell();
cell.setPhrase(new Phrase(header, font));
if ("Size".equals(header)) {
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
}
table.addCell(cell);
}
table.completeRow();
}
// Render footer
@Override
public void afterRendering(PdfPTable table) {
for (String footer : footers) {
Font font = exporter.getFontFactory().getFont(FontFactory.FONT_TYPE_FOOTER);
PdfPCell cell = exporter.getPdfPCellFactory().getFooterCell();
cell.setPhrase(new Phrase(footer, font));
table.addCell(cell);
}
table.completeRow();
}
});
...
}
- Obtain tree data to export
It is important to retain the list of tree nodes, not just data itself so that depth information can be inferred in order to perform indentation later.
private List<TreeNode<PackageData>> getTreeData(TreeNode<PackageData> root) {
List<TreeNode<PackageData>> data = new ArrayList<TreeNode<PackageData>>();
List<TreeNode<PackageData>> children = root.getChildren();
for (TreeNode<PackageData> child : children) {
data.add(child);
if (!child.isLeaf())
data.addAll(getTreeData(child));
}
return data;
}
- Indentation
The following two supporting methods are utilized to indent 2 spaces per tree level.
...
private int getLevel(TreeNode<?> node) {
TreeNode<?> parent = node.getParent();
if (parent == null)
return -1;
else
return getLevel(parent) + 1;
}
...
private String indent(int level) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < level; i++)
sb.append(" ");
return sb.toString();
}
- Render contents using RowRenderer
@Command
public void exportTreeToPdfByDataModel() throws Exception {
...
exporter.export(headers.length, getTreeData(_model.getRoot()), new RowRenderer<PdfPTable, TreeNode<PackageData>>() {
...
@Override
public void render(PdfPTable table, TreeNode<PackageData> node, boolean isOddRow) {
Font font = fontFactory.getFont(FontFactory.FONT_TYPE_CELL);
PackageData pkg = node.getData();
PdfPCell cell = cellFactory.getCell(isOddRow);
cell.setPhrase(new Phrase(indent(getLevel(node)) + pkg.getPath(), font));
table.addCell(cell);
cell = cellFactory.getCell(isOddRow);
cell.setPhrase(new Phrase(pkg.getDescription(), font));
table.addCell(cell);
cell = cellFactory.getCell(isOddRow);
cell.setPhrase(new Phrase(pkg.getSize(), font));
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(cell);
table.completeRow();
}
}, out);
...
}
Excel
ExcelExporter is based on Apache POI to create excel documents. Hence, you would need to be familiar with the Apache POI API in order to write a custom renderer effectively. In addition, some wrapper methods are created to assist in writing a custom renderer. Please refer to the quick guide to get started with POI.
- Render header/footer using Interceptor interface
@Command
public void exportTreeToExcelByDataModel() throws Exception {
final ExcelExporter exporter = new ExcelExporter();
final String[] headers = new String[]{"Path", "Description", "Size"};
final String[] footers = new String[]{"footer 1", "footer 2", "footer 3"};
...
exporter.setInterceptor(new Interceptor<XSSFWorkbook>() {
// Render header
@Override
public void beforeRendering(XSSFWorkbook target) {
ExportContext ctx = exporter.getExportContext();
for (String header : headers) {
Cell cell = exporter.getOrCreateCell(ctx.moveToNextCell(), ctx.getSheet());
cell.setCellValue(header);
if ("Size".equals(header)) {
CellStyle srcStyle = cell.getCellStyle();
if (srcStyle.getAlignment() != CellStyle.ALIGN_CENTER) {
XSSFCellStyle newCellStyle = ctx.getSheet().getWorkbook().createCellStyle();
newCellStyle.cloneStyleFrom(srcStyle);
newCellStyle.setAlignment(CellStyle.ALIGN_CENTER);
cell.setCellStyle(newCellStyle);
}
}
}
}
// Render footer
@Override
public void afterRendering(XSSFWorkbook target) {
ExportContext ctx = exporter.getExportContext();
ctx.moveToNextRow();
for (String footer : footers) {
Cell cell = exporter.getOrCreateCell(ctx.moveToNextCell(), ctx.getSheet());
cell.setCellValue(footer);
}
}
});
...
}
- Obtain tree data to export
The source code is the same as that for PDF format.
- Indentation
The source code is the same as that for PDF format.
- Render contents using RowRenderer
@Command
public void exportTreeToExcelByDataModel() throws Exception {
final ExcelExporter exporter = new ExcelExporter();
...
exporter.export(headers.length, getTreeData(_model.getRoot()), new RowRenderer<Row, TreeNode<PackageData>>() {
...
@Override
public void render(Row row, TreeNode<PackageData> node, boolean oddRow) {
ExportContext ctx = exporter.getExportContext();
XSSFSheet sheet = ctx.getSheet();
PackageData pkg = node.getData();
exporter
.getOrCreateCell(ctx.moveToNextCell(), sheet)
.setCellValue(indent(getLevel(node)) + pkg.getPath());
exporter
.getOrCreateCell(ctx.moveToNextCell(), sheet)
.setCellValue(pkg.getDescription());
Cell cell = exporter.getOrCreateCell(ctx.moveToNextCell(), sheet);
cell.setCellValue(pkg.getSize());
CellStyle cellStyle = sheet.getWorkbook().createCellStyle();
cellStyle.setAlignment(CellStyle.ALIGN_CENTER);
cell.setCellStyle(cellStyle);
}
}, out);
...
}
For complete source code, please refer to here
Summary
This small talk shows how easy it is for developers to export ZK Tree to PDF or Excel documents either from the component itself or from the underlying data model directly. Explore the project and enjoy!
Note that the purpose of the article is to demonstrate on how export could be done. 3rd party libraries that being used in the small talk are licensed under their own licensing terms.
Comments
Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License. |