Package org.pentaho.reporting.engine.classic.core.modules.output.table.xls.helper

Source Code of org.pentaho.reporting.engine.classic.core.modules.output.table.xls.helper.ExcelPrinter

/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors..  All rights reserved.
*/

package org.pentaho.reporting.engine.classic.core.modules.output.table.xls.helper;

import java.awt.Image;
import java.awt.Shape;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.pentaho.reporting.engine.classic.core.AttributeNames;
import org.pentaho.reporting.engine.classic.core.DefaultImageReference;
import org.pentaho.reporting.engine.classic.core.ImageContainer;
import org.pentaho.reporting.engine.classic.core.InvalidReportStateException;
import org.pentaho.reporting.engine.classic.core.layout.model.LogicalPageBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderNode;
import org.pentaho.reporting.engine.classic.core.layout.output.LogicalPageKey;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorFeature;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorMetaData;
import org.pentaho.reporting.engine.classic.core.layout.output.RenderUtility;
import org.pentaho.reporting.engine.classic.core.modules.output.table.base.AbstractTableOutputProcessor;
import org.pentaho.reporting.engine.classic.core.modules.output.table.base.CellBackground;
import org.pentaho.reporting.engine.classic.core.modules.output.table.base.CellBackgroundProducer;
import org.pentaho.reporting.engine.classic.core.modules.output.table.base.CellMarker;
import org.pentaho.reporting.engine.classic.core.modules.output.table.base.SheetLayout;
import org.pentaho.reporting.engine.classic.core.modules.output.table.base.TableContentProducer;
import org.pentaho.reporting.engine.classic.core.modules.output.table.base.TableRectangle;
import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictBounds;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictGeomUtility;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
import org.pentaho.reporting.libraries.resourceloader.factory.drawable.DrawableWrapper;

public class ExcelPrinter extends ExcelPrinterBase
{
  private static final Log logger = LogFactory.getLog(ExcelPrinter.class);

  private OutputStream outputStream;
  private Workbook workbook;
  private Sheet sheet;
  private CellBackgroundProducer cellBackgroundProducer;
  private ExcelTextExtractor textExtractor;
  private ResourceManager resourceManager;

  public ExcelPrinter(final OutputStream outputStream, final ResourceManager resourceManager)
  {
    if (outputStream == null)
    {
      throw new NullPointerException();
    }
    if (resourceManager == null)
    {
      throw new NullPointerException();
    }
    this.resourceManager = resourceManager;
    this.outputStream = outputStream;
  }

  public void init(final OutputProcessorMetaData metaData)
  {
    if (metaData == null)
    {
      throw new NullPointerException();
    }

    super.init(metaData, resourceManager);
    this.cellBackgroundProducer = new CellBackgroundProducer
        (metaData.isFeatureSupported(AbstractTableOutputProcessor.TREAT_ELLIPSE_AS_RECTANGLE),
            metaData.isFeatureSupported(OutputProcessorFeature.UNALIGNED_PAGEBANDS));
  }

  public Sheet getSheet()
  {
    return sheet;
  }

  public void print(final LogicalPageKey logicalPageKey,
                    final LogicalPageBox logicalPage,
                    final TableContentProducer contentProducer,
                    final boolean incremental)
  {
    if (workbook == null)
    {
      workbook = createWorkbook();
      initializeStyleProducers(workbook);
      this.textExtractor = new ExcelTextExtractor
          (getMetaData(), getFontColorProducer(), workbook.getCreationHelper(), getCellStyleProducer().getFontFactory());
    }

    final int startRow = contentProducer.getFinishedRows();
    final int finishRow = contentProducer.getFilledRows();
    if (incremental && startRow == finishRow)
    {
      return;
    }

    if (sheet == null)
    {
      // make sure a new patriarch is created if needed.
      sheet = openSheet(contentProducer.getSheetName());
      final SheetPropertySource excelTableContentProducer = (SheetPropertySource) contentProducer;
      configureSheetProperties(sheet, excelTableContentProducer);
      // Start a new page.
      configureSheetPaperSize(sheet, logicalPage.getPageGrid().getPage(0, 0));
      configureSheetColumnWidths(sheet, contentProducer.getSheetLayout(), contentProducer.getColumnCount());
    }

    // and finally the content ..
    final SheetLayout sheetLayout = contentProducer.getSheetLayout();
    final int colCount = sheetLayout.getColumnCount();

    for (int row = startRow; row < finishRow; row++)
    {
      final Row hssfRow = getRowAt(row);
      final double lastRowHeight = StrictGeomUtility.toExternalValue(sheetLayout.getRowHeight(row));
      hssfRow.setHeightInPoints((float) (lastRowHeight));

      for (int col = 0; col < colCount; col++)
      {
        final CellMarker.SectionType sectionType = contentProducer.getSectionType(row, col);
        final RenderBox content = contentProducer.getContent(row, col);

        if (content == null)
        {
          final RenderBox backgroundBox = contentProducer.getBackground(row, col);
          final CellBackground background;
          if (backgroundBox != null)
          {
            background = cellBackgroundProducer.getBackgroundForBox
                (logicalPage, sheetLayout, col, row, 1, 1, true, sectionType, backgroundBox);
          }
          else
          {
            background = cellBackgroundProducer.getBackgroundAt(logicalPage, sheetLayout, col, row, true, sectionType);
          }
          if (background == null)
          {
            if (row == 0 && col == 0)
            {
              // create a single cell, so that we dont run into nullpointer inside POI..
              getCellAt(col, row);
            }
            // An empty cell .. ignore
            continue;
          }

          // A empty cell with a defined background ..
          final Cell cell = getCellAt(col, row);
          final CellStyle style =
              getCellStyleProducer().createCellStyle(null, null, background);
          if (style != null)
          {
            cell.setCellStyle(style);
          }
          continue;
        }

        if (content.isCommited() == false)
        {
          throw new InvalidReportStateException("Uncommited content encountered");
        }

        final long contentOffset = contentProducer.getContentOffset(row, col);
        final TableRectangle rectangle = sheetLayout.getTableBounds
            (content.getX(), content.getY() + contentOffset,
                content.getWidth(), content.getHeight(), null);
        if (rectangle.isOrigin(col, row) == false)
        {
          // A spanned cell ..
          continue;
        }

        final CellBackground fastBackground = cellBackgroundProducer.getBackgroundForBox
            (logicalPage, sheetLayout, rectangle.getX1(), rectangle.getY1(),
                rectangle.getColumnSpan(), rectangle.getRowSpan(), false, sectionType, content);
        // export the cell and all content ..

        final Cell cell = getCellAt(col, row);
        final CellStyle style =
            getCellStyleProducer().createCellStyle(content.getInstanceId(), content.getStyleSheet(), fastBackground);
        if (style != null)
        {
          cell.setCellStyle(style);
        }

        if (applyCellValue(content, cell, sheetLayout, rectangle, contentOffset))
        {
          mergeCellRegion(rectangle, row, col, sheetLayout, logicalPage, content, contentProducer);
        }

        content.setFinishedTable(true);
      }

    }

    if (incremental == false)
    {
      // cleanup ..
      sheet = null;
    }
  }

  private void mergeCellRegion(final TableRectangle rectangle,
                               final int row,
                               final int col,
                               final SheetLayout sheetLayout,
                               final LogicalPageBox logicalPage,
                               final RenderBox content,
                               final TableContentProducer contentProducer)
  {
    if (content == null)
    {
      throw new NullPointerException();
    }

    final int rowSpan = rectangle.getRowSpan();
    final int columnSpan = rectangle.getColumnSpan();
    if (rowSpan <= 1 && columnSpan <= 1)
    {
      return;
    }

    sheet.addMergedRegion(new CellRangeAddress(row, (row + rowSpan - 1), col, (col + columnSpan - 1)));
    final int rectX = rectangle.getX1();
    final int rectY = rectangle.getY1();

    for (int spannedRow = 0; spannedRow < rowSpan; spannedRow += 1)
    {
      for (int spannedCol = 0; spannedCol < columnSpan; spannedCol += 1)
      {
        final CellMarker.SectionType sectionType = contentProducer.getSectionType(row, col);
        final CellBackground bg = cellBackgroundProducer.getBackgroundForBox
            (logicalPage, sheetLayout, rectX + spannedCol, rectY + spannedRow, 1, 1, false, sectionType, content);
        final Cell regionCell = getCellAt((col + spannedCol), row + spannedRow);
        final CellStyle spannedStyle =
            getCellStyleProducer().createCellStyle(content.getInstanceId(), content.getStyleSheet(), bg);
        if (spannedStyle != null)
        {
          regionCell.setCellStyle(spannedStyle);
        }
      }
    }
  }

  /**
   * Applies the cell value and determines whether the cell should be merged. Merging will only take place if the cell
   * has a row or colspan greater than one. Images will never be merged, as image content is rendered into an anchored
   * frame on top of the cells.
   *
   * @param content
   * @param cell
   * @param sheetLayout
   * @param rectangle
   * @return true, if the cell may to be put into a merged region, false otherwise.
   */
  private boolean applyCellValue(final RenderBox content,
                                 final Cell cell,
                                 final SheetLayout sheetLayout,
                                 final TableRectangle rectangle,
                                 final long contentOffset)
  {
    final Object value = textExtractor.compute(content);

    if (handleImageValues(content, sheetLayout, rectangle, contentOffset, value))
    {
      return false;
    }

    final String linkTarget = (String) content.getStyleSheet().getStyleProperty(ElementStyleKeys.HREF_TARGET);
    if (linkTarget != null)
    {
      // this may be wrong if we have quotes inside. We should escape them ..
      final String formula = "HYPERLINK(" + splitAndQuoteExcelFormula(linkTarget) +
          "," + splitAndQuoteExcelFormula(textExtractor.getText()) + ")";
      if (formula.length() < 1024)
      {
        cell.setCellFormula(formula);
        return true;
      }

      ExcelPrinter.logger.warn(
          "Excel-Cells cannot contain formulas longer than 1023 characters. Converting hyperlink into plain text");
    }

    final Object attr1 = content.getAttributes().getAttribute(AttributeNames.Excel.NAMESPACE,
        AttributeNames.Excel.FIELD_FORMULA);
    if (attr1 != null)
    {
      final String formula = String.valueOf(attr1);
      if (formula.length() < 1024)
      {
        cell.setCellFormula(formula);
        return true;
      }

      ExcelPrinter.logger.warn(
          "Excel-Cells cannot contain formulas longer than 1023 characters. Converting excel formula into plain text");
    }

    if (value instanceof RichTextString)
    {
      cell.setCellValue((RichTextString) value);
    }
    else if (value instanceof Date)
    {
      cell.setCellValue((Date) value);
    }
    else if (value instanceof Number)
    {
      final Number number = (Number) value;
      cell.setCellValue(number.doubleValue());
    }
    else if (value instanceof Boolean)
    {
      cell.setCellValue(Boolean.TRUE.equals(value));
    }
    else // Something we can't handle.
    {
      if (value == null)
      {
        cell.setCellType(Cell.CELL_TYPE_BLANK);
      }
      else
      {
        cell.setCellValue(String.valueOf(value));

      }
    }
    return true;
  }

  private boolean handleImageValues(final RenderBox content,
                                    final SheetLayout sheetLayout,
                                    final TableRectangle rectangle,
                                    final long contentOffset,
                                    final Object value)
  {
    if (value instanceof Image)
    {
      try
      {
        final ImageContainer imageContainer = new DefaultImageReference((Image) value);
        final StyleSheet rawSource = textExtractor.getRawSource().getStyleSheet();
        final StrictBounds contentBounds =
            new StrictBounds(content.getX(), content.getY() + contentOffset, content.getWidth(), content.getHeight());
        createImageCell(rawSource, imageContainer, sheetLayout, rectangle, contentBounds);
      }
      catch (IOException ioe)
      {
        // Should not happen.
        ExcelPrinter.logger.warn("Failed to process AWT-Image in Excel-Export", ioe);
      }
      return true;
    }
    else if (value instanceof ImageContainer)
    {
      final ImageContainer imageContainer = (ImageContainer) value;
      // todo: this is wrong ..
      final StyleSheet rawSource = textExtractor.getRawSource().getStyleSheet();
      final StrictBounds contentBounds =
          new StrictBounds(content.getX(), content.getY() + contentOffset, content.getWidth(), content.getHeight());
      createImageCell(rawSource, imageContainer, sheetLayout, rectangle, contentBounds);
      return true;
    }
    else if (value instanceof DrawableWrapper)
    {
      final DrawableWrapper drawable = (DrawableWrapper) value;
      final RenderNode rawSource = textExtractor.getRawSource();
      final StrictBounds contentBounds = new StrictBounds
          (rawSource.getX(), rawSource.getY() + contentOffset, rawSource.getWidth(), rawSource.getHeight());
      final ImageContainer imageFromDrawable =
          RenderUtility.createImageFromDrawable(drawable, contentBounds, content, getMetaData());
      createImageCell(rawSource.getStyleSheet(), imageFromDrawable, sheetLayout, rectangle, contentBounds);
      return true;
    }
    else if (value instanceof Shape)
    {
      // We *could* do this as well ... but for now we dont.
      return true;
    }
    return false;
  }

  public void close()
  {
    final long start = System.currentTimeMillis();
    logger.info("Closing workbook and writing content to disk.");
    if (workbook != null)
    {
      try
      {
        workbook.write(outputStream);
        // cleanup..
        sheet = null;
        outputStream.flush();
      }
      catch (IOException e)
      {
        ExcelPrinter.logger.warn("could not write xls data. Message:", e);
      }
      finally
      {
        workbook = null;
      }
    }
    final long end = System.currentTimeMillis();
    logger.info("Closing workbook finished in " + ((end - start) / 1000f) + "s");

  }

  public Workbook getWorkbook()
  {
    return workbook;
  }

}
TOP

Related Classes of org.pentaho.reporting.engine.classic.core.modules.output.table.xls.helper.ExcelPrinter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.