it.eng.spagobi.engines.qbe.crosstable.exporter.CrosstabXLSExporter.java Source code

Java tutorial

Introduction

Here is the source code for it.eng.spagobi.engines.qbe.crosstable.exporter.CrosstabXLSExporter.java

Source

/* SpagoBI, the Open Source Business Intelligence suite
    
 * Copyright (C) 2012 Engineering Ingegneria Informatica S.p.A. - SpagoBI Competency Center
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0, without the "Incompatible With Secondary Licenses" notice. 
 * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package it.eng.spagobi.engines.qbe.crosstable.exporter;

import it.eng.qbe.serializer.SerializationException;
import it.eng.spagobi.engines.qbe.crosstable.CrossTab;
import it.eng.spagobi.engines.qbe.crosstable.CrossTab.CellType;
import it.eng.spagobi.engines.qbe.crosstable.Node;
import it.eng.spagobi.engines.worksheet.bo.MeasureScaleFactorOption;
import it.eng.spagobi.engines.worksheet.services.export.MeasureFormatter;
import it.eng.spagobi.utilities.messages.EngineMessageBundle;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * Exports the crosstab data (formatted as a JSON object in input) into a XLS file.
 * The JSON object should have this structure (a node is {node_key:"Text", node_childs:[...]}):
 *       columns: {...} contains tree node structure of the columns' headers
 *       rows: {...} contains tree node structure of the rows' headers
 *       data: [[...], [...], ...] 2-dimensional matrix containing crosstab data
 * 
 * @author Alberto Ghedin (alberto.ghedin@eng.it), Davide Zerbetto (davide.zerbetto@eng.it)
 */
public class CrosstabXLSExporter {

    /** Logger component. */
    public static transient Logger logger = Logger.getLogger(CrosstabXLSExporter.class);

    /** Configuration properties */
    public static final String PROPERTY_HEADER_FONT_SIZE = "HEADER_FONT_SIZE";
    public static final String PROPERTY_HEADER_COLOR = "HEADER_COLOR";
    public static final String PROPERTY_HEADER_BACKGROUND_COLOR = "HEADER_BACKGROUND_COLOR";
    public static final String PROPERTY_HEADER_BORDER_COLOR = "HEADER_BORDER_COLOR";
    public static final String PROPERTY_CELL_FONT_SIZE = "CELL_FONT_SIZE";
    public static final String PROPERTY_CELL_COLOR = "CELL_COLOR";
    public static final String PROPERTY_CELL_BACKGROUND_COLOR = "CELL_BACKGROUND_COLOR";
    public static final String PROPERTY_CELL_BORDER_COLOR = "CELL_BORDER_COLOR";
    public static final String PROPERTY_DIMENSION_NAME_COLOR = "DIMENSION_NAME_COLOR";
    public static final String PROPERTY_DIMENSION_NAME_BACKGROUND_COLOR = "HEADER_DIMENSION_NAME_BACKGROUND_COLOR";
    public static final String PROPERTY_FONT_NAME = "FONT_NAME";

    public static final String PROPERTY_CALCULATED_FIELD_DECIMALS = "CALCULATED_FIELD_DECIMALS";

    public static final short DEFAULT_HEADER_FONT_SIZE = 8;
    public static final String DEFAULT_HEADER_COLOR = "BLACK";
    public static final String DEFAULT_HEADER_BACKGROUND_COLOR = "GREY_25_PERCENT";
    public static final String DEFAULT_HEADER_BORDER_COLOR = "WHITE";
    public static final short DEFAULT_CELL_FONT_SIZE = 8;
    public static final String DEFAULT_CELL_COLOR = "BLACK";
    public static final String DEFAULT_CELL_BACKGROUND_COLOR = "WHITE";
    public static final String DEFAULT_CELL_BORDER_COLOR = "BLACK";
    public static final String DEFAULT_DIMENSION_NAME_COLOR = "BLACK";
    public static final String DEFAULT_DIMENSION_NAME_BACKGROUND_COLOR = "LIGHT_BLUE";
    public static final String DEFAULT_FONT_NAME = "Verdana";
    public static final int DEFAULT_CALCULATED_FIELD_DECIMALS = 2;

    private Properties properties;

    public CrosstabXLSExporter(Properties properties) {
        super();
        if (properties == null) {
            this.properties = new Properties();
        } else {
            this.properties = properties;
        }

    }

    public void setProperty(String propertyName, Object propertyValue) {
        this.properties.put(propertyName, propertyValue);
    }

    public Object getProperty(String propertyName) {
        return this.properties.get(propertyName);
    }

    public int fillAlreadyCreatedSheet(Sheet sheet, CrossTab cs, JSONObject crosstabJSON,
            CreationHelper createHelper, int startRow, Locale locale) throws JSONException, SerializationException {
        // we enrich the JSON object putting every node the descendants_no
        // property: it is useful when merging cell into rows/columns headers
        // and when initializing the sheet
        int totalRowNum = commonFillSheet(sheet, cs, crosstabJSON, createHelper, startRow, locale);
        return totalRowNum;
    }

    public int commonFillSheet(Sheet sheet, CrossTab cs, JSONObject crosstabJSON, CreationHelper createHelper,
            int startRow, Locale locale) throws SerializationException, JSONException {
        int columnsDepth = cs.getColumnsRoot().getSubTreeDepth();
        int rowsDepth = cs.getRowsRoot().getSubTreeDepth();

        MeasureFormatter measureFormatter = new MeasureFormatter(cs);
        int rowsNumber = cs.getDataMatrix().length;
        // + 1 because there may be also the bottom row with the totals
        int totalRowsNumber = columnsDepth + rowsNumber + 1;
        for (int i = 0; i < totalRowsNumber + 5; i++) {
            sheet.createRow(startRow + i);
        }

        CellStyle memberCellStyle = this.buildHeaderCellStyle(sheet);
        CellStyle dimensionCellStyle = this.buildDimensionCellStyle(sheet);

        // build headers for column first ...
        buildColumnsHeader(sheet, cs, cs.getColumnsRoot().getChilds(), startRow, rowsDepth - 1, createHelper,
                locale, memberCellStyle, dimensionCellStyle);
        // ... then build headers for rows ....
        buildRowsHeaders(sheet, cs, cs.getRowsRoot().getChilds(), columnsDepth - 1 + startRow, 0, createHelper,
                locale, memberCellStyle);
        // then put the matrix data
        buildDataMatrix(sheet, cs, columnsDepth + startRow - 1, rowsDepth - 1, createHelper, measureFormatter);

        buildRowHeaderTitle(sheet, cs, columnsDepth - 2, 0, startRow, createHelper, locale, dimensionCellStyle);

        return startRow + totalRowsNumber;
    }

    /**
     * Sheet initialization. We create as many rows as it is required to contain the crosstab.
     * 
     * @param sheet The XLS sheet
     * @param json The crosstab data (it must have been enriched with the calculateDescendants method)
     * @throws JSONException
     */
    public int initSheet(Sheet sheet, CrossTab cs) throws JSONException {

        int columnsDepth = cs.getColumnsRoot().getSubTreeDepth();
        int rowsNumber = cs.getRowsRoot().getSubTreeDepth();
        // + 1 because there may be also the bottom row with the totals
        int totalRowsNumber = columnsDepth + rowsNumber + 1;
        for (int i = 0; i < totalRowsNumber + 4; i++) {
            sheet.createRow(i);
        }
        return totalRowsNumber + 4;
    }

    protected int buildDataMatrix(Sheet sheet, CrossTab cs, int rowOffset, int columnOffset,
            CreationHelper createHelper, MeasureFormatter measureFormatter) throws JSONException {

        CellStyle cellStyleForNA = buildNACellStyle(sheet);

        Map<Integer, CellStyle> decimalFormats = new HashMap<Integer, CellStyle>();
        int endRowNum = 0;
        for (int i = 0; i < cs.getDataMatrix().length; i++) {
            for (int j = 0; j < cs.getDataMatrix()[0].length; j++) {
                String text = (String) cs.getDataMatrix()[i][j];
                int rowNum = rowOffset + i;
                int columnNum = columnOffset + j;
                Row row = sheet.getRow(rowNum);
                if (row == null) {
                    row = sheet.createRow(rowNum);
                }
                endRowNum = rowNum;
                Cell cell = row.createCell(columnNum);
                try {
                    double value = Double.parseDouble(text);
                    int decimals = measureFormatter.getFormatXLS(i, j);
                    Double valueFormatted = measureFormatter.applyScaleFactor(value, i, j);
                    cell.setCellValue(valueFormatted);
                    cell.setCellType(this.getCellTypeNumeric());
                    cell.setCellStyle(
                            getNumberFormat(decimals, decimalFormats, sheet, createHelper, cs.getCellType(i, j)));
                } catch (NumberFormatException e) {
                    logger.debug("Text " + text + " is not recognized as a number");
                    cell.setCellValue(createHelper.createRichTextString(text));
                    cell.setCellType(this.getCellTypeString());
                    cell.setCellStyle(cellStyleForNA);
                }

            }
        }
        return endRowNum;
    }

    protected int getCellTypeNumeric() {
        return HSSFCell.CELL_TYPE_NUMERIC;
    }

    protected int getCellTypeString() {
        return HSSFCell.CELL_TYPE_STRING;
    }

    public CellStyle buildNACellStyle(Sheet sheet) {
        CellStyle cellStyleForNA = this.buildDataCellStyle(sheet);
        cellStyleForNA.setAlignment(CellStyle.ALIGN_CENTER);
        return cellStyleForNA;
    }

    /**
     * Builds the rows' headers recursively with this order:
     * |-----|-----|-----|
     * |     |     |  3  |
     * |     |     |-----|
     * |     |  2  |  4  |
     * |     |     |-----|
     * |  1  |     |  5  |
     * |     |-----|-----|
     * |     |     |  7  |
     * |     |  6  |-----|
     * |     |     |  8  |
     * |-----|-----|-----|
     * |     |     |  11 |
     * |  9  |  10 |-----|
     * |     |     |  12 |
     * |-----|-----|-----|
     * 
     * @param sheet The sheet of the XLS file
     * @param siblings The siblings nodes of the headers structure
     * @param rowNum The row number where the first sibling must be inserted
     * @param columnNum The column number where the siblings must be inserted
     * @param createHelper The file creation helper
     * @throws JSONException
     */
    protected void buildRowsHeaders(Sheet sheet, CrossTab cs, List<Node> siblings, int rowNum, int columnNum,
            CreationHelper createHelper, Locale locale, CellStyle cellStyle) throws JSONException {
        int rowsCounter = rowNum;

        for (int i = 0; i < siblings.size(); i++) {
            Node aNode = siblings.get(i);
            List<Node> childs = aNode.getChilds();
            Row row = sheet.getRow(rowsCounter);
            Cell cell = row.createCell(columnNum);
            String text = (String) aNode.getDescription();

            if (cs.isMeasureOnRow() && (childs == null || childs.size() <= 0)) {
                //apply the measure scale factor
                text = MeasureScaleFactorOption.getScaledName(text, cs.getMeasureScaleFactor(text), locale);
            }
            cell.setCellValue(createHelper.createRichTextString(text));
            cell.setCellType(this.getCellTypeString());

            cell.setCellStyle(cellStyle);

            int descendants = aNode.getLeafsNumber();
            if (descendants > 1) {
                sheet.addMergedRegion(new CellRangeAddress(rowsCounter, //first row (0-based)
                        rowsCounter + descendants - 1, //last row  (0-based)
                        columnNum, //first column (0-based)
                        columnNum //last column  (0-based)
                ));
            }

            if (childs != null && childs.size() > 0) {
                buildRowsHeaders(sheet, cs, childs, rowsCounter, columnNum + 1, createHelper, locale, cellStyle);
            }
            int increment = descendants > 1 ? descendants : 1;
            rowsCounter = rowsCounter + increment;
        }
    }

    /**
     * Add the title of the columns in the row headers
     * @param sheet
     * @param titles list of titles
     * @param columnHeadersNumber number of column headers
     * @param startColumn first column of the crosstab in the xls
     * @param startRow first row of the crosstab in the xls
     * @param createHelper
     * @throws JSONException
     */
    protected void buildRowHeaderTitle(Sheet sheet, CrossTab cs, int columnHeadersNumber, int startColumn,
            int startRow, CreationHelper createHelper, Locale locale, CellStyle cellStyle) throws JSONException {
        List<String> titles = cs.getRowHeadersTitles();

        if (titles != null) {

            Row row = sheet.getRow(startRow + columnHeadersNumber);
            for (int i = 0; i < titles.size(); i++) {

                Cell cell = row.createCell(startColumn + i);
                String text = titles.get(i);
                cell.setCellValue(createHelper.createRichTextString(text));
                cell.setCellType(this.getCellTypeString());
                cell.setCellStyle(cellStyle);
            }
            if (cs.isMeasureOnRow()) {
                Cell cell = row.createCell(startColumn + titles.size());
                String text = "Measures";
                if (locale != null) {
                    text = EngineMessageBundle.getMessage("worksheet.export.crosstab.header.measures", locale);
                }
                cell.setCellValue(createHelper.createRichTextString(text));
                cell.setCellType(this.getCellTypeString());
                cell.setCellStyle(cellStyle);
            }
        }
    }

    public CellStyle buildDimensionCellStyle(Sheet sheet) {
        CellStyle cellStyle = sheet.getWorkbook().createCellStyle();
        cellStyle.setAlignment(CellStyle.ALIGN_CENTER);
        cellStyle.setVerticalAlignment(CellStyle.ALIGN_CENTER);

        String headerBGColor = (String) this.getProperty(PROPERTY_DIMENSION_NAME_BACKGROUND_COLOR);
        logger.debug("Header background color : " + headerBGColor);
        short backgroundColorIndex = headerBGColor != null ? IndexedColors.valueOf(headerBGColor).getIndex()
                : IndexedColors.valueOf(DEFAULT_DIMENSION_NAME_BACKGROUND_COLOR).getIndex();
        cellStyle.setFillForegroundColor(backgroundColorIndex);

        cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);

        cellStyle.setBorderBottom(CellStyle.BORDER_THIN);
        cellStyle.setBorderLeft(CellStyle.BORDER_THIN);
        cellStyle.setBorderRight(CellStyle.BORDER_THIN);
        cellStyle.setBorderTop(CellStyle.BORDER_THIN);

        String bordeBorderColor = (String) this.getProperty(PROPERTY_HEADER_BORDER_COLOR);
        logger.debug("Header border color : " + bordeBorderColor);
        short borderColorIndex = bordeBorderColor != null ? IndexedColors.valueOf(bordeBorderColor).getIndex()
                : IndexedColors.valueOf(DEFAULT_HEADER_BORDER_COLOR).getIndex();

        cellStyle.setLeftBorderColor(borderColorIndex);
        cellStyle.setRightBorderColor(borderColorIndex);
        cellStyle.setBottomBorderColor(borderColorIndex);
        cellStyle.setTopBorderColor(borderColorIndex);

        Font font = sheet.getWorkbook().createFont();

        Short headerFontSize = (Short) this.getProperty(PROPERTY_HEADER_FONT_SIZE);
        logger.debug("Header font size : " + headerFontSize);
        short headerFontSizeShort = headerFontSize != null ? headerFontSize.shortValue() : DEFAULT_HEADER_FONT_SIZE;
        font.setFontHeightInPoints(headerFontSizeShort);

        String fontName = (String) this.getProperty(PROPERTY_FONT_NAME);
        logger.debug("Font name : " + fontName);
        fontName = fontName != null ? fontName : DEFAULT_FONT_NAME;
        font.setFontName(fontName);

        String color = (String) this.getProperty(PROPERTY_DIMENSION_NAME_COLOR);
        logger.debug("Dimension color : " + color);
        short colorIndex = bordeBorderColor != null ? IndexedColors.valueOf(color).getIndex()
                : IndexedColors.valueOf(DEFAULT_DIMENSION_NAME_COLOR).getIndex();
        font.setColor(colorIndex);

        font.setBoldweight(Font.BOLDWEIGHT_BOLD);
        font.setItalic(true);
        cellStyle.setFont(font);
        return cellStyle;
    }

    public CellStyle buildHeaderCellStyle(Sheet sheet) {
        CellStyle cellStyle = sheet.getWorkbook().createCellStyle();
        cellStyle.setAlignment(CellStyle.ALIGN_LEFT);
        cellStyle.setVerticalAlignment(CellStyle.ALIGN_CENTER);

        String headerBGColor = (String) this.getProperty(PROPERTY_HEADER_BACKGROUND_COLOR);
        logger.debug("Header background color : " + headerBGColor);
        short backgroundColorIndex = headerBGColor != null ? IndexedColors.valueOf(headerBGColor).getIndex()
                : IndexedColors.valueOf(DEFAULT_HEADER_BACKGROUND_COLOR).getIndex();
        cellStyle.setFillForegroundColor(backgroundColorIndex);

        cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);

        cellStyle.setBorderBottom(CellStyle.BORDER_THIN);
        cellStyle.setBorderLeft(CellStyle.BORDER_THIN);
        cellStyle.setBorderRight(CellStyle.BORDER_THIN);
        cellStyle.setBorderTop(CellStyle.BORDER_THIN);

        String bordeBorderColor = (String) this.getProperty(PROPERTY_HEADER_BORDER_COLOR);
        logger.debug("Header border color : " + bordeBorderColor);
        short borderColorIndex = bordeBorderColor != null ? IndexedColors.valueOf(bordeBorderColor).getIndex()
                : IndexedColors.valueOf(DEFAULT_HEADER_BORDER_COLOR).getIndex();

        cellStyle.setLeftBorderColor(borderColorIndex);
        cellStyle.setRightBorderColor(borderColorIndex);
        cellStyle.setBottomBorderColor(borderColorIndex);
        cellStyle.setTopBorderColor(borderColorIndex);

        Font font = sheet.getWorkbook().createFont();

        Short headerFontSize = (Short) this.getProperty(PROPERTY_HEADER_FONT_SIZE);
        logger.debug("Header font size : " + headerFontSize);
        short headerFontSizeShort = headerFontSize != null ? headerFontSize.shortValue() : DEFAULT_HEADER_FONT_SIZE;
        font.setFontHeightInPoints(headerFontSizeShort);

        String fontName = (String) this.getProperty(PROPERTY_FONT_NAME);
        logger.debug("Font name : " + fontName);
        fontName = fontName != null ? fontName : DEFAULT_FONT_NAME;
        font.setFontName(fontName);

        String headerColor = (String) this.getProperty(PROPERTY_HEADER_COLOR);
        logger.debug("Header color : " + headerColor);
        short headerColorIndex = bordeBorderColor != null ? IndexedColors.valueOf(headerColor).getIndex()
                : IndexedColors.valueOf(DEFAULT_HEADER_COLOR).getIndex();
        font.setColor(headerColorIndex);

        font.setBoldweight(Font.BOLDWEIGHT_BOLD);
        cellStyle.setFont(font);
        return cellStyle;
    }

    public CellStyle buildDataCellStyle(Sheet sheet) {
        CellStyle cellStyle = sheet.getWorkbook().createCellStyle();
        cellStyle.setAlignment(CellStyle.ALIGN_RIGHT);
        cellStyle.setVerticalAlignment(CellStyle.ALIGN_CENTER);

        String cellBGColor = (String) this.getProperty(PROPERTY_CELL_BACKGROUND_COLOR);
        logger.debug("Cell background color : " + cellBGColor);
        short backgroundColorIndex = cellBGColor != null ? IndexedColors.valueOf(cellBGColor).getIndex()
                : IndexedColors.valueOf(DEFAULT_CELL_BACKGROUND_COLOR).getIndex();
        cellStyle.setFillForegroundColor(backgroundColorIndex);

        cellStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);

        cellStyle.setBorderBottom(CellStyle.BORDER_THIN);
        cellStyle.setBorderLeft(CellStyle.BORDER_THIN);
        cellStyle.setBorderRight(CellStyle.BORDER_THIN);
        cellStyle.setBorderTop(CellStyle.BORDER_THIN);

        String bordeBorderColor = (String) this.getProperty(PROPERTY_CELL_BORDER_COLOR);
        logger.debug("Cell border color : " + bordeBorderColor);
        short borderColorIndex = bordeBorderColor != null ? IndexedColors.valueOf(bordeBorderColor).getIndex()
                : IndexedColors.valueOf(DEFAULT_CELL_BORDER_COLOR).getIndex();

        cellStyle.setLeftBorderColor(borderColorIndex);
        cellStyle.setRightBorderColor(borderColorIndex);
        cellStyle.setBottomBorderColor(borderColorIndex);
        cellStyle.setTopBorderColor(borderColorIndex);

        Font font = sheet.getWorkbook().createFont();

        Short cellFontSize = (Short) this.getProperty(PROPERTY_CELL_FONT_SIZE);
        logger.debug("Cell font size : " + cellFontSize);
        short cellFontSizeShort = cellFontSize != null ? cellFontSize.shortValue() : DEFAULT_CELL_FONT_SIZE;
        font.setFontHeightInPoints(cellFontSizeShort);

        String fontName = (String) this.getProperty(PROPERTY_FONT_NAME);
        logger.debug("Font name : " + fontName);
        fontName = fontName != null ? fontName : DEFAULT_FONT_NAME;
        font.setFontName(fontName);

        String cellColor = (String) this.getProperty(PROPERTY_CELL_COLOR);
        logger.debug("Cell color : " + cellColor);
        short cellColorIndex = cellColor != null ? IndexedColors.valueOf(cellColor).getIndex()
                : IndexedColors.valueOf(DEFAULT_CELL_COLOR).getIndex();
        font.setColor(cellColorIndex);

        cellStyle.setFont(font);
        return cellStyle;
    }

    /**
     * Builds the columns' headers recursively with this order:
     * |------------------------------------------|
     * |              1              |     9      |
     * |------------------------------------------|
     * |     2     |        5        |     10     |
     * |-----------|-----------------|------------|
     * |  3  |  4  |  6  |  7  |  8  |  11  | 12  |
     * |------------------------------------------|
     * 
     * @param sheet The sheet of the XLS file
     * @param siblings The siblings nodes of the headers structure
     * @param rowNum The row number where the siblings must be inserted
     * @param columnNum The column number where the first sibling must be inserted
     * @param createHelper The file creation helper
     * @param dimensionCellStyle The cell style for cells containing dimensions (i.e. attributes' names)
     * @param memberCellStyle The cell style for cells containing members (i.e. attributes' values)
     * @throws JSONException
     */
    protected void buildColumnsHeader(Sheet sheet, CrossTab cs, List<Node> siblings, int rowNum, int columnNum,
            CreationHelper createHelper, Locale locale, CellStyle memberCellStyle, CellStyle dimensionCellStyle)
            throws JSONException {
        int columnCounter = columnNum;

        for (int i = 0; i < siblings.size(); i++) {
            Node aNode = (Node) siblings.get(i);
            List<Node> childs = aNode.getChilds();
            Row row = sheet.getRow(rowNum);
            Cell cell = row.createCell(columnCounter);
            String text = (String) aNode.getDescription();
            if (!cs.isMeasureOnRow() && (childs == null || childs.size() <= 0)) {
                //apply the measure scale factor
                text = MeasureScaleFactorOption.getScaledName(text, cs.getMeasureScaleFactor(text), locale);
            }

            cell.setCellValue(createHelper.createRichTextString(text));
            cell.setCellType(this.getCellTypeString());
            int descendants = aNode.getLeafsNumber();
            if (descendants > 1) {
                sheet.addMergedRegion(new CellRangeAddress(rowNum, //first row (0-based)
                        rowNum, //last row  (0-based)
                        columnCounter, //first column (0-based)
                        columnCounter + descendants - 1 //last column  (0-based)
                ));
            }

            /*
             * Now we have to set the style properly according to the nature of
             * the node: if it contains the name of a dimension or a member.
             * Since the structure foresees that a list of members follows a
             * dimension, we calculate the position of the node with respect to
             * the leaves; in case it is odd, the cell contains a dimension; in
             * case it is even, the cell contains a dimension.
             */
            int distanceToLeaves = aNode.getDistanceFromLeaves();
            if (!cs.isMeasureOnRow()) {
                distanceToLeaves--;
            }
            boolean isDimensionNameCell = distanceToLeaves > 0 && (distanceToLeaves % 2) == 1;
            if (isDimensionNameCell) {
                cell.setCellStyle(dimensionCellStyle);
            } else {
                cell.setCellStyle(memberCellStyle);
            }

            if (childs != null && childs.size() > 0) {
                buildColumnsHeader(sheet, cs, childs, rowNum + 1, columnCounter, createHelper, locale,
                        memberCellStyle, dimensionCellStyle);
            }
            int increment = descendants > 1 ? descendants : 1;
            columnCounter = columnCounter + increment;
        }
    }

    public CellStyle getNumberFormat(int j, Map<Integer, CellStyle> decimalFormats, Sheet sheet,
            CreationHelper createHelper, CellType celltype) {

        int mapPosition = j;

        if (celltype.equals(CellType.TOTAL)) {
            mapPosition = j + 90000;
        } else if (celltype.equals(CellType.SUBTOTAL)) {
            mapPosition = j + 80000;
        } else if (celltype.equals(CellType.CF)) {
            mapPosition = j + 60000;
        }

        if (decimalFormats.get(mapPosition) != null)
            return decimalFormats.get(mapPosition);

        if (celltype.equals(CellType.CF)) {
            j = this.getCalculatedFieldDecimals();
        }

        String decimals = "";

        for (int i = 0; i < j; i++) {
            decimals += "0";
        }

        CellStyle cellStyle = this.buildDataCellStyle(sheet);
        DataFormat df = createHelper.createDataFormat();
        String format = "#,##0";
        if (decimals.length() > 0) {
            format += "." + decimals;
        }
        cellStyle.setDataFormat(df.getFormat(format));

        if (celltype.equals(CellType.TOTAL)) {
            cellStyle.setFillForegroundColor(IndexedColors.GREY_40_PERCENT.getIndex());
        }
        if (celltype.equals(CellType.CF)) {
            cellStyle.setFillForegroundColor(IndexedColors.DARK_YELLOW.getIndex());
        }
        if (celltype.equals(CellType.SUBTOTAL)) {
            cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        }

        decimalFormats.put(mapPosition, cellStyle);
        return cellStyle;
    }

    public int getCalculatedFieldDecimals() {
        Integer decimals = (Integer) this.getProperty(PROPERTY_CALCULATED_FIELD_DECIMALS);
        if (decimals == null) {
            return DEFAULT_CALCULATED_FIELD_DECIMALS;
        }
        return decimals;
    }

}