/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org 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 version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ package com.sun.star.report.pentaho.output; import com.sun.star.report.DataSourceFactory; import com.sun.star.report.ImageService; import com.sun.star.report.InputRepository; import com.sun.star.report.OfficeToken; import com.sun.star.report.OutputRepository; import com.sun.star.report.ReportEngineParameterNames; import com.sun.star.report.SDBCReportDataFactory; 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 java.awt.Image; import java.io.BufferedReader; 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.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jfree.layouting.input.style.parser.CSSValueFactory; import org.jfree.layouting.input.style.parser.StyleSheetParserUtil; import org.jfree.layouting.input.style.values.CSSNumericType; 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.layouting.util.LazyAttributeMap; 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.pentaho.reporting.libraries.base.util.FastStack; import org.pentaho.reporting.libraries.base.util.IOUtils; import org.pentaho.reporting.libraries.resourceloader.ResourceException; import org.pentaho.reporting.libraries.resourceloader.ResourceKey; import org.pentaho.reporting.libraries.resourceloader.ResourceManager; import org.pentaho.reporting.libraries.xmlns.common.AttributeList; import org.pentaho.reporting.libraries.xmlns.writer.DefaultTagDescription; import org.pentaho.reporting.libraries.xmlns.writer.XmlWriter; import org.pentaho.reporting.libraries.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 { protected static final Log LOGGER = LogFactory.getLog(OfficeDocumentReportTarget.class); public static final String HORIZONTAL_POS = "horizontal-pos"; 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; public static final String FAILED = "Failed"; public static final String VERTICAL_POS = "vertical-pos"; private static final String ZERO_CM = "0cm"; protected static class BufferState { private final XmlWriter xmlWriter; private final MemoryByteArrayOutputStream xmlBuffer; private final 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 final 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 final FastStack states; private int currentRole; private final 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 final OutputRepository outputRepository; private final InputRepository inputRepository; private final AttributeNameGenerator tableNameGenerator; private final AttributeNameGenerator frameNameGenerator; private final AttributeNameGenerator autoStyleNameGenerator; private final String target; private static final int INITIAL_BUFFER_SIZE = 40960; private StyleMapper styleMapper; private StyleSheetParserUtil styleSheetParserUtil; private final AttributeNameGenerator imageNames; private final ImageProducer imageProducer; private final OleProducer oleProducer; 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, final DataSourceFactory datasourcefactory) 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.frameNameGenerator = new AttributeNameGenerator(); this.autoStyleNameGenerator = new AttributeNameGenerator(); this.outputRepository = outputRepository; this.inputRepository = inputRepository; this.states = new FastStack(); this.xmlWriters = new FastStack(); this.imageNames = new AttributeNameGenerator(); this.imageProducer = new ImageProducer(inputRepository, outputRepository, imageService); this.oleProducer = new OleProducer(inputRepository, outputRepository, imageService, datasourcefactory, (Integer) reportJob.getParameters().get(ReportEngineParameterNames.MAXROWS)); 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; } protected InputRepository getInputRepository() { return inputRepository; } /** * 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("chartooo", OfficeNamespaces.CHARTOOO_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.addNamespaceDeclaration("grddl", OfficeNamespaces.GRDDL_NS); rootAttributes.setAttribute(OfficeNamespaces.OFFICE_NS, "version", "1.2"); 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(); frameNameGenerator.reset(); final OfficeDocument reportDoc = (OfficeDocument) report; predefinedStylesCollection = reportDoc.getStylesCollection(); final OfficeStyles commonStyles = predefinedStylesCollection.getCommonStyles(); if (!commonStyles.containsStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS)) { final OfficeStyle graphicsDefaultStyle = new OfficeStyle(); graphicsDefaultStyle.setStyleFamily(OfficeToken.GRAPHIC); graphicsDefaultStyle.setStyleName(OfficeToken.GRAPHICS); final Element graphicProperties = produceFirstChild(graphicsDefaultStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES); graphicProperties.setAttribute(OfficeNamespaces.TEXT_NS, "anchor-type", OfficeToken.PARAGRAPH); graphicProperties.setAttribute(OfficeNamespaces.SVG_NS, "x", ZERO_CM); graphicProperties.setAttribute(OfficeNamespaces.SVG_NS, "y", ZERO_CM); graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "wrap", "dynamic"); graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "number-wrapped-paragraphs", "no-limit"); graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "wrap-contour", OfficeToken.FALSE); graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, VERTICAL_POS, "from-top"); // changed for chart graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "vertical-rel", OfficeToken.PARAGRAPH); graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, HORIZONTAL_POS, "from-left"); // changed for chart graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "horizontal-rel", OfficeToken.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; } /** * 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 roAttrs the attribute map for the current element * @throws DataSourceException * @throws ReportProcessingException */ public final void startElement(final AttributeMap roAttrs) throws DataSourceException, ReportProcessingException { final AttributeMap attrs = new LazyAttributeMap(roAttrs); // todo if (DEBUG_ELEMENTS) { LOGGER.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))) { startOther(attrs); } } break; } 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'"); } break; } case OfficeDocumentReportTarget.STATE_IN_CONTENT: { // Either a ordinary section or a group .. // A group. if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "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(JFreeReportInfo.REPORT_NAMESPACE, "template", attrs)) { currentRole = OfficeDocumentReportTarget.ROLE_TEMPLATE; } else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "page-header", attrs)) { if ("spreadsheet-section".equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "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(JFreeReportInfo.REPORT_NAMESPACE, "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(JFreeReportInfo.REPORT_NAMESPACE, "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); } break; } 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(JFreeReportInfo.REPORT_NAMESPACE, "variables-section", attrs)) { currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES; } else { throw new IllegalStateException("Expected either 'group', 'detail' or 'variables-section'"); } startReportSection(attrs, currentRole); } break; } case OfficeDocumentReportTarget.STATE_IN_GROUP: { // A group can carry a repeating group header/footer or a group-instance section. if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "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) && OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "repeated-section"))) { currentRole = OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER; } else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-footer", attrs) && OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "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); } break; } case OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE: { if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "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(JFreeReportInfo.REPORT_NAMESPACE, "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); } break; } case OfficeDocumentReportTarget.STATE_IN_SECTION: { states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER)); startOther(attrs); break; } case OfficeDocumentReportTarget.STATE_IN_OTHER: { states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER)); startOther(attrs); break; } default: throw new IllegalStateException("Failure: " + getCurrentState()); } } catch (IOException ioe) { LOGGER.error("ReportProcessing failed", ioe); throw new ReportProcessingException("Failed to write content", ioe); } // finally // { // LOGGER.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. LOGGER.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); } private final boolean allowBuffering(final int role) { return (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER || role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER || role == OfficeDocumentReportTarget.ROLE_TEMPLATE); } protected void startReportSection(final AttributeMap attrs, final int role) throws IOException, DataSourceException, ReportProcessingException { if (allowBuffering(role)) { 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(JFreeReportInfo.REPORT_NAMESPACE, "repeating-header-or-footer"); if (OfficeToken.TRUE.equals(repeatingHeaderOrFooter)) { getGroupContext().setGroupWithRepeatingSection(true); } final Object iterationCount = attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "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 BufferedReader br = new BufferedReader(new StringReader(text)); String line = br.readLine(); while (line != null) { xmlWriter.writeTextNormalized(line, false); line = br.readLine(); if (line != null) { 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 (JFreeReportInfo.REPORT_NAMESPACE.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 BufferedReader br = new BufferedReader(new StringReader(text)); String line = br.readLine(); while (line != null) { xmlWriter.writeTextNormalized(line, false); line = br.readLine(); if (line != null) { xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, "line-break", XmlWriterSupport.CLOSE); } } } catch (IOException e) { throw new ReportProcessingException(FAILED, e); } } public final void endElement(final AttributeMap roAttrs) throws DataSourceException, ReportProcessingException { final AttributeMap attrs = new LazyAttributeMap(roAttrs); // final int oldState = getCurrentState(); try { switch (getCurrentState()) { case OfficeDocumentReportTarget.STATE_IN_OTHER: { endOther(attrs); break; } case OfficeDocumentReportTarget.STATE_IN_SECTION: { endReportSection(attrs, currentRole); currentRole = OfficeDocumentReportTarget.ROLE_NONE; break; } case OfficeDocumentReportTarget.STATE_IN_GROUP: { endGroup(attrs); groupContext = groupContext.getParent(); break; } case OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE: { endGroupInstance(attrs); break; } case OfficeDocumentReportTarget.STATE_IN_GROUP_BODY: { endGroupBody(attrs); break; } case OfficeDocumentReportTarget.STATE_IN_CONTENT: { endContent(attrs); break; } case OfficeDocumentReportTarget.STATE_IN_BODY: { endBody(attrs); break; } 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) { LOGGER.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 (allowBuffering(role)) { 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", ioe); } } public BufferState finishBuffering() throws ReportProcessingException { final BufferState state = (BufferState) xmlWriters.pop(); try { state.getXmlWriter().close(); } catch (IOException e) { LOGGER.error("ReportProcessing failed", e); } 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 String elementType = ReportTargetUtil.getElemenTypeFromAttribute(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 if (OfficeNamespaces.DRAWING_NS.equals(attrNamespace) && "name".equals(key) && !"equation".equals(elementType)) { final String objectName = String.valueOf(entry.getValue()); attrList.setAttribute(attrNamespace, key, frameNameGenerator.generateName(objectName)); } 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(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.IMAGE_DATA); final boolean preserveIRI = OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.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(JFreeReportInfo.REPORT_NAMESPACE, "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 LOGGER.debug("Image " + imageData + " Width: " + width + ", Height: " + height); if (width == null || height == null) { return; } CSSNumericValue imageAreaWidthVal; CSSNumericValue imageAreaHeightVal; CSSNumericValue posX = CSSNumericValue.createValue(CSSNumericType.CM, 0.0); CSSNumericValue posY = CSSNumericValue.createValue(CSSNumericType.CM, 0.0); String styleName = null; if (imageContext != null) { imageAreaWidthVal = computeImageWidth(imageContext); imageAreaHeightVal = computeImageHeight(imageContext); if (imageAreaWidthVal == null || imageAreaHeightVal == null) { LOGGER.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 String scale = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.SCALE); if (OfficeToken.NONE.equals(scale) && 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(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS); final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.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(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS); final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.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(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS); final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.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; } } else if (OfficeToken.ISOTROPIC.equals(scale)) { final double[] ret = calcPaintSize(imageAreaWidthVal, imageAreaHeightVal, normalizedImageWidth, normalizedImageHeight); posX = CSSNumericValue.createValue(imageAreaWidthVal.getType(), (imageAreaWidthVal.getValue() - ret[0]) * 0.5); posY = CSSNumericValue.createValue(imageAreaHeightVal.getType(), (imageAreaHeightVal.getValue() - ret[1]) * 0.5); imageAreaWidthVal = CSSNumericValue.createValue(imageAreaWidthVal.getType(), ret[0]); imageAreaHeightVal = CSSNumericValue.createValue(imageAreaHeightVal.getType(), ret[1]); } } // 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 { LOGGER.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, OfficeToken.STYLE_NAME, styleName); } frameList.setAttribute(OfficeNamespaces.TEXT_NS, "anchor-type", OfficeToken.PARAGRAPH); frameList.setAttribute(OfficeNamespaces.SVG_NS, "z-index", "0"); frameList.setAttribute(OfficeNamespaces.SVG_NS, "x", posX.getValue() + posX.getType().getType()); frameList.setAttribute(OfficeNamespaces.SVG_NS, "y", posY.getValue() + posY.getType().getType()); LOGGER.debug("Image " + imageData + " A-Width: " + imageAreaWidthVal + ", A-Height: " + imageAreaHeightVal); if (imageAreaWidthVal != null) { frameList.setAttribute(OfficeNamespaces.SVG_NS, "width", imageAreaWidthVal.getValue() + imageAreaWidthVal.getType().getType()); } if (imageAreaHeightVal != null) { frameList.setAttribute(OfficeNamespaces.SVG_NS, "height", 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, OfficeToken.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(OfficeToken.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(OfficeToken.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(OfficeToken.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(OfficeToken.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(OfficeToken.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(OfficeToken.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; } protected void startChartProcessing(final AttributeMap attrs) throws ReportProcessingException { final String classId = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "class-id"); final String chartUrl = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "href"); final ArrayList masterColumns = (ArrayList) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_COLUMNS); final ArrayList masterValues = (ArrayList) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_VALUES); final ArrayList detailColumns = (ArrayList) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.DETAIL_COLUMNS); final String href = oleProducer.produceOle(chartUrl, masterColumns, masterValues, detailColumns); final AttributeList oleList = new AttributeList(); oleList.setAttribute(OfficeNamespaces.DRAWING_NS, "class-id", classId); oleList.setAttribute(OfficeNamespaces.XLINK_NS, "href", "./" + href); oleList.setAttribute(OfficeNamespaces.XLINK_NS, "type", "simple"); oleList.setAttribute(OfficeNamespaces.XLINK_NS, "show", "embed"); oleList.setAttribute(OfficeNamespaces.XLINK_NS, "actuate", "onLoad"); try { getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, OfficeToken.OBJECT_OLE, oleList, XmlWriterSupport.CLOSE); } catch (IOException ioe) { throw new ReportProcessingException(FAILED, ioe); } } static private double[] calcPaintSize(final CSSNumericValue areaWidth, final CSSNumericValue areaHeight, final CSSNumericValue imageWidth, final CSSNumericValue imageHeight) { final double ratioX = areaWidth.getValue() / imageWidth.getValue(); final double ratioY = areaHeight.getValue() / imageHeight.getValue(); final double ratioMin = Math.min(ratioX, ratioY); double[] ret = new double[2]; ret[0] = imageWidth.getValue() * ratioMin; ret[1] = imageHeight.getValue() * ratioMin; return ret; } protected void writeNullDate() throws IOException { // write NULL DATE final XmlWriter xmlWriter = getXmlWriter(); xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, "calculation-settings", null, XmlWriterSupport.OPEN); final AttributeMap nullDateAttributes = new AttributeMap(); nullDateAttributes.setAttribute(OfficeNamespaces.TABLE_NS, "date-value", "1900-01-01"); xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, "null-date", buildAttributeList(nullDateAttributes), XmlWriterSupport.CLOSE); xmlWriter.writeCloseTag(); } }