Package com.sun.star.report.pentaho.output

Source Code of com.sun.star.report.pentaho.output.OfficeDocumentReportTarget$GroupContext

/*************************************************************************
*
*  OpenOffice.org - a multi-platform office productivity suite
*
*  $RCSfile: OfficeDocumentReportTarget.java,v $
*
*  $Revision: 1.3.60.1 $
*
*  last change: $Author: hr $ $Date: 2008/01/24 14:27:12 $
*
*  The Contents of this file are made available subject to
*  the terms of GNU Lesser General Public License Version 2.1.
*
*
*    GNU Lesser General Public License Version 2.1
*    =============================================
*    Copyright 2007 by Sun Microsystems, Inc.
*    901 San Antonio Road, Palo Alto, CA 94303, USA
*    Copyright 2007 by Pentaho Corporation
*
*    This library 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.
*
*    This library 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.
*
*    You should have received a copy of the GNU Lesser General Public
*    License along with this library; if not, write to the Free Software
*    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
*    MA  02111-1307  USA
*
************************************************************************/


package com.sun.star.report.pentaho.output;

import java.awt.Image;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Iterator;
import java.util.Map;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;

import com.sun.star.report.ImageService;
import com.sun.star.report.InputRepository;
import com.sun.star.report.OutputRepository;
import com.sun.star.report.pentaho.OfficeNamespaces;
import com.sun.star.report.pentaho.layoutprocessor.ImageElementContext;
import com.sun.star.report.pentaho.model.OfficeDocument;
import com.sun.star.report.pentaho.model.OfficeStyle;
import com.sun.star.report.pentaho.model.OfficeStyles;
import com.sun.star.report.pentaho.model.OfficeStylesCollection;
import com.sun.star.report.pentaho.styles.LengthCalculator;
import com.sun.star.report.pentaho.styles.StyleMapper;
import org.jfree.io.IOUtils;
import org.jfree.layouting.input.style.parser.CSSValueFactory;
import org.jfree.layouting.input.style.parser.StyleSheetParserUtil;
import org.jfree.layouting.input.style.values.CSSNumericValue;
import org.jfree.layouting.layouter.style.CSSValueResolverUtility;
import org.jfree.layouting.namespace.NamespaceDefinition;
import org.jfree.layouting.namespace.Namespaces;
import org.jfree.layouting.util.AttributeMap;
import org.jfree.report.DataFlags;
import org.jfree.report.DataSourceException;
import org.jfree.report.JFreeReportBoot;
import org.jfree.report.JFreeReportInfo;
import org.jfree.report.ReportProcessingException;
import org.jfree.report.flow.AbstractReportTarget;
import org.jfree.report.flow.ReportJob;
import org.jfree.report.flow.ReportStructureRoot;
import org.jfree.report.flow.ReportTargetUtil;
import org.jfree.report.structure.Element;
import org.jfree.report.structure.Section;
import org.jfree.report.util.AttributeNameGenerator;
import org.jfree.report.util.IntegerCache;
import org.jfree.report.util.MemoryByteArrayOutputStream;
import org.jfree.resourceloader.ResourceException;
import org.jfree.resourceloader.ResourceKey;
import org.jfree.resourceloader.ResourceManager;
import org.jfree.util.FastStack;
import org.jfree.util.LineBreakIterator;
import org.jfree.util.Log;
import org.jfree.xmlns.common.AttributeList;
import org.jfree.xmlns.writer.DefaultTagDescription;
import org.jfree.xmlns.writer.XmlWriter;
import org.jfree.xmlns.writer.XmlWriterSupport;
import org.w3c.css.sac.LexicalUnit;

/**
* Todo: Document me!
*
* @author Thomas Morgner
* @since 08.03.2007
*/
public abstract class OfficeDocumentReportTarget extends AbstractReportTarget
{
  public static final String TAG_DEF_PREFIX = "com.sun.star.report.pentaho.output.";

  public static final int ROLE_NONE = 0;
  public static final int ROLE_REPORT_HEADER = 1;
  public static final int ROLE_REPORT_FOOTER = 2;
  public static final int ROLE_GROUP_HEADER = 3;
  public static final int ROLE_GROUP_FOOTER = 4;
  public static final int ROLE_REPEATING_GROUP_HEADER = 5;
  public static final int ROLE_REPEATING_GROUP_FOOTER = 6;
  public static final int ROLE_PAGE_HEADER = 7;
  public static final int ROLE_PAGE_FOOTER = 8;
  public static final int ROLE_DETAIL = 9;
  public static final int ROLE_VARIABLES = 10;
  public static final int ROLE_TEMPLATE = 11;
  public static final int ROLE_SPREADSHEET_PAGE_HEADER = 12;
  public static final int ROLE_SPREADSHEET_PAGE_FOOTER = 13;

  public static final int STATE_IN_DOCUMENT = 0;
  public static final int STATE_IN_BODY = 1;
  public static final int STATE_IN_CONTENT = 2;
  public static final int STATE_IN_GROUP = 3;
  public static final int STATE_IN_GROUP_BODY = 4;
  public static final int STATE_IN_SECTION = 5;
  public static final int STATE_IN_OTHER = 6;
  public static final int STATE_IN_GROUP_INSTANCE = 7;

  protected static class BufferState
  {
    private XmlWriter xmlWriter;
    private MemoryByteArrayOutputStream xmlBuffer;
    private OfficeStylesCollection stylesCollection;

    protected BufferState(final XmlWriter xmlWriter,
                          final MemoryByteArrayOutputStream xmlBuffer,
                          final OfficeStylesCollection stylesCollection)
    {
      this.stylesCollection = stylesCollection;
      this.xmlWriter = xmlWriter;
      this.xmlBuffer = xmlBuffer;
    }


    public OfficeStylesCollection getStylesCollection()
    {
      return stylesCollection;
    }

    public XmlWriter getXmlWriter()
    {
      return xmlWriter;
    }

    public String getXmlBuffer() throws ReportProcessingException
    {
      try
      {
        final byte[] zippedData = xmlBuffer.getRaw();
        final InputStreamReader reader = new InputStreamReader
            (new InflaterInputStream(new ByteArrayInputStream(zippedData, 0, xmlBuffer.getLength())), "UTF-16");
        final StringWriter writer = new StringWriter((zippedData.length / 2) + 1);
        IOUtils.getInstance().copyWriter(reader, writer);
        return writer.toString();
      }
      catch (IOException e)
      {
        throw new ReportProcessingException("Failed to copy buffer", e);
      }
    }

    public Reader getXmlAsReader() throws ReportProcessingException
    {
      try
      {
        final byte[] zippedData = xmlBuffer.getRaw();
        return new InputStreamReader
            (new InflaterInputStream(new ByteArrayInputStream(zippedData, 0, xmlBuffer.getLength())), "UTF-16");
      }
      catch (IOException e)
      {
        throw new ReportProcessingException("Failed to copy buffer", e);
      }
    }
  }

  protected static class GroupContext
  {
    private GroupContext parent;
    private int iterationCount;
    private boolean groupWithRepeatingSection;

    protected GroupContext(final GroupContext parent)
    {
      this.parent = parent;
    }

    public GroupContext getParent()
    {
      return parent;
    }

    public int getIterationCount()
    {
      return iterationCount;
    }

    public void setIterationCount(final int iterationCount)
    {
      this.iterationCount = iterationCount;
    }

    public boolean isGroupWithRepeatingSection()
    {
      return groupWithRepeatingSection;
    }

    public void setGroupWithRepeatingSection(final boolean groupWithRepeatingSection)
    {
      this.groupWithRepeatingSection = groupWithRepeatingSection;
    }


    public String toString()
    {
      return "GroupContext{" +
          "parent=" + parent +
          ", iterationCount=" + iterationCount +
          ", groupWithRepeatingSection=" + groupWithRepeatingSection +
          '}';
    }
  }

  private FastStack states;
  private int currentRole;

  private FastStack xmlWriters;
  private XmlWriter rootXmlWriter;

  /**
   * This styles-collection contains all styles that were predefined in the report definition file. The common styles
   * and the master-styles will be written unmodified, the automatic styles will be ignored.
   */
  private OfficeStylesCollection predefinedStylesCollection;

  /**
   * This styles-collection contains all master-styles that have been generated by the report definition process. It
   * also contains all automatic styles that have been generated for the page-bands (and the pagebands as well).
   */
  private OfficeStylesCollection globalStylesCollection;

  /**
   * The content styles collection contains all automatic styles that have been generated for the normal-flow content.
   */
  private OfficeStylesCollection contentStylesCollection;

  private OutputRepository outputRepository;
  private AttributeNameGenerator tableNameGenerator;
  private AttributeNameGenerator autoStyleNameGenerator;
  private String target;
  private static final int INITIAL_BUFFER_SIZE = 40960;
  private StyleMapper styleMapper;
  private StyleSheetParserUtil styleSheetParserUtil;
  private AttributeNameGenerator imageNames;
  private ImageProducer imageProducer;
  private GroupContext groupContext;
  private static final boolean DEBUG_ELEMENTS =
      JFreeReportBoot.getInstance().getExtendedConfig().getBoolProperty
          ("com.sun.star.report.pentaho.output.DebugElements");

  protected OfficeDocumentReportTarget(final ReportJob reportJob,
                                       final ResourceManager resourceManager,
                                       final ResourceKey baseResource,
                                       final InputRepository inputRepository,
                                       final OutputRepository outputRepository,
                                       final String target,
                                       final ImageService imageService)
      throws ReportProcessingException
  {
    super(reportJob, resourceManager, baseResource);
    if (imageService == null)
    {
      throw new NullPointerException("ImageService must not be null");
    }
    if (target == null)
    {
      throw new NullPointerException("Target-Name must not be null");
    }

    this.target = target;

    this.tableNameGenerator = new AttributeNameGenerator();
    this.autoStyleNameGenerator = new AttributeNameGenerator();
    this.outputRepository = outputRepository;
    this.states = new FastStack();
    this.xmlWriters = new FastStack();
    this.imageNames = new AttributeNameGenerator();

    this.imageProducer = new ImageProducer(inputRepository, outputRepository, imageService);

    try
    {
      final ResourceManager realResourceManager = getResourceManager();
      styleMapper = StyleMapper.loadInstance(realResourceManager);
    }
    catch (ResourceException e)
    {
      throw new ReportProcessingException("Failed to load style-mapper", e);
    }
  }

  protected abstract String getTargetMimeType();

  protected OutputRepository getOutputRepository()
  {
    return outputRepository;
  }

  /**
   * Starts the output of a new office document. This method writes the generic 'office:document-content' tag along with
   * all known namespace declarations.
   *
   * @param report the report object.
   * @throws DataSourceException       if there was an error accessing the datasource
   * @throws ReportProcessingException if some other error occured.
   */
  public void startReport(final ReportStructureRoot report)
      throws DataSourceException, ReportProcessingException
  {
    imageNames.reset();
    this.groupContext = new GroupContext(null);

    final DefaultTagDescription tagDescription = createTagDescription();
    try
    {
      final OutputStream outputStream = outputRepository.createOutputStream(target, "text/xml");
      final Writer writer = new OutputStreamWriter(outputStream, "UTF-8");

      this.rootXmlWriter = new XmlWriter(writer, tagDescription);
      this.rootXmlWriter.setAlwaysAddNamespace(true);

      final AttributeList rootAttributes = new AttributeList();
      rootAttributes.addNamespaceDeclaration("office", OfficeNamespaces.OFFICE_NS);
      rootAttributes.addNamespaceDeclaration("style", OfficeNamespaces.STYLE_NS);
      rootAttributes.addNamespaceDeclaration("text", OfficeNamespaces.TEXT_NS);
      rootAttributes.addNamespaceDeclaration("table", OfficeNamespaces.TABLE_NS);
      rootAttributes.addNamespaceDeclaration("draw", OfficeNamespaces.DRAWING_NS);
      rootAttributes.addNamespaceDeclaration("fo", OfficeNamespaces.FO_NS);
      rootAttributes.addNamespaceDeclaration("xlink", OfficeNamespaces.XLINK_NS);
      rootAttributes.addNamespaceDeclaration("dc", OfficeNamespaces.PURL_NS);
      rootAttributes.addNamespaceDeclaration("meta", OfficeNamespaces.META_NS);
      rootAttributes.addNamespaceDeclaration("number", OfficeNamespaces.DATASTYLE_NS);
      rootAttributes.addNamespaceDeclaration("svg", OfficeNamespaces.SVG_NS);
      rootAttributes.addNamespaceDeclaration("chart", OfficeNamespaces.CHART_NS);
      rootAttributes.addNamespaceDeclaration("dr3d", OfficeNamespaces.DR3D_NS);
      rootAttributes.addNamespaceDeclaration("math", OfficeNamespaces.MATHML_NS);
      rootAttributes.addNamespaceDeclaration("form", OfficeNamespaces.FORM_NS);
      rootAttributes.addNamespaceDeclaration("script", OfficeNamespaces.SCRIPT_NS);
      rootAttributes.addNamespaceDeclaration("ooo", OfficeNamespaces.OO2004_NS);
      rootAttributes.addNamespaceDeclaration("ooow", OfficeNamespaces.OOW2004_NS);
      rootAttributes.addNamespaceDeclaration("oooc", OfficeNamespaces.OOC2004_NS);
      rootAttributes.addNamespaceDeclaration("dom", OfficeNamespaces.XML_EVENT_NS);
      rootAttributes.addNamespaceDeclaration("xforms", OfficeNamespaces.XFORMS_NS);
      rootAttributes.addNamespaceDeclaration("xsd", OfficeNamespaces.XSD_NS);
      rootAttributes.addNamespaceDeclaration("xsi", OfficeNamespaces.XSI_NS);
      rootAttributes.setAttribute(OfficeNamespaces.OFFICE_NS, "version", "1.0");

      this.rootXmlWriter.writeXmlDeclaration("UTF-8");
      this.rootXmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "document-content", rootAttributes, XmlWriterSupport.OPEN);

      states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_DOCUMENT));

      autoStyleNameGenerator.reset();
      tableNameGenerator.reset();

      final OfficeDocument reportDoc = (OfficeDocument) report;
      predefinedStylesCollection = reportDoc.getStylesCollection();

      final OfficeStyles commonStyles = predefinedStylesCollection.getCommonStyles();
      if (commonStyles.containsStyle("graphic", "Graphics") == false)
      {
        final OfficeStyle graphicsDefaultStyle = new OfficeStyle();
        graphicsDefaultStyle.setStyleFamily("graphic");
        graphicsDefaultStyle.setStyleName("Graphics");
        final Element graphicProperties = produceFirstChild(graphicsDefaultStyle, OfficeNamespaces.STYLE_NS, "graphic-properties");
        graphicProperties.setAttribute(OfficeNamespaces.TEXT_NS, "anchor-type", "paragraph");
        graphicProperties.setAttribute(OfficeNamespaces.SVG_NS, "x", "0cm");
        graphicProperties.setAttribute(OfficeNamespaces.SVG_NS, "y", "0cm");
        graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "wrap", "dynamic");
        graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "number-wrapped-paragraphs", "no-limit");
        graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "wrap-contour", "false");
        graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "vertical-pos", "top");
        graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "vertical-rel", "paragraph");
        graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "horizontal-pos", "center");
        graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "horizontal-rel", "paragraph");
        commonStyles.addStyle(graphicsDefaultStyle);
      }

      // Make sure that later generated styles do not overwrite existing styles.
      fillStyleNameGenerator(predefinedStylesCollection);

      contentStylesCollection = new OfficeStylesCollection();
      globalStylesCollection = new OfficeStylesCollection();

      startBuffering(contentStylesCollection, true);
    }
    catch (IOException e)
    {
      throw new ReportProcessingException("Failed", e);
    }
  }

  protected AttributeNameGenerator getAutoStyleNameGenerator()
  {
    return autoStyleNameGenerator;
  }

  private void fillStyleNameGenerator(final OfficeStylesCollection stylesCollection)
  {
    final OfficeStyles commonStyles = stylesCollection.getCommonStyles();
    final OfficeStyle[] allCommonStyles = commonStyles.getAllStyles();
    for (int i = 0; i < allCommonStyles.length; i++)
    {
      final OfficeStyle style = allCommonStyles[i];
      autoStyleNameGenerator.generateName(style.getStyleName());
    }

    final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles();
    final OfficeStyle[] allAutoStyles = autoStyles.getAllStyles();
    for (int i = 0; i < allAutoStyles.length; i++)
    {
      final OfficeStyle style = allAutoStyles[i];
      autoStyleNameGenerator.generateName(style.getStyleName());
    }
  }

  public OfficeStylesCollection getPredefinedStylesCollection()
  {
    return predefinedStylesCollection;
  }

  public OfficeStylesCollection getGlobalStylesCollection()
  {
    return globalStylesCollection;
  }

  public OfficeStylesCollection getContentStylesCollection()
  {
    return contentStylesCollection;
  }

  /**
   * Returns the XML-Writer tag description. This description defines whether an element can have character data inside.
   * Such element will disable the indention, as in that case the additional whitespaces might alter the meaning of the
   * element's contents.
   *
   * @return the tag description library.
   */
  protected DefaultTagDescription createTagDescription()
  {
    final DefaultTagDescription tagDescription = new DefaultTagDescription();
    tagDescription.configure(JFreeReportBoot.getInstance().getGlobalConfig(),
        OfficeDocumentReportTarget.TAG_DEF_PREFIX);
    return tagDescription;
  }

  /**
   * Returns the current processing state.
   *
   * @return the processing state.
   */
  protected int getCurrentState()
  {
    if (states.isEmpty())
    {
      throw new IllegalStateException();
    }
    final Integer o = (Integer) states.peek();
    return o.intValue();
  }

  /**
   * Starts the processing of an element and updates the processing state. This will select an apropriate handler method
   * for the call and will call one of the start* methods.
   *
   * @param attrs the attribute map for the current element
   * @throws DataSourceException
   * @throws ReportProcessingException
   */
  public final void startElement(final AttributeMap attrs)
      throws DataSourceException, ReportProcessingException
  {
    // todo
    if (DEBUG_ELEMENTS)
    {
      Log.debug("Starting " + getCurrentState() + '/' + states.size() + ' ' +
          ReportTargetUtil.getNamespaceFromAttribute(attrs) + " -> " +
          ReportTargetUtil.getElemenTypeFromAttribute(attrs));
    }
    try
    {
      switch (getCurrentState())
      {
        case OfficeDocumentReportTarget.STATE_IN_DOCUMENT:
        {
          if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OFFICE_NS, "body", attrs))
          {
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_BODY));
            startBody(attrs);
          }
          else
          {
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER));
            if (isFilteredNamespace(ReportTargetUtil.getNamespaceFromAttribute(attrs)) == false)
            {
              startOther(attrs);
            }
          }
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_BODY:
        {
          if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OFFICE_NS, "report", attrs))
          {
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_CONTENT));
            startContent(attrs);
          }
          else
          {
            throw new IllegalStateException
                ("The 'office:body' element must have exactly one child of type 'report'");
          }
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_CONTENT:
        {
          // Either a ordinary section or a group ..
          // A group.
          if (ReportTargetUtil.isElementOfType(OfficeNamespaces.INTERNAL_NS, "report-body", attrs))
          {
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP_BODY));
            startGroupBody(attrs);
          }
          else
          {
            // Either a template-section, page-header, page-footer, report-header, report-footer
            // or variables-section
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
            if (ReportTargetUtil.isElementOfType(OfficeNamespaces.INTERNAL_NS, "template", attrs))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_TEMPLATE;
            }
            else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "page-header", attrs))
            {
              if ("spreadsheet-section".equals(attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "role")))
              {
                currentRole = OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_HEADER;
              }
              else
              {
                currentRole = OfficeDocumentReportTarget.ROLE_PAGE_HEADER;
              }
            }
            else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "page-footer", attrs))
            {
              if ("spreadsheet-section".equals(attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "role")))
              {
                currentRole = OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_FOOTER;
              }
              else
              {
                currentRole = OfficeDocumentReportTarget.ROLE_PAGE_FOOTER;
              }
            }
            else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "report-header", attrs))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_REPORT_HEADER;
            }
            else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "report-footer", attrs))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_REPORT_FOOTER;
            }
            else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.INTERNAL_NS, "variables-section", attrs))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES;
            }
            else
            {
              throw new IllegalStateException("Expected either 'template', 'report-body', " +
                  "'report-header', 'report-footer', 'variables-section', 'page-header' or 'page-footer'");
            }
            startReportSection(attrs, currentRole);
          }
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_GROUP_BODY:
        {
          // We now expect either an other group or a detail band.

          if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group", attrs))
          {
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP));
            groupContext = new GroupContext(groupContext);
            startGroup(attrs);
          }
          else
          {
            // Either a variables-section, or a detail-band
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
            if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "detail", attrs))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_DETAIL;
            }
            else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.INTERNAL_NS, "variables-section", attrs))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES;
            }
            else
            {
              throw new IllegalStateException("Expected either 'group', 'detail' or 'variables-section'");
            }
            startReportSection(attrs, currentRole);
          }
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_GROUP:
        {
          // A group can carry a repeating group header/footer or a group-instance section.
          if (ReportTargetUtil.isElementOfType(OfficeNamespaces.INTERNAL_NS, "group-instance", attrs))
          {
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE));
            startGroupInstance(attrs);
          }
          else
          {
            // repeating group header/footer, but *no* variables section
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
            if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-header", attrs) &&
                "true".equals(attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "repeated-section")))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER;
            }
            else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-footer", attrs) &&
                "true".equals(attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "repeated-section")))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER;
            }
            else
            {
              throw new IllegalStateException("Expected either 'group-instance', " +
                  "'repeating group-header' or 'repeating group-footer'");
            }
            startReportSection(attrs, currentRole);
          }
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE:
        {
          if (ReportTargetUtil.isElementOfType(OfficeNamespaces.INTERNAL_NS, "group-body", attrs))
          {
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP_BODY));
            startGroupBody(attrs);
          }
          else
          {
            // Either a group-header or group-footer or variables-section
            states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
            if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-header", attrs))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_GROUP_HEADER;
            }
            else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-footer", attrs))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_GROUP_FOOTER;
            }
            else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.INTERNAL_NS, "variables-section", attrs))
            {
              currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES;
            }
            else
            {
              throw new IllegalStateException("Expected either 'group-body', 'group-header', 'group-footer' or 'variables-section'");
            }
            startReportSection(attrs, currentRole);
          }
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_SECTION:
        {
          states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER));
          startOther(attrs);
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_OTHER:
        {
          states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER));
          startOther(attrs);
          return;
        }
        default:
          throw new IllegalStateException("Failure: " + getCurrentState());
      }
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
      throw new ReportProcessingException("Failed to write content", ioe);
    }
//    finally
//    {
//      Log.debug ("Started " + getNamespaceFromAttribute(attrs) + ":" +
//                 getElemenTypeFromAttribute(attrs) + " -> " + getCurrentState());
//    }
  }

  protected GroupContext getGroupContext()
  {
    return groupContext;
  }

  protected void performStyleProcessing(final AttributeMap attrs)
      throws ReportProcessingException
  {
    final OfficeStylesCollection stylesCollection = getStylesCollection();
    final OfficeStylesCollection predefCollection = getPredefinedStylesCollection();
    final OfficeStylesCollection globalStylesCollection = getGlobalStylesCollection();

    final String elementNamespace =
        ReportTargetUtil.getNamespaceFromAttribute(attrs);
    final String elementName =
        ReportTargetUtil.getElemenTypeFromAttribute(attrs);

    final String[] namespaces = attrs.getNameSpaces();
    for (int i = 0; i < namespaces.length; i++)
    {
      final String attrNamespace = namespaces[i];
      if (isFilteredNamespace(attrNamespace))
      {
        continue;
      }

      final Map attributes = attrs.getAttributes(attrNamespace);
      final Iterator iterator = attributes.entrySet().iterator();
      while (iterator.hasNext())
      {
        final Map.Entry entry = (Map.Entry) iterator.next();
        final String attrName = (String) entry.getKey();
        final String attrValue = String.valueOf(entry.getValue());

        final String styleFamily = styleMapper.getStyleFamilyFor
            (elementNamespace, elementName, attrNamespace, attrName);
        if (styleFamily == null)
        {
          // None of the known style attributes.
          continue;
        }

        if (styleMapper.isListOfStyles
            (elementNamespace, elementName, attrNamespace, attrName))
        {
          // ignored for now.
          Log.warn("List of styles is not yet implemented.");
          continue;
        }

        // Copy styles is only called once per style.
        StyleUtilities.copyStyle(styleFamily, attrValue, stylesCollection, globalStylesCollection, predefCollection);
      }
    }
  }

  protected void startBody(final AttributeMap attrs)
      throws IOException
  {
    getXmlWriter().writeTag(OfficeNamespaces.OFFICE_NS, "body", XmlWriterSupport.OPEN);
  }

  protected void startReportSection(final AttributeMap attrs, final int role)
      throws IOException, DataSourceException, ReportProcessingException
  {
    if (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER ||
        role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER ||
        role == OfficeDocumentReportTarget.ROLE_TEMPLATE)
    {
      startBuffering(new OfficeStylesCollection(), true);
    }
  }

  protected abstract void startContent(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException;

  protected void startGroup(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException
  {
    final Object repeatingHeaderOrFooter = attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "repeating-header-or-footer");
    if ("true".equals(repeatingHeaderOrFooter))
    {
      getGroupContext().setGroupWithRepeatingSection(true);
    }

    final Object iterationCount = attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "iteration-count");
    if (iterationCount instanceof Number)
    {
      final Number itNumber = (Number) iterationCount;
      getGroupContext().setIterationCount(itNumber.intValue());
    }
  }

  protected void startGroupInstance(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException
  {

  }

  protected void startGroupBody(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException
  {
  }

  protected abstract void startOther(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException;

  public void processText(final String text)
      throws DataSourceException, ReportProcessingException
  {
    try
    {
      final XmlWriter xmlWriter = getXmlWriter();
      final LineBreakIterator lb = new LineBreakIterator(text);
      while (lb.hasNext())
      {
        final String line = (String) lb.next();
        final String normalizedText = XmlWriterSupport.normalize(line, false);
        xmlWriter.writeText(normalizedText);
        if (lb.hasNext())
        {
          xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, "line-break", XmlWriterSupport.CLOSE);
        }
      }
    }
    catch (IOException e)
    {
      throw new ReportProcessingException("Failed", e);
    }
  }

  protected boolean isFilteredNamespace(final String namespace)
  {
    if (Namespaces.LIBLAYOUT_NAMESPACE.equals(namespace))
    {
      return true;
    }
    if (JFreeReportInfo.REPORT_NAMESPACE.equals(namespace))
    {
      return true;
    }
    if (OfficeNamespaces.INTERNAL_NS.equals(namespace))
    {
      return true;
    }
    if (JFreeReportInfo.COMPATIBILITY_NAMESPACE.equals(namespace))
    {
      return true;
    }
    if (OfficeNamespaces.OOREPORT_NS.equals(namespace))
    {
      return true;
    }
    return false;
  }

  public void processContent(final DataFlags value)
      throws DataSourceException, ReportProcessingException
  {
    final Object rawvalue = value.getValue();
    if (rawvalue == null)
    {
      return;
    }

    // special handler for image (possibly also for URL ..)
    if (rawvalue instanceof Image)
    {
      // do nothing yet. We should define something for that later ..
      return;
    }

    final XmlWriter xmlWriter = getXmlWriter();
    final String text = String.valueOf(rawvalue);
    try
    {
      final LineBreakIterator lb = new LineBreakIterator(text);
      while (lb.hasNext())
      {
        final String line = (String) lb.next();
        final String normalizedText = XmlWriterSupport.normalize(line, false);
        xmlWriter.writeText(normalizedText);
        if (lb.hasNext())
        {
          xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, "line-break", XmlWriterSupport.CLOSE);
        }
      }
    }
    catch (IOException e)
    {
      throw new ReportProcessingException("Failed", e);
    }
  }


  public final void endElement(final AttributeMap attrs)
      throws DataSourceException, ReportProcessingException
  {
    // final int oldState = getCurrentState();
    try
    {

      switch (getCurrentState())
      {
        case OfficeDocumentReportTarget.STATE_IN_OTHER:
        {
          endOther(attrs);
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_SECTION:
        {
          endReportSection(attrs, currentRole);
          currentRole = OfficeDocumentReportTarget.ROLE_NONE;
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_GROUP:
        {
          endGroup(attrs);
          groupContext = groupContext.getParent();
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE:
        {
          endGroupInstance(attrs);
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_GROUP_BODY:
        {
          endGroupBody(attrs);
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_CONTENT:
        {
          endContent(attrs);
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_BODY:
        {
          endBody(attrs);
          return;
        }
        case OfficeDocumentReportTarget.STATE_IN_DOCUMENT:
        {
          throw new IllegalStateException("This cannot be.");
        }
        default:
        {
          throw new IllegalStateException("Invalid state encountered.");
        }
      }
    }
    catch (IOException ioe)
    {
      throw new ReportProcessingException("IO Error while writing content",
          ioe);
    }
    finally
    {
      states.pop();

      if (DEBUG_ELEMENTS)
      {
        Log.debug("Finished " + getCurrentState() + "/" + states.size() + " " +
            ReportTargetUtil.getNamespaceFromAttribute(attrs) + ":" +
            ReportTargetUtil.getElemenTypeFromAttribute(attrs));
      }

    }
  }

  protected void endGroupBody(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException
  {

  }

  protected void endGroupInstance(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException
  {

  }

  public int getCurrentRole()
  {
    return currentRole;
  }

  protected abstract void endOther(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException;

  protected void endReportSection(final AttributeMap attrs,
                                  final int role)
      throws IOException, DataSourceException, ReportProcessingException
  {
    if (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER ||
        role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER ||
        role == OfficeDocumentReportTarget.ROLE_TEMPLATE)
    {
      finishBuffering();
    }
  }

  protected void endGroup(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException
  {
  }

  protected abstract void endContent(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException;

  protected void endBody(final AttributeMap attrs)
      throws IOException, DataSourceException, ReportProcessingException
  {
    getXmlWriter().writeCloseTag();
  }

  public void endReport(final ReportStructureRoot report)
      throws DataSourceException, ReportProcessingException
  {
    if (xmlWriters.size() != 1)
    {
      throw new IllegalStateException("Invalid writer-stack state");
    }

    try
    {
      final StylesWriter inlineStylesWriter = new StylesWriter(rootXmlWriter);
      inlineStylesWriter.writeContentStyles
          (predefinedStylesCollection, contentStylesCollection);

      final BufferState state = finishBuffering();
      this.rootXmlWriter.writeStream(state.getXmlAsReader());

      final OutputStream stylesOutStream =
          outputRepository.createOutputStream("styles.xml", "text/xml");
      final OutputStreamWriter osw =
          new OutputStreamWriter(stylesOutStream, "UTF-8");
      final StylesWriter stylesWriter = new StylesWriter(osw);
      stylesWriter.writeGlobalStyles
          (predefinedStylesCollection, globalStylesCollection);
      stylesWriter.close();

      this.rootXmlWriter.writeCloseTag();
      this.rootXmlWriter.close();
    }
    catch (IOException e)
    {
      throw new ReportProcessingException("Failed", e);
    }
  }

  public XmlWriter getXmlWriter()
  {
    final BufferState bufferState = (BufferState) xmlWriters.peek();
    return bufferState.getXmlWriter();
  }

  public OfficeStylesCollection getStylesCollection()
  {
    final BufferState bufferState = (BufferState) xmlWriters.peek();
    return bufferState.getStylesCollection();
  }

  public void startBuffering(final OfficeStylesCollection stylesCollection,
                             final boolean indent) throws ReportProcessingException
  {
    final XmlWriter currentWriter;
    if (xmlWriters.isEmpty())
    {
      currentWriter = rootXmlWriter;
    }
    else
    {
      final BufferState bufferState = (BufferState) xmlWriters.peek();
      currentWriter = bufferState.getXmlWriter();
    }

    try
    {
      final MemoryByteArrayOutputStream out =
          new MemoryByteArrayOutputStream(INITIAL_BUFFER_SIZE, 256 * INITIAL_BUFFER_SIZE);
      final DeflaterOutputStream deflateOut = new DeflaterOutputStream(out);
      final OutputStreamWriter xmlBuffer = new OutputStreamWriter(deflateOut, "UTF-16");
      //    final StringWriter xmlBuffer = new StringWriter
      //        (OfficeDocumentReportTarget.INITIAL_BUFFER_SIZE);
      final XmlWriter contentXmlWriter = new XmlWriter(xmlBuffer, createTagDescription());
      contentXmlWriter.copyNamespaces(currentWriter);
      if (indent)
      {
        contentXmlWriter.setAdditionalIndent(currentWriter.getCurrentIndentLevel());
        contentXmlWriter.setWriteFinalLinebreak(true);
      }
      else
      {
        contentXmlWriter.setWriteFinalLinebreak(false);
      }
      contentXmlWriter.setAlwaysAddNamespace(true);
      xmlWriters.push(new BufferState(contentXmlWriter, out, stylesCollection));
    }
    catch (IOException ioe)
    {
      throw new ReportProcessingException("Unable to create the buffer");
    }
  }

  public BufferState finishBuffering() throws ReportProcessingException
  {
    final BufferState state = (BufferState) xmlWriters.pop();
    try
    {
      state.getXmlWriter().close();
    }
    catch (IOException e)
    {
      e.printStackTrace();
    }
    return state;
  }

  public void commit()
      throws ReportProcessingException
  {
    // do not call flush before the report is fully finished. Every flush
    // causes the Office-Backend to fully ZIP all contents (it acts like a
    // 'Save' call from the UI) and that's expensive like hell
  }

  public NamespaceDefinition getNamespaceByUri(final String uri)
  {
    return null;
  }

  protected AttributeList buildAttributeList(final AttributeMap attrs)
  {
    final AttributeList attrList = new AttributeList();
    final String[] namespaces = attrs.getNameSpaces();
    for (int i = 0; i < namespaces.length; i++)
    {
      final String attrNamespace = namespaces[i];
      if (isFilteredNamespace(attrNamespace))
      {
        continue;
      }

      final Map localAttributes = attrs.getAttributes(attrNamespace);
      final Iterator entries = localAttributes.entrySet().iterator();
      while (entries.hasNext())
      {
        final Map.Entry entry = (Map.Entry) entries.next();
        final String key = String.valueOf(entry.getKey());
        if (OfficeNamespaces.TABLE_NS.equals(attrNamespace) &&
            "name".equals(key))
        {
          final String tableName = String.valueOf(entry.getValue());
          final String saneName = sanitizeName(tableName);
          attrList.setAttribute(attrNamespace, key,
              tableNameGenerator.generateName(saneName));
        }
        else
        {
          attrList.setAttribute
              (attrNamespace, key, String.valueOf(entry.getValue()));
        }
      }
    }
    return attrList;
  }

  protected String sanitizeName(final String name)
  {
    // A table name cannot contain spaces and should only contain
    // ascii-characters.
    if (name == null)
    {
      return "";
    }
    final char[] chars = name.toCharArray();
    final StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < chars.length; i++)
    {
      final char aChar = chars[i];
      if (Character.isWhitespace(aChar))
      {
        buffer.append('_');
      }
      else
      {
        buffer.append(aChar);
      }
    }
    return buffer.toString();
  }

  /**
   * Returns the length in point. This method is f**king slow, it eats half of the processing time. I surely should
   * replace it with something more efficient later.
   *
   * @param text
   * @return
   */
  protected CSSNumericValue parseLength(final String text)
  {
    if (styleSheetParserUtil == null)
    {
      styleSheetParserUtil = StyleSheetParserUtil.getInstance();
    }

    final LexicalUnit cssValue = styleSheetParserUtil.parseLexicalStyleValue(
        text);
    return CSSValueFactory.createLengthValue(cssValue);
  }

  protected boolean isRepeatingSection()
  {
    return (currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER ||
        currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER ||
        currentRole == OfficeDocumentReportTarget.ROLE_PAGE_FOOTER ||
        currentRole == OfficeDocumentReportTarget.ROLE_PAGE_HEADER ||
        currentRole == OfficeDocumentReportTarget.ROLE_VARIABLES);

  }

  protected OfficeStyle deriveStyle(final String styleFamily, final String styleName)
      throws ReportProcessingException
  {
    // autogenerate a style. The style has already been added to the current
    // auto-collection.
    final OfficeStyle style = StyleUtilities.deriveStyle(styleFamily, styleName,
        getStylesCollection(), getGlobalStylesCollection(),
        getPredefinedStylesCollection(), getAutoStyleNameGenerator());
    return style;
  }


  protected void startImageProcessing(final AttributeMap attrs)
      throws ReportProcessingException
  {
    final Object imageData = attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "image-data");
    final boolean preserveIRI = "true".equals(attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "preserve-IRI"));

    // for the first shot, do nothing fancy ..
    final ImageProducer.OfficeImage image = imageProducer.produceImage(imageData, preserveIRI);
    if (image != null)
    {
      final ImageElementContext imageContext = (ImageElementContext)
          attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "image-context");

      // When scaling, we have to create an image-style.
      final CSSNumericValue width = image.getWidth(); // always in 100th of a mm
      final CSSNumericValue height = image.getHeight(); // always in 100th of a mm

      Log.debug("Image " + imageData + " Width: " + width + ", Height: " + height);
      if (width == null || height == null)
      {
        return;
      }

      CSSNumericValue imageAreaWidthVal;
      CSSNumericValue imageAreaHeightVal;
      String styleName = null;
      if (imageContext != null)
      {
        imageAreaWidthVal = computeImageWidth(imageContext);
        imageAreaHeightVal = computeImageHeight(imageContext);

        if (imageAreaWidthVal == null || imageAreaHeightVal == null)
        {
          Log.debug("Image data returned from context is invalid. Maybe this is not an image?");
          return;
        }
        else
        {
          // compute the clip-area ..
          final CSSNumericValue normalizedImageWidth =
              CSSValueResolverUtility.convertLength(width, imageAreaWidthVal.getType());
          final CSSNumericValue normalizedImageHeight =
              CSSValueResolverUtility.convertLength(height, imageAreaHeightVal.getType());

          final boolean scale = "true".equals(attrs.getAttribute(OfficeNamespaces.INTERNAL_NS, "scale"));
          if (scale == false && normalizedImageWidth.getValue() > 0 && normalizedImageHeight.getValue() > 0)
          {
            final double clipWidth = normalizedImageWidth.getValue() - imageAreaWidthVal.getValue();
            final double clipHeight = normalizedImageHeight.getValue() - imageAreaHeightVal.getValue();
            if (clipWidth > 0 && clipHeight > 0)
            {
              final OfficeStyle imageStyle = deriveStyle("graphic", "Graphics");
              final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, "graphic-properties");
              final StringBuffer buffer = new StringBuffer();
              buffer.append("rect(");
              buffer.append(clipHeight / 2);
              buffer.append(imageAreaHeightVal.getType().getType());
              buffer.append(" ");
              buffer.append(clipWidth / 2);
              buffer.append(imageAreaWidthVal.getType().getType());
              buffer.append(" ");
              buffer.append(clipHeight / 2);
              buffer.append(imageAreaHeightVal.getType().getType());
              buffer.append(" ");
              buffer.append(clipWidth / 2);
              buffer.append(imageAreaWidthVal.getType().getType());
              buffer.append(")");
              graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());

              styleName = imageStyle.getStyleName();
              getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
            }
            else if (clipWidth > 0)
            {
              final OfficeStyle imageStyle = deriveStyle("graphic", "Graphics");
              final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, "graphic-properties");
              final StringBuffer buffer = new StringBuffer();
              buffer.append("rect(0cm ");
              buffer.append(clipWidth / 2);
              buffer.append(imageAreaWidthVal.getType().getType());
              buffer.append(" 0cm ");
              buffer.append(clipWidth / 2);
              buffer.append(imageAreaWidthVal.getType().getType());
              buffer.append(")");
              graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());

              styleName = imageStyle.getStyleName();
              getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
              imageAreaHeightVal = normalizedImageHeight;
            }
            else if (clipHeight > 0)
            {
              final OfficeStyle imageStyle = deriveStyle("graphic", "Graphics");
              final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, "graphic-properties");
              final StringBuffer buffer = new StringBuffer();
              buffer.append("rect(");
              buffer.append(clipHeight / 2);
              buffer.append(imageAreaHeightVal.getType().getType());
              buffer.append(" 0cm ");
              buffer.append(clipHeight / 2);
              buffer.append(imageAreaHeightVal.getType().getType());
              buffer.append(" 0cm)");
              graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());

              styleName = imageStyle.getStyleName();
              getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
              imageAreaWidthVal = normalizedImageWidth;
            }
            else
            {
              imageAreaWidthVal = normalizedImageWidth;
              imageAreaHeightVal = normalizedImageHeight;
            }
          }
        }
        // If we do scale, then we simply use the given image-area-size as valid image size and dont
        // care about the image itself ..
      }
      else
      {
        Log.debug("There is no image-context, so we have to rely on the image's natural bounds. " +
            "This may go awfully wrong.");
        imageAreaWidthVal = image.getWidth();
        imageAreaHeightVal = image.getHeight();
      }

      final AttributeList frameList = new AttributeList();
      frameList.setAttribute(OfficeNamespaces.DRAWING_NS, "name", imageNames.generateName("Image"));
      if (styleName != null)
      {
        frameList.setAttribute(OfficeNamespaces.DRAWING_NS, "style-name", styleName);
      }
      frameList.setAttribute(OfficeNamespaces.TEXT_NS, "anchor-type", "paragraph");
      frameList.setAttribute(OfficeNamespaces.SVG_NS, "z-index", "0");
      frameList.setAttribute(OfficeNamespaces.SVG_NS, "x", "0cm");
      frameList.setAttribute(OfficeNamespaces.SVG_NS, "y", "0cm");

      Log.debug("Image " + imageData + " A-Width: " + imageAreaWidthVal + ", A-Height: " + imageAreaHeightVal);

      if (imageAreaWidthVal != null)
      {
        frameList.setAttribute(OfficeNamespaces.SVG_NS,
            "width", String.valueOf(imageAreaWidthVal.getValue()) + imageAreaWidthVal.getType().getType());
      }

      if (imageAreaHeightVal != null)
      {
        frameList.setAttribute(OfficeNamespaces.SVG_NS,
            "height", String.valueOf(imageAreaHeightVal.getValue()) + imageAreaHeightVal.getType().getType());
      }


      final AttributeList imageList = new AttributeList();
      imageList.setAttribute(OfficeNamespaces.XLINK_NS, "href", image.getEmbeddableLink());
      imageList.setAttribute(OfficeNamespaces.XLINK_NS, "type", "simple");
      imageList.setAttribute(OfficeNamespaces.XLINK_NS, "show", "embed");
      imageList.setAttribute(OfficeNamespaces.XLINK_NS, "actuate", "onLoad");


      try
      {
        getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, "frame", frameList, XmlWriterSupport.OPEN);
        getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, "image", imageList, XmlWriterSupport.CLOSE);
        getXmlWriter().writeCloseTag();
      }
      catch (IOException ioe)
      {
        throw new ReportProcessingException("Failed", ioe);
      }
    }
  }

  private CSSNumericValue computeImageWidth(final ImageElementContext imageElementContext)
  {
    final LengthCalculator calculator = new LengthCalculator();
    final String[] strings = imageElementContext.getColStyles();
    for (int i = 0; i < strings.length; i++)
    {
      final String styleName = strings[i];
      final CSSNumericValue value = computeColumnWidth(styleName);
      if (value != null)
      {
        calculator.add(value);
      }
    }
    return calculator.getResult();
  }

  private CSSNumericValue computeImageHeight(final ImageElementContext imageElementContext)
  {
    final LengthCalculator calculator = new LengthCalculator();
    final String[] strings = imageElementContext.getRowStyles();
    for (int i = 0; i < strings.length; i++)
    {
      final String styleName = strings[i];
      final CSSNumericValue value = computeRowHeight(styleName);
      if (value != null)
      {
        calculator.add(value);
      }
    }
    return calculator.getResult();
  }


  protected CSSNumericValue computeRowHeight(final String rowStyle)
  {
    final OfficeStylesCollection contentStyles = getContentStylesCollection();
    final OfficeStyle style = contentStyles.getStyle("table-row", rowStyle);
    if (style != null)
    {
      final Element element = style.getTableRowProperties();
      if (element != null)
      {
        final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
        if (height != null)
        {
          return parseLength(height);
        }
      }

      final String styleParent = style.getStyleParent();
      if (styleParent != null)
      {
        return computeRowHeight(styleParent);
      }
    }

    final OfficeStylesCollection globalStyles = getGlobalStylesCollection();
    final OfficeStyle globalStyle = globalStyles.getStyle("table-row", rowStyle);
    if (globalStyle != null)
    {
      final Element element = globalStyle.getTableRowProperties();
      if (element != null)
      {
        final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
        if (height != null)
        {
          return parseLength(height);
        }
      }
      final String styleParent = globalStyle.getStyleParent();
      if (styleParent != null)
      {
        return computeRowHeight(styleParent);
      }
    }

    final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
    final OfficeStyle predefStyle = predefStyles.getStyle("table-row", rowStyle);
    if (predefStyle != null)
    {
      final Element element = predefStyle.getTableRowProperties();
      if (element != null)
      {
        final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
        if (height != null)
        {
          return parseLength(height);
        }
      }
      final String styleParent = predefStyle.getStyleParent();
      if (styleParent != null)
      {
        return computeRowHeight(styleParent);
      }
    }
    // not found.
    return null;
  }


  protected CSSNumericValue computeColumnWidth(final String colStyle)
  {
    final OfficeStylesCollection contentStyles = getContentStylesCollection();
    final OfficeStyle style = contentStyles.getStyle("table-column", colStyle);
    if (style != null)
    {
      final Element element = style.getTableColumnProperties();
      if (element != null)
      {
        final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
        if (height != null)
        {
          return parseLength(height);
        }
      }

      final String styleParent = style.getStyleParent();
      if (styleParent != null)
      {
        return computeRowHeight(styleParent);
      }
    }

    final OfficeStylesCollection globalStyles = getGlobalStylesCollection();
    final OfficeStyle globalStyle = globalStyles.getStyle("table-column", colStyle);
    if (globalStyle != null)
    {
      final Element element = globalStyle.getTableColumnProperties();
      if (element != null)
      {
        final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
        if (height != null)
        {
          return parseLength(height);
        }
      }
      final String styleParent = globalStyle.getStyleParent();
      if (styleParent != null)
      {
        return computeRowHeight(styleParent);
      }
    }

    final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
    final OfficeStyle predefStyle = predefStyles.getStyle("table-column", colStyle);
    if (predefStyle != null)
    {
      final Element element = predefStyle.getTableColumnProperties();
      if (element != null)
      {
        final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
        if (height != null)
        {
          return parseLength(height);
        }
      }
      final String styleParent = predefStyle.getStyleParent();
      if (styleParent != null)
      {
        return computeRowHeight(styleParent);
      }
    }
    // not found.
    return null;
  }

  protected Element produceFirstChild(final Section style,
                                      final String nameSpace,
                                      final String type)
  {
    Element paragraphProps = style.findFirstChild(nameSpace, type);
    if (paragraphProps == null)
    {
      paragraphProps = new Section();
      paragraphProps.setNamespace(nameSpace);
      paragraphProps.setType(type);
      style.addNode(paragraphProps);
    }
    return paragraphProps;
  }


}
TOP

Related Classes of com.sun.star.report.pentaho.output.OfficeDocumentReportTarget$GroupContext

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.