package org.jboss.seam.excel.exporter; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.faces.component.UIComponent; import javax.faces.component.UIData; import javax.faces.component.UIOutput; import javax.faces.context.FacesContext; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.core.Interpolator; import org.jboss.seam.core.Manager; import org.jboss.seam.document.ByteArrayDocumentData; import org.jboss.seam.document.DocumentData; import org.jboss.seam.document.DocumentStore; import org.jboss.seam.excel.ExcelFactory; import org.jboss.seam.excel.ExcelWorkbook; import org.jboss.seam.excel.ExcelWorkbookException; import org.jboss.seam.excel.css.CSSNames; import org.jboss.seam.excel.css.ColumnStyle; import org.jboss.seam.excel.css.CSSParser; import org.jboss.seam.excel.css.StyleMap; import org.jboss.seam.excel.ui.ExcelComponent; import org.jboss.seam.excel.ui.UICell; import org.jboss.seam.excel.ui.UIColumn; import org.jboss.seam.excel.ui.UIWorkbook; import org.jboss.seam.excel.ui.UIWorksheet; import org.jboss.seam.navigation.Pages; /** * Excel export class that exports a UIData component to an Excel workbook * * @author Nicklas Karlsson (nickarls@gmail.com) * @author Daniel Roth (danielc.roth@gmail.com) * */ @Name("org.jboss.seam.excel.exporter.excelExporter") @Scope(ScopeType.EVENT) @Install(precedence = Install.BUILT_IN) @BypassInterceptors public class ExcelExporter { // The excel workbook implementation private ExcelWorkbook excelWorkbook = null; // A map of known column widths private Map<Integer, Integer> columnWidths = new HashMap<Integer, Integer>(); /** * Helper method to call the exporter and use the default excel workbook * implementation * * @param dataTableId */ public void export(String dataTableId) { export(dataTableId, ""); } /** * Exports the UIData object to Excel workbook. Looks up the component, parse * the templates, iterates the columns and the UIOutput elements within * * @param dataTableId id of data table to export * @param type ExcelWorkbook implementation to use */ @SuppressWarnings("unchecked") public void export(String dataTableId, String type) { excelWorkbook = ExcelFactory.instance().getExcelWorkbook(type); CSSParser parser = new CSSParser(); // Gets the datatable UIData dataTable = (UIData) FacesContext.getCurrentInstance().getViewRoot().findComponent(dataTableId); if (dataTable == null) { throw new ExcelWorkbookException(Interpolator.instance().interpolate("Could not find data table with id #0", dataTableId)); } // Inits the workbook and worksheet UIWorkbook uiWorkbook = new UIWorkbook(); excelWorkbook.createWorkbook(uiWorkbook); UIWorksheet uiWorksheet = new UIWorksheet(); uiWorkbook.getChildren().add(uiWorksheet); uiWorksheet.setStyle(CSSParser.getStyle(dataTable)); uiWorksheet.setStyleClass(CSSParser.getStyleClass(dataTable)); excelWorkbook.createOrSelectWorksheet(uiWorksheet); // Saves the datatable var String dataTableVar = dataTable.getVar(); Object oldValue = FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get(dataTableVar); // Processes the columns List<javax.faces.component.UIColumn> columns = ExcelComponent.getChildrenOfType(dataTable.getChildren(), javax.faces.component.UIColumn.class); columnWidths = parseColumnWidths(uiWorksheet); int col = 0; for (javax.faces.component.UIColumn column : columns) { ColumnStyle columnStyle = new ColumnStyle(parser.getCascadedStyleMap(column)); boolean cssExport = columnStyle.export == null || columnStyle.export; if (column.isRendered() && cssExport) { uiWorksheet.getChildren().add(column); Iterator iterator = UIWorksheet.unwrapIterator(dataTable.getValue()); processColumn(column, iterator, dataTableVar, col++); excelWorkbook.nextColumn(); } } // Restores the data table var if (oldValue == null) { FacesContext.getCurrentInstance().getExternalContext().getRequestMap().remove(dataTableVar); } else { FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put(dataTableVar, oldValue); } // Redirects to the generated document redirectExport(); } /** * Parses column widths from a worksheet tag * * @param worksheet The worksheet to get the style from * @return The map of column number -> column width */ private Map<Integer, Integer> parseColumnWidths(UIWorksheet worksheet) { Map<Integer, Integer> columnWidths = new HashMap<Integer, Integer>(); CSSParser parser = new CSSParser(); StyleMap styleMap = parser.getCascadedStyleMap(worksheet); for (Map.Entry<String, Object> entry : styleMap.entrySet()) { String key = entry.getKey(); if (key.startsWith(CSSNames.COLUMN_WIDTHS)) { String columnIndexString = key.substring(CSSNames.COLUMN_WIDTHS.length()); int columnIndex = Integer.parseInt(columnIndexString); columnWidths.put(columnIndex, (Integer) entry.getValue()); } } return columnWidths; } /** * Puts document in store and redirects */ private void redirectExport() { String viewId = Pages.getViewId(FacesContext.getCurrentInstance()); String baseName = Pages.getCurrentBaseName(); DocumentData documentData = new ByteArrayDocumentData(baseName, excelWorkbook.getDocumentType(), excelWorkbook.getBytes()); String id = DocumentStore.instance().newId(); String url = DocumentStore.instance().preferredUrlForContent(baseName, excelWorkbook.getDocumentType().getExtension(), id); url = Manager.instance().encodeConversationId(url, viewId); DocumentStore.instance().saveData(id, documentData); try { FacesContext.getCurrentInstance().getExternalContext().redirect(url); } catch (IOException e) { throw new ExcelWorkbookException(Interpolator.instance().interpolate("Could not redirect to #0", url), e); } } /** * Processes a datatable column * * @param column The column to parse * @param iterator The iterator to the data * @param var The binding var * @param col */ @SuppressWarnings("unchecked") private void processColumn(javax.faces.component.UIColumn column, Iterator iterator, String var, int columnIndex) { // Process header facet UIComponent headerFacet = column.getFacet(UIColumn.HEADER_FACET_NAME); if (headerFacet != null && UIOutput.class.isAssignableFrom(headerFacet.getClass())) { List<UIOutput> headerOutputs = new ArrayList<UIOutput>(); headerOutputs.add((UIOutput) headerFacet); processOutputs(column, headerOutputs); } // Process data while (iterator.hasNext()) { FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put(var, iterator.next()); List<UIOutput> dataOutputs = ExcelComponent.getChildrenOfType(column.getChildren(), UIOutput.class); processOutputs(column, dataOutputs); } Integer columnWidth = columnWidths.get(columnIndex); if (columnWidth != null) { UIColumn uiColumn = new UIColumn(); uiColumn.setStyle(CSSNames.COLUMN_WIDTH + ":" + columnWidth); excelWorkbook.applyColumnSettings(uiColumn); } } /** * Processes all output type elements (in column) * * @param outputs The list of outputs to process * @param preTemplates The pre-pushed templates */ private void processOutputs(javax.faces.component.UIColumn column, List<UIOutput> outputs) { for (UIOutput output : outputs) { if (!output.isRendered()) { continue; } UICell cell = new UICell(); column.getChildren().add(cell); cell.setId(output.getId()); cell.setValue(output.getValue()); cell.setStyle(CSSParser.getStyle(output)); cell.setStyleClass(CSSParser.getStyleClass(output)); excelWorkbook.addItem(cell); } } }