Export Tree to PDF or Excel"

From Documentation
(13 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
{{Template:Smalltalk_Author|
 
{{Template:Smalltalk_Author|
 
|author=Neil Lee, Engineer, Potix Corporation
 
|author=Neil Lee, Engineer, Potix Corporation
|date=January XX, 2014
+
|date=January 14, 2014
 
|version=ZK 6.0 and later
 
|version=ZK 6.0 and later
 
}}
 
}}
Line 9: Line 9:
 
== Introduction ==
 
== Introduction ==
  
In an earlier [http://books.zkoss.org/wiki/Small_Talks/2012/December/Export_Grid_or_Listbox_to_PDF_or_Excel article], the PdfExporter and ExcelExporter utilities were introduced to convert ZK Grid or Listbox to PDF/Excel document.
+
In an earlier [http://books.zkoss.org/wiki/Small_Talks/2012/December/Export_Grid_or_Listbox_to_PDF_or_Excel 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 conversion from ZK Tree to PDF/Excel document as well.
+
This small talk is going to extend that library to handle conversions from ZK Tree to PDF/Excel documents as well.
  
 
==Demo==
 
==Demo==
Line 28: Line 28:
 
== Usage ==
 
== Usage ==
  
=== Export Tree with PdfExporter and ExcelExporter ===
+
The two utilities, <b>PdfExporter</b> and <b>ExcelExporter</b>, 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.
  
The two utilities, <b>PdfExporter</b> and <b>ExcelExporter</b>, have been extended from the previous article to also handle ZK Tree. As you can see in the following sample code, exporting Tree to PDF or Excel with these utilities is the same as for ZK Grid/Listbox. The resulting outputs are demonstrated as the screenshots in the previous section.
+
=== 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.
  
 
==== PDF ====
 
==== PDF ====
 
<source lang="java" high="5,6">
 
<source lang="java" high="5,6">
@Command
+
    @Command
public void exportTreeToPdf(@BindingParam("ref") Tree tree) throws Exception {
+
    public void exportTreeToPdf(@BindingParam("ref") Tree tree) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
+
        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
       
PdfExporter exporter = new PdfExporter();
+
        PdfExporter exporter = new PdfExporter();
exporter.export(tree, out);
+
        exporter.export(tree, out);
+
       
AMedia amedia = new AMedia("FirstReport.pdf", "pdf", "application/pdf", out.toByteArray());
+
        AMedia amedia = new AMedia("FirstReport.pdf", "pdf", "application/pdf", out.toByteArray());
Filedownload.save(amedia);
+
        Filedownload.save(amedia);
out.close();
+
        out.close();
}
+
    }
 
</source>
 
</source>
  
Line 50: Line 52:
  
 
<source lang="java" high="5,6">
 
<source lang="java" high="5,6">
@Command
+
    @Command
public void exportTreeToExcel(@BindingParam("ref") Tree tree) throws Exception {
+
    public void exportTreeToExcel(@BindingParam("ref") Tree tree) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
+
        ByteArrayOutputStream out = new ByteArrayOutputStream();
+
       
ExcelExporter exporter = new ExcelExporter();
+
        ExcelExporter exporter = new ExcelExporter();
exporter.export(tree, out);
+
        exporter.export(tree, out);
+
       
AMedia amedia = new AMedia("FirstReport.xlsx", "xls", "application/file", out.toByteArray());
+
        AMedia amedia = new AMedia("FirstReport.xlsx", "xls", "application/file", out.toByteArray());
Filedownload.save(amedia);
+
        Filedownload.save(amedia);
out.close();
+
        out.close();
}
+
    }
 
</source>
 
</source>
  
=== Export data by Renderer ===
+
=== Export data model via custom renderer ===
  
Although exporting Tree to PDF or Excel format with PdfExporter and ExcelExporter is quite straightforward, it does have several limitation. For instance, when ROD (Render on Demand) is enabled, they can only export the part of the tree that is expanded. 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.
+
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.
  
 
==== PDF ====
 
==== PDF ====
  
<b>PdfExporter</b> is based on iText library to create PDF documents. Please see the previous [http://books.zkoss.org/wiki/Small_Talks/2012/December/Export_Grid_or_Listbox_to_PDF_or_Excel article] for more detail.
+
<b>PdfExporter</b> 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 [http://books.zkoss.org/wiki/Small_Talks/2012/December/Export_Grid_or_Listbox_to_PDF_or_Excel small talk] for more details.
  
 
* Render header/footer using <b>Interceptor</b> interface
 
* Render header/footer using <b>Interceptor</b> interface
  
 
<source lang="java" high="12,29">
 
<source lang="java" high="12,29">
@Command
+
    @Command
 
     public void exportTreeToPdfByDataModel() throws Exception {
 
     public void exportTreeToPdfByDataModel() throws Exception {
    final PdfExporter exporter = new PdfExporter();
+
        final PdfExporter exporter = new PdfExporter();
...
+
        ...    
final String[] headers = new String[]{"Path", "Description", "Size" };
+
        final String[] headers = new String[]{"Path", "Description", "Size" };
final String[] footers = new String[]{"footer1", "footer2", "footer3" };
+
        final String[] footers = new String[]{"footer1", "footer2", "footer3" };
  
exporter.setInterceptor(new Interceptor <PdfPTable> () {
+
        exporter.setInterceptor(new Interceptor <PdfPTable> () {
  
// Render header
+
            // Render header
@Override
+
            @Override
public void beforeRendering(PdfPTable table) {
+
            public void beforeRendering(PdfPTable table) {
for (int i = 0; i < headers.length; i++) {
+
                for (int i = 0; i < headers.length; i++) {
String header = headers[i];
+
                    String header = headers[i];
Font font = exporter.getFontFactory().getFont(FontFactory.FONT_TYPE_HEADER);
+
                    Font font = exporter.getFontFactory().getFont(FontFactory.FONT_TYPE_HEADER);
+
                   
PdfPCell cell = exporter.getPdfPCellFactory().getHeaderCell();
+
                    PdfPCell cell = exporter.getPdfPCellFactory().getHeaderCell();
cell.setPhrase(new Phrase(header, font));
+
                    cell.setPhrase(new Phrase(header, font));
if ("Size".equals(header)) {
+
                    if ("Size".equals(header)) {
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+
                        cell.setHorizontalAlignment(Element.ALIGN_CENTER);
}
+
                    }
table.addCell(cell);
+
                    table.addCell(cell);
}
+
                }
table.completeRow();
+
                table.completeRow();
}
+
            }
+
           
// Render footer
+
            // Render footer
@Override
+
            @Override
public void afterRendering(PdfPTable table) {
+
            public void afterRendering(PdfPTable table) {
for (String footer : footers) {
+
                for (String footer : footers) {
Font font = exporter.getFontFactory().getFont(FontFactory.FONT_TYPE_FOOTER);
+
                    Font font = exporter.getFontFactory().getFont(FontFactory.FONT_TYPE_FOOTER);
+
                   
PdfPCell cell = exporter.getPdfPCellFactory().getFooterCell();
+
                    PdfPCell cell = exporter.getPdfPCellFactory().getFooterCell();
cell.setPhrase(new Phrase(footer, font));
+
                    cell.setPhrase(new Phrase(footer, font));
table.addCell(cell);
+
                    table.addCell(cell);
}
+
                }
table.completeRow();
+
                table.completeRow();
}
+
            }
});
+
        });
...
+
        ...
}
+
    }
 
</source>
 
</source>
  
 
* Obtain tree data to export
 
* Obtain tree data to export
  
It is important to retain the list of tree nodes, not just data themselves so we can infer the depth information of the data in order to perform indentation later.
+
    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.
  
 
<source lang="java">
 
<source lang="java">
 
     private List<TreeNode<PackageData>> getTreeData(TreeNode<PackageData> root) {
 
     private List<TreeNode<PackageData>> getTreeData(TreeNode<PackageData> root) {
    List<TreeNode<PackageData>> data = new ArrayList<TreeNode<PackageData>>();
+
        List<TreeNode<PackageData>> data = new ArrayList<TreeNode<PackageData>>();
   
+
       
    List<TreeNode<PackageData>> children = root.getChildren();
+
        List<TreeNode<PackageData>> children = root.getChildren();
    for (TreeNode<PackageData> child : children) {
+
        for (TreeNode<PackageData> child : children) {
  data.add(child);
+
            data.add(child);
    if (!child.isLeaf())
+
            if (!child.isLeaf())
    data.addAll(getTreeData(child));
+
                data.addAll(getTreeData(child));
    }
+
        }
   
+
       
    return data;
+
        return data;
 
     }
 
     }
 
</source>
 
</source>
Line 138: Line 140:
 
* Indentation
 
* Indentation
  
The following two supporting methods are utilized to indent 2 spaces per tree level.
+
The following two supporting methods are utilized to indent 2 spaces per tree level.
  
<source lang="java">
+
<source lang="java" high="2,10">
...
+
    ...
 
     private int getLevel(TreeNode<?> node) {
 
     private int getLevel(TreeNode<?> node) {
    TreeNode<?> parent = node.getParent();
+
        TreeNode<?> parent = node.getParent();
    if (parent == null)
+
        if (parent == null)
    return -1;
+
            return -1;
    else
+
        else
    return getLevel(parent) + 1;
+
            return getLevel(parent) + 1;
 
     }
 
     }
 
     ...
 
     ...
 
     private String indent(int level) {
 
     private String indent(int level) {
StringBuffer sb = new StringBuffer();
+
        StringBuffer sb = new StringBuffer();
for (int i = 0; i < level; i++)
+
        for (int i = 0; i < level; i++)
sb.append("  ");
+
            sb.append("  ");
return sb.toString();
+
        return sb.toString();
}
+
    }
 
</source>
 
</source>
  
 
* Render contents using RowRenderer
 
* Render contents using RowRenderer
  
<source lang="java">
+
<source lang="java" high="4,8">
@Command
+
    @Command
 
     public void exportTreeToPdfByDataModel() throws Exception {
 
     public void exportTreeToPdfByDataModel() throws Exception {
...
+
        ...    
exporter.export(headers.length, getTreeData(_model.getRoot()), new RowRenderer<PdfPTable, TreeNode<PackageData>>() {
+
        exporter.export(headers.length, getTreeData(_model.getRoot()), new RowRenderer<PdfPTable, TreeNode<PackageData>>() {
+
            ...
private String indent(int level) {
 
StringBuffer sb = new StringBuffer();
 
for (int i = 0; i < level; i++)
 
sb.append("  ");
 
return sb.toString();
 
}
 
  
@Override
+
            @Override
public void render(PdfPTable table, TreeNode<PackageData> node, boolean isOddRow) {
+
            public void render(PdfPTable table, TreeNode<PackageData> node, boolean isOddRow) {
Font font = fontFactory.getFont(FontFactory.FONT_TYPE_CELL);
+
                Font font = fontFactory.getFont(FontFactory.FONT_TYPE_CELL);
+
               
PackageData pkg = node.getData();
+
                PackageData pkg = node.getData();
+
               
PdfPCell cell = cellFactory.getCell(isOddRow);
+
                PdfPCell cell = cellFactory.getCell(isOddRow);
cell.setPhrase(new Phrase(indent(getLevel(node)) + pkg.getPath(), font));
+
                cell.setPhrase(new Phrase(indent(getLevel(node)) + pkg.getPath(), font));
table.addCell(cell);
+
                table.addCell(cell);
+
               
cell = cellFactory.getCell(isOddRow);
+
                cell = cellFactory.getCell(isOddRow);
cell.setPhrase(new Phrase(pkg.getDescription(), font));
+
                cell.setPhrase(new Phrase(pkg.getDescription(), font));
table.addCell(cell);
+
                table.addCell(cell);
+
               
cell = cellFactory.getCell(isOddRow);
+
                cell = cellFactory.getCell(isOddRow);
cell.setPhrase(new Phrase(pkg.getSize(), font));
+
                cell.setPhrase(new Phrase(pkg.getSize(), font));
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
+
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(cell);
+
                table.addCell(cell);
+
               
table.completeRow();
+
                table.completeRow();
}
+
            }
  
}, out);
+
        }, out);
...
+
        ...
 
     }
 
     }
 
</source>
 
</source>
Line 202: Line 198:
 
==== Excel ====
 
==== Excel ====
  
<b>ExcelExporter</b> is based on Apache POI to create excel documents. Please refer to the [http://poi.apache.org/spreadsheet/quick-guide.html quick guide] to get started with POI.
+
<b>ExcelExporter</b> 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 [http://poi.apache.org/spreadsheet/quick-guide.html quick guide] to get started with POI.
  
 
* Render header/footer using <b>Interceptor</b> interface
 
* Render header/footer using <b>Interceptor</b> interface
  
<source lang="java">
+
<source lang="java" high="12,33">
 
     @Command
 
     @Command
 
     public void exportTreeToExcelByDataModel() throws Exception {
 
     public void exportTreeToExcelByDataModel() throws Exception {
final ExcelExporter exporter = new ExcelExporter();
+
        final ExcelExporter exporter = new ExcelExporter();
  
final String[] headers = new String[]{"Path", "Description", "Size"};
+
        final String[] headers = new String[]{"Path", "Description", "Size"};
final String[] footers = new String[]{"footer 1", "footer 2", "footer 3"};
+
        final String[] footers = new String[]{"footer 1", "footer 2", "footer 3"};
...
+
        ...
exporter.setInterceptor(new Interceptor<XSSFWorkbook>() {
+
        exporter.setInterceptor(new Interceptor<XSSFWorkbook>() {
+
           
// Render header
+
            // Render header
@Override
+
            @Override
public void beforeRendering(XSSFWorkbook target) {
+
            public void beforeRendering(XSSFWorkbook target) {
ExportContext ctx = exporter.getExportContext();
+
                ExportContext ctx = exporter.getExportContext();
+
               
for (String header : headers) {
+
                for (String header : headers) {
Cell cell = exporter.getOrCreateCell(ctx.moveToNextCell(), ctx.getSheet());
+
                    Cell cell = exporter.getOrCreateCell(ctx.moveToNextCell(), ctx.getSheet());
cell.setCellValue(header);
+
                    cell.setCellValue(header);
+
                   
if ("Size".equals(header)) {
+
                    if ("Size".equals(header)) {
CellStyle srcStyle = cell.getCellStyle();
+
                        CellStyle srcStyle = cell.getCellStyle();
if (srcStyle.getAlignment() != CellStyle.ALIGN_CENTER) {
+
                        if (srcStyle.getAlignment() != CellStyle.ALIGN_CENTER) {
XSSFCellStyle newCellStyle = ctx.getSheet().getWorkbook().createCellStyle();
+
                            XSSFCellStyle newCellStyle = ctx.getSheet().getWorkbook().createCellStyle();
newCellStyle.cloneStyleFrom(srcStyle);
+
                            newCellStyle.cloneStyleFrom(srcStyle);
newCellStyle.setAlignment(CellStyle.ALIGN_CENTER);
+
                            newCellStyle.setAlignment(CellStyle.ALIGN_CENTER);
cell.setCellStyle(newCellStyle);
+
                            cell.setCellStyle(newCellStyle);
}
+
                        }
}
+
                    }
}
+
                }
}
+
            }
+
           
// Render footer
+
            // Render footer
@Override
+
            @Override
public void afterRendering(XSSFWorkbook target) {
+
            public void afterRendering(XSSFWorkbook target) {
ExportContext ctx = exporter.getExportContext();
+
                ExportContext ctx = exporter.getExportContext();
  
ctx.moveToNextRow();
+
                ctx.moveToNextRow();
for (String footer : footers) {
+
                for (String footer : footers) {
Cell cell = exporter.getOrCreateCell(ctx.moveToNextCell(), ctx.getSheet());
+
                    Cell cell = exporter.getOrCreateCell(ctx.moveToNextCell(), ctx.getSheet());
cell.setCellValue(footer);
+
                    cell.setCellValue(footer);
}
+
                }
}
+
            }
});
+
        });
...
+
        ...
}
+
    }
 
</source>
 
</source>
  
 
* Obtain tree data to export
 
* Obtain tree data to export
  
The source code is the same as that for PDF format.
+
    The source code is the same as that for PDF format.
  
 
* Indentation
 
* Indentation
  
The source code is the same as that for PDF format.
+
    The source code is the same as that for PDF format.
  
 
* Render contents using <b>RowRenderer</b>
 
* Render contents using <b>RowRenderer</b>
  
<source lang="java">
+
<source lang="java" high="8">
 
     @Command
 
     @Command
 
     public void exportTreeToExcelByDataModel() throws Exception {
 
     public void exportTreeToExcelByDataModel() throws Exception {
    final ExcelExporter exporter = new ExcelExporter();
+
        final ExcelExporter exporter = new ExcelExporter();
    ...
+
        ...
exporter.export(headers.length, getTreeData(_model.getRoot()), new RowRenderer<Row, TreeNode<PackageData>>() {
+
        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);
 +
            }
  
private String indent(int level) {
+
        }, out);
StringBuffer sb = new StringBuffer();
+
        ...
for (int i = 0; i < level; i++)
+
    }
sb.append("  ");
 
return sb.toString();
 
}
 
 
@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);
 
...
 
}
 
 
</source>
 
</source>
  
Line 308: Line 297:
 
==Summary==
 
==Summary==
  
In this smalltalk, I have showed it is also easy for developers to export a ZK Tree to PDF or Excel documents either from the component itself or from the underlying data model directly. Explore the [https://github.com/leeyt/exporter project] and enjoy it.
+
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 [https://github.com/leeyt/exporter 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.
  
 
{{Template:CommentedSmalltalk_Footer|
 
{{Template:CommentedSmalltalk_Footer|
 
|name=Potix Corporation
 
|name=Potix Corporation
 
}}
 
}}

Revision as of 04:38, 4 March 2015

DocumentationSmall Talks2014JanuaryExport Tree to PDF or Excel
Export Tree to PDF or Excel

Author
Neil Lee, Engineer, Potix Corporation
Date
January 14, 2014
Version
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
Tree to be exported.png

Resulting PDF
Export Tree to PDF Format.png

Resulting Excel
Export Tree to Excel Format.png

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.

PDF

    @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.

PDF

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.