uk.co.spudsoft.birt.emitters.excel.handlers.PageHandler.java Source code

Java tutorial

Introduction

Here is the source code for uk.co.spudsoft.birt.emitters.excel.handlers.PageHandler.java

Source

/*************************************************************************************
 * Copyright (c) 2011, 2012, 2013 James Talbut.
 *  jim-emitters@spudsoft.co.uk
 *  
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     James Talbut - Initial implementation.
 ************************************************************************************/

package uk.co.spudsoft.birt.emitters.excel.handlers;

import java.util.Collection;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.HeaderFooter;
import org.apache.poi.ss.usermodel.PrintSetup;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.report.engine.content.IAutoTextContent;
import org.eclipse.birt.report.engine.content.IContent;
import org.eclipse.birt.report.engine.content.IDataContent;
import org.eclipse.birt.report.engine.content.IForeignContent;
import org.eclipse.birt.report.engine.content.IImageContent;
import org.eclipse.birt.report.engine.content.ILabelContent;
import org.eclipse.birt.report.engine.content.IListContent;
import org.eclipse.birt.report.engine.content.IPageContent;
import org.eclipse.birt.report.engine.content.IRowContent;
import org.eclipse.birt.report.engine.content.ITableContent;
import org.eclipse.birt.report.engine.content.ITextContent;
import org.eclipse.birt.report.engine.content.impl.CellContent;
import org.eclipse.birt.report.engine.ir.DimensionType;
import org.eclipse.birt.report.engine.presentation.ContentEmitterVisitor;

import uk.co.spudsoft.birt.emitters.excel.CellImage;
import uk.co.spudsoft.birt.emitters.excel.ClientAnchorConversions;
import uk.co.spudsoft.birt.emitters.excel.Coordinate;
import uk.co.spudsoft.birt.emitters.excel.EmitterServices;
import uk.co.spudsoft.birt.emitters.excel.ExcelEmitter;
import uk.co.spudsoft.birt.emitters.excel.HandlerState;
import uk.co.spudsoft.birt.emitters.excel.StyleManagerUtils;
import uk.co.spudsoft.birt.emitters.excel.framework.Logger;

public class PageHandler extends AbstractHandler {

    public PageHandler(Logger log, IPageContent page) {
        super(log, null, page);
    }

    private void setupPageSize(HandlerState state, IPageContent page) {
        PrintSetup printSetup = state.currentSheet.getPrintSetup();
        printSetup.setPaperSize(state.getSmu().getPaperSizeFromString(page.getPageType()));
        if (page.getOrientation() != null) {
            if ("landscape".equals(page.getOrientation())) {
                printSetup.setLandscape(true);
            }
        }
    }

    private String contentAsString(HandlerState state, Object obj) throws BirtException {

        StringCellHandler stringCellHandler = new StringCellHandler(state.getEmitter(), log, this,
                obj instanceof CellContent ? (CellContent) obj : null);

        state.setHandler(stringCellHandler);

        stringCellHandler.visit(obj);

        state.setHandler(this);

        return stringCellHandler.getString();
    }

    @SuppressWarnings("rawtypes")
    private void processHeaderFooter(HandlerState state, Collection birtHeaderFooter, HeaderFooter poiHeaderFooter)
            throws BirtException {
        boolean handledAsGrid = false;
        for (Object ftrObject : birtHeaderFooter) {
            if (ftrObject instanceof ITableContent) {
                ITableContent ftrTable = (ITableContent) ftrObject;
                if (ftrTable.getChildren().size() == 1) {
                    Object child = ftrTable.getChildren().toArray()[0];
                    if (child instanceof IRowContent) {
                        IRowContent row = (IRowContent) child;
                        if (ftrTable.getColumnCount() <= 3) {
                            Object[] cellObjects = row.getChildren().toArray();
                            if (ftrTable.getColumnCount() == 1) {
                                poiHeaderFooter.setLeft(contentAsString(state, cellObjects[0]));
                                handledAsGrid = true;
                            } else if (ftrTable.getColumnCount() == 2) {
                                poiHeaderFooter.setLeft(contentAsString(state, cellObjects[0]));
                                poiHeaderFooter.setRight(contentAsString(state, cellObjects[1]));
                                handledAsGrid = true;
                            } else if (ftrTable.getColumnCount() == 3) {
                                poiHeaderFooter.setLeft(contentAsString(state, cellObjects[0]));
                                poiHeaderFooter.setCenter(contentAsString(state, cellObjects[1]));
                                poiHeaderFooter.setRight(contentAsString(state, cellObjects[2]));
                                handledAsGrid = true;
                            }
                        }
                    }
                }
            }
            if (!handledAsGrid) {
                poiHeaderFooter.setLeft(contentAsString(state, ftrObject));
            }
        }
    }

    @SuppressWarnings("rawtypes")
    private void outputStructuredHeaderFooter(HandlerState state, Collection birtHeaderFooter)
            throws BirtException {
        ContentEmitterVisitor visitor = new ContentEmitterVisitor(state.getEmitter());
        for (Object content : birtHeaderFooter) {
            if (content instanceof IContent) {
                visitor.visit((IContent) content, null);
            }
        }

    }

    @Override
    public void startPage(HandlerState state, IPageContent page) throws BirtException {

        if (state.getWb().getNumberOfSheets() > 0) {
            if (EmitterServices.booleanOption(state.getRenderOptions(), page, ExcelEmitter.SINGLE_SHEET_PAGE_BREAKS,
                    false)) {
                state.currentSheet.setRowBreak(state.rowNum - 1);
            }
            if (EmitterServices.booleanOption(state.getRenderOptions(), page, ExcelEmitter.SINGLE_SHEET, false)) {
                return;
            }
        }

        state.currentSheet = state.getWb().createSheet();
        log.debug("Page type: ", page.getPageType());

        if (page.getPageType() != null) {
            setupPageSize(state, page);
        }

        if (EmitterServices.booleanOption(state.getRenderOptions(), page, ExcelEmitter.DISPLAYFORMULAS_PROP,
                false)) {
            state.currentSheet.setDisplayFormulas(true);
        }
        if (!EmitterServices.booleanOption(state.getRenderOptions(), page, ExcelEmitter.DISPLAYGRIDLINES_PROP,
                true)) {
            state.currentSheet.setDisplayGridlines(false);
        }
        if (!EmitterServices.booleanOption(state.getRenderOptions(), page, ExcelEmitter.DISPLAYROWCOLHEADINGS_PROP,
                true)) {
            state.currentSheet.setDisplayRowColHeadings(false);
        }
        if (!EmitterServices.booleanOption(state.getRenderOptions(), page, ExcelEmitter.DISPLAYZEROS_PROP, true)) {
            state.currentSheet.setDisplayZeros(false);
        }
        int pagesHigh = EmitterServices.integerOption(state.getRenderOptions(), page, ExcelEmitter.PRINT_PAGES_HIGH,
                -1);
        if ((pagesHigh > 0) && (pagesHigh < Short.MAX_VALUE)) {
            state.currentSheet.getPrintSetup().setFitHeight((short) pagesHigh);
            state.currentSheet.setAutobreaks(true);
        }
        int pagesWide = EmitterServices.integerOption(state.getRenderOptions(), page, ExcelEmitter.PRINT_PAGES_WIDE,
                -1);
        if ((pagesWide > 0) && (pagesWide < Short.MAX_VALUE)) {
            state.currentSheet.getPrintSetup().setFitWidth((short) pagesWide);
            state.currentSheet.setAutobreaks(true);
        }
        int printScale = EmitterServices.integerOption(state.getRenderOptions(), page, ExcelEmitter.PRINT_SCALE,
                -1);
        if ((printScale > 0) && (printScale < Short.MAX_VALUE)) {
            state.currentSheet.getPrintSetup().setScale((short) printScale);
        }

        if (EmitterServices.booleanOption(state.getRenderOptions(), page, ExcelEmitter.STRUCTURED_HEADER, false)) {
            outputStructuredHeaderFooter(state, page.getHeader());
        } else {
            processHeaderFooter(state, page.getHeader(), state.currentSheet.getHeader());
            processHeaderFooter(state, page.getFooter(), state.currentSheet.getFooter());
        }

        state.getSmu().prepareMarginDimensions(state.currentSheet, page);
    }

    private String prepareSheetName(HandlerState state) {
        if (state.sheetName != null) {
            String preparedName = state.sheetName;
            Integer nameCount = state.sheetNames.get(preparedName);
            if (nameCount != null) {
                ++nameCount;
                state.sheetNames.put(preparedName, nameCount);
                preparedName = preparedName + " " + nameCount;
            } else {
                state.sheetNames.put(preparedName, 1);
            }
            return preparedName;
        }
        return null;
    }

    @Override
    public void endPage(HandlerState state, IPageContent page) throws BirtException {

        if (EmitterServices.booleanOption(state.getRenderOptions(), page, ExcelEmitter.SINGLE_SHEET, false)
                && !state.reportEnding) {
            return;
        }

        if (EmitterServices.booleanOption(state.getRenderOptions(), page, ExcelEmitter.STRUCTURED_HEADER, false)) {
            outputStructuredHeaderFooter(state, page.getFooter());
        }

        String sheetName = prepareSheetName(state);
        if (sheetName != null) {
            log.debug("Attempting to name sheet ", (state.getWb().getNumberOfSheets() - 1), " \"", sheetName,
                    "\" ");
            int existingSheetIndex = -1;
            for (int i = 0; i < state.getWb().getNumberOfSheets() - 1; ++i) {
                if (state.getWb().getSheetName(i).equals(sheetName)) {
                    log.debug("Found matching sheet at ", i, " \"", state.getWb().getSheetName(i), "\"");
                    existingSheetIndex = i;
                    break;
                }
            }
            if (existingSheetIndex >= 0) {
                log.debug("Deleting sheet at ", existingSheetIndex, " \"",
                        state.getWb().getSheetName(existingSheetIndex), "\"");
                state.getWb().removeSheetAt(existingSheetIndex);
            }
            state.getWb().setSheetName(state.getWb().getNumberOfSheets() - 1, sheetName);
            if (existingSheetIndex >= 0) {
                state.getWb().setSheetOrder(sheetName, existingSheetIndex);
            }
            state.sheetName = null;
        }
        if (state.sheetPassword != null) {
            log.debug("Attempting to protect sheet ", (state.getWb().getNumberOfSheets() - 1));
            state.currentSheet.protectSheet(state.sheetPassword);
            state.sheetPassword = null;
        }

        Drawing drawing = null;
        if (!state.images.isEmpty()) {
            drawing = state.currentSheet.createDrawingPatriarch();
        }
        for (CellImage cellImage : state.images) {
            processCellImage(state, drawing, cellImage);
        }
        state.images.clear();
        state.rowNum = 0;
        state.colNum = 0;
        state.clearRowSpans();
        state.areaBorders.clear();

        state.currentSheet = null;
    }

    private CellRangeAddress getMergedRegionBegunBy(Sheet sheet, int row, int col) {
        for (int i = 0; i < sheet.getNumMergedRegions(); ++i) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            if ((range.getFirstColumn() == col) && (range.getFirstRow() == row)) {
                return range;
            }
        }
        return null;
    }

    /**
     * <p>
     * Process a CellImage from the images list and place the image on the sheet.
     * </p><p>
     * This involves changing the row height as necesssary and determining the column spread of the image.
     * </p>
     * @param cellImage
     * The image to be placed on the sheet.
     */
    private void processCellImage(HandlerState state, Drawing drawing, CellImage cellImage) {
        Coordinate location = cellImage.location;

        Cell cell = state.currentSheet.getRow(location.getRow()).getCell(location.getCol());

        IImageContent image = cellImage.image;

        StyleManagerUtils smu = state.getSmu();
        float ptHeight = cell.getRow().getHeightInPoints();
        if (image.getHeight() != null) {
            ptHeight = smu.fontSizeInPoints(image.getHeight().toString());
        }

        // Get image width
        int endCol = cell.getColumnIndex();
        double lastColWidth = ClientAnchorConversions
                .widthUnits2Millimetres((short) state.currentSheet.getColumnWidth(endCol)) + 2.0;
        int dx = smu.anchorDxFromMM(lastColWidth, lastColWidth);
        double mmWidth = 0.0;
        if (smu.isAbsolute(image.getWidth())) {
            mmWidth = image.getWidth().convertTo(DimensionType.UNITS_MM);
        } else if (smu.isPixels(image.getWidth())) {
            mmWidth = ClientAnchorConversions.pixels2Millimetres(image.getWidth().getMeasure());
        }
        // Allow image to span multiple columns
        CellRangeAddress mergedRegion = getMergedRegionBegunBy(state.currentSheet, location.getRow(),
                location.getCol());
        if ((cellImage.spanColumns) || (mergedRegion != null)) {
            log.debug("Image size: ", image.getWidth(), " translates as mmWidth = ", mmWidth);
            if (mmWidth > 0) {
                double mmAccumulatedWidth = 0;
                int endColLimit = cellImage.spanColumns ? 256 : mergedRegion.getLastColumn();
                for (endCol = cell.getColumnIndex(); mmAccumulatedWidth < mmWidth
                        && endCol < endColLimit; ++endCol) {
                    lastColWidth = ClientAnchorConversions
                            .widthUnits2Millimetres((short) state.currentSheet.getColumnWidth(endCol)) + 2.0;
                    mmAccumulatedWidth += lastColWidth;
                    log.debug("lastColWidth = ", lastColWidth, "; mmAccumulatedWidth = ", mmAccumulatedWidth);
                }
                if (mmAccumulatedWidth > mmWidth) {
                    mmAccumulatedWidth -= lastColWidth;
                    --endCol;
                    double mmShort = mmWidth - mmAccumulatedWidth;
                    dx = smu.anchorDxFromMM(mmShort, lastColWidth);
                }
            }
        } else {
            float widthRatio = (float) (mmWidth / lastColWidth);
            ptHeight = ptHeight / widthRatio;
        }

        int rowsSpanned = state.findRowsSpanned(cell.getRowIndex(), cell.getColumnIndex());
        float neededRowHeightPoints = ptHeight;

        for (int i = 0; i < rowsSpanned; ++i) {
            int rowIndex = cell.getRowIndex() + 1 + i;
            neededRowHeightPoints -= state.currentSheet.getRow(rowIndex).getHeightInPoints();
        }

        if (neededRowHeightPoints > cell.getRow().getHeightInPoints()) {
            cell.getRow().setHeightInPoints(neededRowHeightPoints);
        }

        // ClientAnchor anchor = wb.getCreationHelper().createClientAnchor();
        ClientAnchor anchor = state.getWb().getCreationHelper().createClientAnchor();
        anchor.setCol1(cell.getColumnIndex());
        anchor.setRow1(cell.getRowIndex());
        anchor.setCol2(endCol);
        anchor.setRow2(cell.getRowIndex() + rowsSpanned);
        anchor.setDx2(dx);
        anchor.setDy2(smu.anchorDyFromPoints(ptHeight, cell.getRow().getHeightInPoints()));
        anchor.setAnchorType(ClientAnchor.MOVE_DONT_RESIZE);
        drawing.createPicture(anchor, cellImage.imageIdx);
    }

    @Override
    public void startList(HandlerState state, IListContent list) throws BirtException {
        state.setHandler(new TopLevelListHandler(log, this, list));
        state.getHandler().startList(state, list);
    }

    @Override
    public void startTable(HandlerState state, ITableContent table) throws BirtException {
        state.setHandler(new TopLevelTableHandler(log, this, table));
        state.getHandler().startTable(state, table);
    }

    @Override
    public void emitText(HandlerState state, ITextContent text) throws BirtException {
        state.setHandler(new TopLevelContentHandler(state.getEmitter(), log, this));
        state.getHandler().emitText(state, text);
    }

    @Override
    public void emitData(HandlerState state, IDataContent data) throws BirtException {
        state.setHandler(new TopLevelContentHandler(state.getEmitter(), log, this));
        state.getHandler().emitData(state, data);
    }

    @Override
    public void emitLabel(HandlerState state, ILabelContent label) throws BirtException {
        state.setHandler(new TopLevelContentHandler(state.getEmitter(), log, this));
        state.getHandler().emitLabel(state, label);
    }

    @Override
    public void emitAutoText(HandlerState state, IAutoTextContent autoText) throws BirtException {
        state.setHandler(new TopLevelContentHandler(state.getEmitter(), log, this));
        state.getHandler().emitAutoText(state, autoText);
    }

    @Override
    public void emitForeign(HandlerState state, IForeignContent foreign) throws BirtException {
        state.setHandler(new TopLevelContentHandler(state.getEmitter(), log, this));
        state.getHandler().emitForeign(state, foreign);
    }

    @Override
    public void emitImage(HandlerState state, IImageContent image) throws BirtException {
        state.setHandler(new TopLevelContentHandler(state.getEmitter(), log, this));
        state.getHandler().emitImage(state, image);
    }

}