blob: ac23ceec4a4d33b696301106bc82027fca548ed9 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
package com.sun.star.report.pentaho.output.text;
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.pentaho.OfficeNamespaces;
import com.sun.star.report.pentaho.PentahoReportEngineMetaData;
import com.sun.star.report.pentaho.layoutprocessor.FormatValueUtility;
import com.sun.star.report.pentaho.model.OfficeMasterPage;
import com.sun.star.report.pentaho.model.OfficeMasterStyles;
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.model.PageSection;
import com.sun.star.report.pentaho.output.OfficeDocumentReportTarget;
import com.sun.star.report.pentaho.output.StyleUtilities;
import com.sun.star.report.pentaho.styles.LengthCalculator;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import org.jfree.layouting.input.style.values.CSSNumericValue;
import org.jfree.layouting.util.AttributeMap;
import org.jfree.report.DataSourceException;
import org.jfree.report.JFreeReportInfo;
import org.jfree.report.ReportProcessingException;
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.pentaho.reporting.libraries.base.util.FastStack;
import org.pentaho.reporting.libraries.base.util.ObjectUtilities;
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.XmlWriter;
import org.pentaho.reporting.libraries.xmlns.writer.XmlWriterSupport;
/**
* Creation-Date: 03.07.2006, 16:28:00
*
* @author Thomas Morgner
*/
public class TextRawReportTarget extends OfficeDocumentReportTarget
{
private static final String ALWAYS = "always";
private static final String KEEP_TOGETHER = "keep-together";
private static final String KEEP_WITH_NEXT = "keep-with-next";
private static final String MAY_BREAK_BETWEEN_ROWS = "may-break-between-rows";
private static final String NAME = "name";
private static final String NONE = "none";
private static final String NORMAL = "normal";
private static final String PARAGRAPH_PROPERTIES = "paragraph-properties";
private static final String STANDARD = "Standard";
private static final String TABLE_PROPERTIES = "table-properties";
private static final String VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT = "variables_paragraph_with_next";
private static final String VARIABLES_HIDDEN_STYLE_WITHOUT_KEEPWNEXT = "variables_paragraph_without_next";
private static final int TABLE_LAYOUT_VARIABLES_PARAGRAPH = 0;
private static final int TABLE_LAYOUT_SINGLE_DETAIL_TABLE = 2;
private static final int CP_SETUP = 0;
private static final int CP_FIRST_TABLE = 1;
private static final int CP_NEXT_TABLE = 2;
// This is the initial state of the detail-band processing. It states, that we are now waiting for a
// detail-band to be printed.
private static final int DETAIL_SECTION_WAIT = 0;
// The first detail section has started.
private static final int DETAIL_SECTION_FIRST_STARTED = 1;
// The first detail section has been printed.
private static final int DETAIL_SECTION_FIRST_PRINTED = 2;
// An other detail section has started
private static final int DETAIL_SECTION_OTHER_STARTED = 3;
// The other detail section has been printed.
private static final int DETAIL_SECTION_OTHER_PRINTED = 4;
private boolean pageFooterOnReportFooter;
private boolean pageFooterOnReportHeader;
private boolean pageHeaderOnReportFooter;
private boolean pageHeaderOnReportHeader;
private int contentProcessingState;
private OfficeMasterPage currentMasterPage;
private final FastStack activePageContext;
private MasterPageFactory masterPageFactory;
private LengthCalculator sectionHeight;
private String variables;
private PageBreakDefinition pageBreakDefinition;
private VariablesDeclarations variablesDeclarations;
private boolean columnBreakPending;
private boolean sectionKeepTogether;
private final AttributeNameGenerator sectionNames;
private int detailBandProcessingState;
private final int tableLayoutConfig;
private int expectedTableRowCount;
private boolean firstCellSeen;
public TextRawReportTarget(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, inputRepository, outputRepository, target, imageService, datasourcefactory);
activePageContext = new FastStack();
this.sectionNames = new AttributeNameGenerator();
this.tableLayoutConfig = TABLE_LAYOUT_SINGLE_DETAIL_TABLE;
}
protected String getTargetMimeType()
{
return "application/vnd.oasis.opendocument.text";
}
/**
* Checks, whether a manual page break should be inserted at the next possible location.
*
* @return true, if a pagebreak is pending, false otherwise.
*/
private boolean isPagebreakPending()
{
return pageBreakDefinition != null;
}
private boolean isResetPageNumber()
{
return pageBreakDefinition != null && pageBreakDefinition.isResetPageNumber();
}
/**
* Defines, whether a manual pagebreak should be inserted at the next possible location.
*
* @param pageBreakDefinition the new flag value.
*/
private void setPagebreakDefinition(final PageBreakDefinition pageBreakDefinition)
{
this.pageBreakDefinition = pageBreakDefinition;
}
private PageBreakDefinition getPagebreakDefinition()
{
return pageBreakDefinition;
}
// todo
private boolean isKeepTableWithNext()
{
final int keepTogetherState = getCurrentContext().getKeepTogether();
if (keepTogetherState == PageContext.KEEP_TOGETHER_GROUP)
{
return true;
}
final boolean keepWithNext;
keepWithNext = keepTogetherState == PageContext.KEEP_TOGETHER_FIRST_DETAIL && (detailBandProcessingState == DETAIL_SECTION_WAIT);
return keepWithNext;
}
private boolean isSectionPagebreakAfter(final AttributeMap attrs)
{
final Object forceNewPage =
attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "force-new-page");
return "after-section".equals(forceNewPage) || "before-after-section".equals(forceNewPage);
}
private boolean isSectionPagebreakBefore(final AttributeMap attrs)
{
final Object forceNewPage =
attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "force-new-page");
return "before-section".equals(forceNewPage) || "before-after-section".equals(forceNewPage);
}
private PageContext getCurrentContext()
{
return (PageContext) activePageContext.peek();
}
private String createMasterPage(final boolean printHeader,
final boolean printFooter)
throws ReportProcessingException
{
// create the master page for the report-header.
// If there is a page-header or footer in the report that gets
// surpressed on the report-header, we have to insert a pagebreak
// afterwards.
final String activePageFooter;
// Check, whether the report header can have a page-header
final PageContext context = getCurrentContext();
if (printFooter)
{
activePageFooter = context.getPageFooterContent();
}
else
{
activePageFooter = null;
}
final String activePageHeader;
if (printHeader)
{
// we have to insert a manual pagebreak after the report header.
activePageHeader = context.getPageHeaderContent();
}
else
{
activePageHeader = null;
}
final String masterPageName;
if (currentMasterPage == null || !masterPageFactory.containsMasterPage(STANDARD, activePageHeader, activePageFooter))
{
final CSSNumericValue headerSize = context.getAllHeaderSize();
final CSSNumericValue footerSize = context.getAllFooterSize();
currentMasterPage = masterPageFactory.createMasterPage(STANDARD, activePageHeader, activePageFooter);
// LOGGER.debug("Created a new master-page: " + currentMasterPage.getStyleName());
// todo: Store the page-layouts as well.
// The page layouts are derived from a common template, but as the
// header-heights differ, we have to derive these beasts instead
// of copying them
final OfficeStylesCollection officeStylesCollection = getGlobalStylesCollection();
final OfficeMasterStyles officeMasterStyles = officeStylesCollection.getMasterStyles();
final String pageLayoutTemplate = currentMasterPage.getPageLayout();
if (pageLayoutTemplate == null)
{
// there is no pagelayout. Create one ..
final String derivedLayout = masterPageFactory.createPageStyle(getGlobalStylesCollection().getAutomaticStyles(), headerSize, footerSize);
currentMasterPage.setPageLayout(derivedLayout);
}
else
{
final String derivedLayout = masterPageFactory.derivePageStyle(pageLayoutTemplate,
getPredefinedStylesCollection().getAutomaticStyles(),
getGlobalStylesCollection().getAutomaticStyles(), headerSize, footerSize);
currentMasterPage.setPageLayout(derivedLayout);
}
officeMasterStyles.addMasterPage(currentMasterPage);
masterPageName = currentMasterPage.getStyleName();
}
else
{
// retrieve the master-page.
final OfficeMasterPage masterPage = masterPageFactory.getMasterPage(STANDARD, activePageHeader, activePageFooter);
if (ObjectUtilities.equal(masterPage.getStyleName(), currentMasterPage.getStyleName()))
{
// They are the same,
masterPageName = null;
}
else
{
// reuse the existing one ..
currentMasterPage = masterPage;
masterPageName = currentMasterPage.getStyleName();
}
}
// if either the pageheader or footer are *not* printed with the
// report header, then this implies that we have to insert a manual
// pagebreak at the end of the section.
if ((!printHeader && context.getHeader() != null) || (!printFooter && context.getFooter() != null))
{
setPagebreakDefinition(new PageBreakDefinition(isResetPageNumber()));
}
return masterPageName;
}
private boolean isColumnBreakPending()
{
return columnBreakPending;
}
private void setColumnBreakPending(final boolean columnBreakPending)
{
this.columnBreakPending = columnBreakPending;
}
private Integer parseInt(final Object value)
{
if (value instanceof Number)
{
final Number n = (Number) value;
return IntegerCache.getInteger(n.intValue());
}
if (value instanceof String)
{
try
{
return IntegerCache.getInteger(Integer.parseInt((String) value));
}
catch (NumberFormatException nfe)
{
//return null; // ignore
}
}
return null;
}
private BufferState applyColumnsToPageBand(final BufferState contents,
final int numberOfColumns)
throws IOException, ReportProcessingException
{
if (numberOfColumns <= 1)
{
return contents;
}
startBuffering(getGlobalStylesCollection(), true);
// derive section style ..
// This is a rather cheap solution to the problem. In a sane world, we would have to feed the
// footer multiple times. Right now, we simply rely on the balacing, which should make sure that
// the column's content are evenly distributed.
final XmlWriter writer = getXmlWriter();
final AttributeList attrs = new AttributeList();
attrs.setAttribute(OfficeNamespaces.TEXT_NS, OfficeToken.STYLE_NAME, generateSectionStyle(numberOfColumns));
attrs.setAttribute(OfficeNamespaces.TEXT_NS, NAME, sectionNames.generateName("Section"));
writer.writeTag(OfficeNamespaces.TEXT_NS, "section", attrs, XmlWriterSupport.OPEN);
for (int i = 0; i < numberOfColumns; i++)
{
writer.writeStream(contents.getXmlAsReader());
}
writer.writeCloseTag();
return finishBuffering();
}
private String generateSectionStyle(final int columnCount)
{
final OfficeStyles automaticStyles = getStylesCollection().getAutomaticStyles();
final String styleName = getAutoStyleNameGenerator().generateName("auto_section_style");
final Section sectionProperties = new Section();
sectionProperties.setNamespace(OfficeNamespaces.STYLE_NS);
sectionProperties.setType("section-properties");
sectionProperties.setAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR, "transparent");
sectionProperties.setAttribute(OfficeNamespaces.TEXT_NS, "dont-balance-text-columns", OfficeToken.FALSE);
sectionProperties.setAttribute(OfficeNamespaces.STYLE_NS, "editable", OfficeToken.FALSE);
if (columnCount > 1)
{
final Section columns = new Section();
columns.setNamespace(OfficeNamespaces.STYLE_NS);
columns.setType("columns");
columns.setAttribute(OfficeNamespaces.FO_NS, "column-count", String.valueOf(columnCount));
columns.setAttribute(OfficeNamespaces.STYLE_NS, "column-gap", "0cm");
sectionProperties.addNode(columns);
// final Section columnSep = new Section();
// columnSep.setNamespace(OfficeNamespaces.STYLE_NS);
// columnSep.setType("column-sep");
// columnSep.setAttribute(OfficeNamespaces.STYLE_NS, "width", "0.035cm");
// columnSep.setAttribute(OfficeNamespaces.STYLE_NS, "color", "#000000");
// columnSep.setAttribute(OfficeNamespaces.STYLE_NS, "height", "100%");
// columns.addNode(columnSep);
for (int i = 0; i < columnCount; i++)
{
final Section column = new Section();
column.setNamespace(OfficeNamespaces.STYLE_NS);
column.setType("column");
column.setAttribute(OfficeNamespaces.STYLE_NS, "rel-width", "1*");
column.setAttribute(OfficeNamespaces.FO_NS, "start-indent", "0cm");
column.setAttribute(OfficeNamespaces.FO_NS, "end-indent", "0cm");
columns.addNode(column);
}
}
final OfficeStyle style = new OfficeStyle();
style.setNamespace(OfficeNamespaces.STYLE_NS);
style.setType("style");
style.setAttribute(OfficeNamespaces.STYLE_NS, NAME, styleName);
style.setAttribute(OfficeNamespaces.STYLE_NS, "family", "section");
style.addNode(sectionProperties);
automaticStyles.addStyle(style);
return styleName;
}
/**
* 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 org.jfree.report.DataSourceException
* if there was an error accessing the datasource
* @throws org.jfree.report.ReportProcessingException
* if some other error occured.
*/
public void startReport(final ReportStructureRoot report)
throws DataSourceException, ReportProcessingException
{
super.startReport(report);
variablesDeclarations = new VariablesDeclarations();
detailBandProcessingState = DETAIL_SECTION_WAIT;
sectionNames.reset();
pageFooterOnReportFooter = false;
pageFooterOnReportHeader = false;
pageHeaderOnReportFooter = false;
pageHeaderOnReportHeader = false;
contentProcessingState = TextRawReportTarget.CP_SETUP;
activePageContext.clear();
activePageContext.push(new PageContext());
final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
masterPageFactory = new MasterPageFactory(predefStyles.getMasterStyles());
predefStyles.getAutomaticStyles().addStyle(createVariablesStyle(true));
predefStyles.getAutomaticStyles().addStyle(createVariablesStyle(false));
}
private OfficeStyle createVariablesStyle(final boolean keepWithNext)
{
final OfficeStyle variablesSectionStyle = new OfficeStyle();
variablesSectionStyle.setStyleFamily(OfficeToken.PARAGRAPH);
if (keepWithNext)
{
variablesSectionStyle.setStyleName(TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT);
}
else
{
variablesSectionStyle.setStyleName(TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITHOUT_KEEPWNEXT);
}
final Section paragraphProps = new Section();
paragraphProps.setNamespace(OfficeNamespaces.STYLE_NS);
paragraphProps.setType(PARAGRAPH_PROPERTIES);
paragraphProps.setAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR, "transparent");
paragraphProps.setAttribute(OfficeNamespaces.FO_NS, "text-align", "start");
paragraphProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_WITH_NEXT, ALWAYS);
paragraphProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_TOGETHER, ALWAYS);
paragraphProps.setAttribute(OfficeNamespaces.STYLE_NS, "vertical-align", "top");
variablesSectionStyle.addNode(paragraphProps);
final Section textProps = new Section();
textProps.setNamespace(OfficeNamespaces.STYLE_NS);
textProps.setType("text-properties");
textProps.setAttribute(OfficeNamespaces.FO_NS, "font-variant", NORMAL);
textProps.setAttribute(OfficeNamespaces.FO_NS, "text-transform", NONE);
textProps.setAttribute(OfficeNamespaces.FO_NS, "color", "#ffffff");
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-outline", OfficeToken.FALSE);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-blinking", OfficeToken.FALSE);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-line-through-style", NONE);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-line-through-mode", "continuous");
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-position", "0% 100%");
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "font-name", "Tahoma");
textProps.setAttribute(OfficeNamespaces.FO_NS, "font-size", "1pt");
textProps.setAttribute(OfficeNamespaces.FO_NS, "letter-spacing", NORMAL);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "letter-kerning", OfficeToken.FALSE);
textProps.setAttribute(OfficeNamespaces.FO_NS, "font-style", NORMAL);
textProps.setAttribute(OfficeNamespaces.FO_NS, "text-shadow", NONE);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-underline-style", NONE);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-underline-mode", "continuous");
textProps.setAttribute(OfficeNamespaces.FO_NS, "font-weight", NORMAL);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-rotation-angle", "0");
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-emphasize", NONE);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-combine", NONE);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-combine-start-char", "");
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-combine-end-char", "");
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-blinking", OfficeToken.FALSE);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-scale", "100%");
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "font-relief", NONE);
textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-display", NONE);
variablesSectionStyle.addNode(textProps);
return variablesSectionStyle;
}
protected void startContent(final AttributeMap attrs)
throws IOException, DataSourceException, ReportProcessingException
{
final XmlWriter xmlWriter = getXmlWriter();
xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "text", null, XmlWriterSupport.OPEN);
writeNullDate();
// now start the buffering. We have to insert the variables declaration
// later ..
startBuffering(getStylesCollection(), true);
final Object columnCountRaw = attrs.getAttribute(OfficeNamespaces.FO_NS, "column-count");
final Integer colCount = parseInt(columnCountRaw);
if (colCount != null)
{
final PageContext pageContext = getCurrentContext();
pageContext.setColumnCount(colCount);
}
}
protected void startOther(final AttributeMap attrs)
throws IOException, DataSourceException, ReportProcessingException
{
final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
if (ObjectUtilities.equal(JFreeReportInfo.REPORT_NAMESPACE, namespace))
{
if (ObjectUtilities.equal(OfficeToken.IMAGE, elementType))
{
startImageProcessing(attrs);
}
else if (ObjectUtilities.equal(OfficeToken.OBJECT_OLE, elementType) && getCurrentRole() != ROLE_TEMPLATE)
{
startChartProcessing(attrs);
}
return;
}
else if (isFilteredNamespace(namespace))
{
throw new IllegalStateException("This element should be hidden: " + namespace + ", " + elementType);
}
if (isTableMergeActive() && detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED && ObjectUtilities.equal(OfficeNamespaces.TABLE_NS, namespace) && ObjectUtilities.equal(OfficeToken.TABLE_COLUMNS, elementType))
{
// Skip the columns section if the tables get merged..
startBuffering(getStylesCollection(), true);
}
else
{
openSection();
final boolean isTableNS = ObjectUtilities.equal(OfficeNamespaces.TABLE_NS, namespace);
if (isTableNS)
{
if (ObjectUtilities.equal(OfficeToken.TABLE, elementType))
{
startTable(attrs);
return;
}
if (ObjectUtilities.equal(OfficeToken.TABLE_ROW, elementType))
{
startRow(attrs);
return;
}
}
if (ObjectUtilities.equal(OfficeNamespaces.TEXT_NS, namespace))
{
if (ObjectUtilities.equal("variable-set", elementType))
{
// update the variables-declaration thingie ..
final String varName = (String) attrs.getAttribute(OfficeNamespaces.TEXT_NS, NAME);
final String varType = (String) attrs.getAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE);
final String newVarName = variablesDeclarations.produceVariable(varName, varType);
attrs.setAttribute(OfficeNamespaces.TEXT_NS, NAME, newVarName);
}
else if (ObjectUtilities.equal("variable-get", elementType))
{
final String varName = (String) attrs.getAttribute(OfficeNamespaces.TEXT_NS, NAME);
final String varType = (String) attrs.getAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE);
final String newVarName = variablesDeclarations.produceVariable(varName, varType);
attrs.setAttribute(OfficeNamespaces.TEXT_NS, NAME, newVarName);
// this one must not be written, as the DTD does not declare it.
// attrs.setAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE, null);
}
}
if (tableLayoutConfig == TABLE_LAYOUT_VARIABLES_PARAGRAPH && variables != null)
{
// This cannot happen as long as the report sections only contain tables. But at some point in the
// future they will be made of paragraphs, and then we are prepared ..
// LOGGER.debug("Variables-Section in own paragraph " + variables);
StyleUtilities.copyStyle(OfficeToken.PARAGRAPH,
TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, getStylesCollection(),
getGlobalStylesCollection(), getPredefinedStylesCollection());
final XmlWriter xmlWriter = getXmlWriter();
xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME,
TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, XmlWriterSupport.OPEN);
xmlWriter.writeText(variables);
xmlWriter.writeCloseTag();
variables = null;
}
final boolean keepTogetherOnParagraph = true;
if (keepTogetherOnParagraph)
{
if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TEXT_NS, OfficeToken.P, attrs))
{
final int keepTogetherState = getCurrentContext().getKeepTogether();
if (!firstCellSeen && (sectionKeepTogether || keepTogetherState == PageContext.KEEP_TOGETHER_GROUP))
{
OfficeStyle style = null;
final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TEXT_NS, OfficeToken.STYLE_NAME);
if (styleName == null)
{
final boolean keep = (keepTogetherState == PageContext.KEEP_TOGETHER_GROUP || expectedTableRowCount > 0) && isParentKeepTogether();
final ArrayList propertyNameSpaces = new ArrayList();
final ArrayList propertyNames = new ArrayList();
final ArrayList propertyValues = new ArrayList();
propertyNameSpaces.add(OfficeNamespaces.FO_NS);
propertyNameSpaces.add(OfficeNamespaces.FO_NS);
propertyNames.add(KEEP_TOGETHER);
propertyValues.add(ALWAYS);
if (keep)
{
propertyNames.add(KEEP_WITH_NEXT);
propertyValues.add(ALWAYS);
}
else
{
propertyNames.add(KEEP_WITH_NEXT);
propertyValues.add(null);
}
style = StyleUtilities.queryStyleByProperties(getStylesCollection(), OfficeToken.PARAGRAPH, PARAGRAPH_PROPERTIES, propertyNameSpaces, propertyNames, propertyValues);
}
if (style == null)
{
style = deriveStyle(OfficeToken.PARAGRAPH, styleName);
// Lets set the 'keep-together' flag..
Element paragraphProps = style.getParagraphProperties();
if (paragraphProps == null)
{
paragraphProps = new Section();
paragraphProps.setNamespace(OfficeNamespaces.STYLE_NS);
paragraphProps.setType(PARAGRAPH_PROPERTIES);
style.addNode(paragraphProps);
}
paragraphProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_TOGETHER, ALWAYS);
// We prevent pagebreaks within the two adjacent rows (this one and the next one) if
// either a group-wide keep-together is defined or if we haven't reached the end of the
// current section yet.
if ((keepTogetherState == PageContext.KEEP_TOGETHER_GROUP || expectedTableRowCount > 0) && isParentKeepTogether())
{
paragraphProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_WITH_NEXT, ALWAYS);
}
}
attrs.setAttribute(OfficeNamespaces.TEXT_NS, OfficeToken.STYLE_NAME, style.getStyleName());
}
}
}
if (ObjectUtilities.equal(OfficeNamespaces.DRAWING_NS, namespace) && ObjectUtilities.equal(OfficeToken.FRAME, elementType))
{
final String styleName = (String) attrs.getAttribute(OfficeNamespaces.DRAWING_NS, OfficeToken.STYLE_NAME);
final OfficeStyle predefAutoStyle = getPredefinedStylesCollection().getAutomaticStyles().getStyle(OfficeToken.GRAPHIC, styleName);
if (predefAutoStyle != null)
{
// special ole handling
final Element graphicProperties = predefAutoStyle.getGraphicProperties();
graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, VERTICAL_POS, "from-top");
graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, HORIZONTAL_POS, "from-left");
graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "vertical-rel", "paragraph-content");
graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "horizontal-rel", "paragraph");
graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "flow-with-text", "false");
graphicProperties.setAttribute(OfficeNamespaces.DRAWING_NS, "ole-draw-aspect", "1");
// attrs.setAttribute(OfficeNamespaces.DRAWING_NS, OfficeToken.STYLE_NAME, predefAutoStyle.getStyleName());
}
}
// process the styles as usual
performStyleProcessing(attrs);
final XmlWriter xmlWriter = getXmlWriter();
final AttributeList attrList = buildAttributeList(attrs);
xmlWriter.writeTag(namespace, elementType, attrList, XmlWriterSupport.OPEN);
if (tableLayoutConfig != TABLE_LAYOUT_VARIABLES_PARAGRAPH
&& variables != null
&& !isRepeatingSection()
&& ReportTargetUtil.isElementOfType(OfficeNamespaces.TEXT_NS, OfficeToken.P, attrs))
{
//LOGGER.debug("Variables-Section in existing cell " + variables);
xmlWriter.writeText(variables);
variables = null;
}
}
}
private void startRow(final AttributeMap attrs)
throws IOException, ReportProcessingException
{
firstCellSeen = false;
expectedTableRowCount -= 1;
final String rowStyle = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
final CSSNumericValue rowHeight = computeRowHeight(rowStyle);
// LOGGER.debug("Adding row-Style: " + rowStyle + " " + rowHeight);
sectionHeight.add(rowHeight);
// if (expectedTableRowCount > 0)
// {
// // Some other row. Create a keep-together
//
// }
// else
// {
// // This is the last row before the section will end.
// // or (in some weird cases) There is no information when the row will end.
// // Anyway, if we are here, we do not create a keep-together style on the table-row ..
// }
// process the styles as usual
performStyleProcessing(attrs);
final AttributeList attrList = buildAttributeList(attrs);
getXmlWriter().writeTag(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_ROW, attrList, XmlWriterSupport.OPEN);
}
private void startTable(final AttributeMap attrs)
throws ReportProcessingException, IOException
{
final Integer trc = (Integer) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "table-row-count");
if (trc == null)
{
expectedTableRowCount = -1;
}
else
{
expectedTableRowCount = trc;
}
if (isSectionPagebreakBefore(attrs))
{
// force a pagebreak ..
setPagebreakDefinition(new PageBreakDefinition(isResetPageNumber()));
}
// its a table. This means, it is a root-level element
final PageBreakDefinition breakDefinition;
String masterPageName = null;
final int currentRole = getCurrentRole();
if (contentProcessingState == TextRawReportTarget.CP_FIRST_TABLE)
{
contentProcessingState = TextRawReportTarget.CP_NEXT_TABLE;
// Processing the report header now.
if (currentRole == OfficeDocumentReportTarget.ROLE_REPORT_HEADER)
{
breakDefinition = new PageBreakDefinition(isResetPageNumber());
masterPageName = createMasterPage(pageHeaderOnReportHeader, pageFooterOnReportHeader);
if (masterPageName == null)
{
// we should always have a master-page ...
masterPageName = currentMasterPage.getStyleName();
}
}
else if (currentRole == OfficeDocumentReportTarget.ROLE_REPORT_FOOTER)
{
breakDefinition = new PageBreakDefinition(isResetPageNumber());
masterPageName = createMasterPage(pageHeaderOnReportFooter, pageFooterOnReportFooter);
if (masterPageName == null && isSectionPagebreakBefore(attrs))
{
// If we have a manual pagebreak, then activate the current master-page again.
masterPageName = currentMasterPage.getStyleName();
}
// But we skip this (and therefore the resulting pagebreak) if there is no manual break
// and no other condition that would force an break.
}
else if (currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER || currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER)
{
breakDefinition = null;
// no pagebreaks ..
}
else if (currentMasterPage == null || isPagebreakPending())
{
// Must be the first table, as we have no master-page yet.
masterPageName = createMasterPage(true, true);
setPagebreakDefinition(null);
if (masterPageName == null)
{
// we should always have a master-page ...
masterPageName = currentMasterPage.getStyleName();
}
breakDefinition = new PageBreakDefinition(isResetPageNumber());
}
else
{
breakDefinition = null;
}
}
else if (isPagebreakPending() && currentRole != OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER && currentRole != OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER)
{
// Derive an automatic style for the pagebreak.
// LOGGER.debug("Manual pagebreak (within the section): " + getCurrentRole());
breakDefinition = getPagebreakDefinition();
setPagebreakDefinition(null);
masterPageName = createMasterPage(true, true);
if (masterPageName == null || isSectionPagebreakBefore(attrs))
{
// If we have a manual pagebreak, then activate the current master-page again.
masterPageName = currentMasterPage.getStyleName();
}
}
else
{
breakDefinition = null;
}
final XmlWriter xmlWriter = getXmlWriter();
if (detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED && masterPageName != null)
{
// close the last table-tag, we will open a new one
xmlWriter.writeCloseTag();
// Reset the detail-state to 'started' so that the table's columns get printed now.
detailBandProcessingState = DETAIL_SECTION_OTHER_STARTED;
}
if (tableLayoutConfig == TABLE_LAYOUT_VARIABLES_PARAGRAPH && variables != null)
{
if (masterPageName != null)
{
// write a paragraph that uses the VARIABLES_HIDDEN_STYLE as
// primary style. Derive that one and add the manual pagebreak.
// The predefined style already has the 'keep-together' flags set.
// LOGGER.debug("Variables-Section with new Master-Page " + variables + " " + masterPageName);
final OfficeStyle style = deriveStyle(OfficeToken.PARAGRAPH, TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT);
style.setAttribute(OfficeNamespaces.STYLE_NS, "master-page-name", masterPageName);
if (breakDefinition.isResetPageNumber())
{
final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
paragraphProps.setAttribute(OfficeNamespaces.STYLE_NS, "page-number", "1");
}
if (isColumnBreakPending())
{
final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
paragraphProps.setAttribute(OfficeNamespaces.FO_NS, "break-before", "column");
setColumnBreakPending(false);
}
xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME, style.getStyleName(), XmlWriterSupport.OPEN);
masterPageName = null;
//breakDefinition = null;
}
else if (isColumnBreakPending())
{
setColumnBreakPending(false);
final OfficeStyle style = deriveStyle(OfficeToken.PARAGRAPH, TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT);
final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
paragraphProps.setAttribute(OfficeNamespaces.STYLE_NS, "page-number", "1");
xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME, style.getStyleName(), XmlWriterSupport.OPEN);
}
else
{
// Write a paragraph without adding the pagebreak. We can reuse the global style, but we have to make
// sure that the style is part of the current 'auto-style' collection.
// LOGGER.debug("Variables-Section " + variables);
StyleUtilities.copyStyle(OfficeToken.PARAGRAPH,
TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, getStylesCollection(),
getGlobalStylesCollection(), getPredefinedStylesCollection());
xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME,
TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, XmlWriterSupport.OPEN);
}
xmlWriter.writeText(variables);
xmlWriter.writeCloseTag();
variables = null;
}
final boolean keepWithNext = isKeepTableWithNext();
final boolean localKeepTogether = OfficeToken.TRUE.equals(attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, KEEP_TOGETHER));
final boolean tableMergeActive = isTableMergeActive();
this.sectionKeepTogether = tableMergeActive && localKeepTogether;
// Check, whether we have a reason to derive a style...
if (masterPageName != null || (!tableMergeActive && (localKeepTogether || keepWithNext)) || isColumnBreakPending())
{
final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
final OfficeStyle style = deriveStyle("table", styleName);
if (masterPageName != null)
{
// LOGGER.debug("Starting a new MasterPage: " + masterPageName);
// Patch the current styles.
// This usually only happens on Table-Styles or Paragraph-Styles
style.setAttribute(OfficeNamespaces.STYLE_NS, "master-page-name", masterPageName);
if (breakDefinition.isResetPageNumber())
{
final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
paragraphProps.setAttribute(OfficeNamespaces.STYLE_NS, "page-number", "1");
}
}
if (isColumnBreakPending())
{
final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
paragraphProps.setAttribute(OfficeNamespaces.FO_NS, "break-before", "column");
setColumnBreakPending(false);
}
// Inhibit breaks inside the table only if it has been defined and if we do not create one single
// big detail section. In that case, this flag would be invalid and would cause layout-errors.
if (!tableMergeActive)
{
if (localKeepTogether)
{
final Element tableProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, TABLE_PROPERTIES);
tableProps.setAttribute(OfficeNamespaces.STYLE_NS, MAY_BREAK_BETWEEN_ROWS, OfficeToken.FALSE);
}
}
else
{
if (detailBandProcessingState == DETAIL_SECTION_WAIT)
{
detailBandProcessingState = DETAIL_SECTION_FIRST_STARTED;
}
else if (detailBandProcessingState == DETAIL_SECTION_FIRST_PRINTED)
{
detailBandProcessingState = DETAIL_SECTION_OTHER_STARTED;
}
}
if (keepWithNext)
{
boolean addKeepWithNext = true;
if (currentRole == ROLE_GROUP_FOOTER)
{
addKeepWithNext = isParentKeepTogether();
}
final Element tableProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, TABLE_PROPERTIES);
tableProps.setAttribute(OfficeNamespaces.STYLE_NS, MAY_BREAK_BETWEEN_ROWS, OfficeToken.FALSE);
if (addKeepWithNext)
{
tableProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_WITH_NEXT, ALWAYS);
// A keep-with-next does not work, if the may-break-betweek rows is not set to false ..
}
}
attrs.setAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME, style.getStyleName());
// no need to copy the styles, this was done while deriving the
// style ..
}
else
{
// Check, whether we may be able to skip the table.
if (tableMergeActive)
{
if (detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED)
{
// Skip the whole thing ..
return;
}
else if (detailBandProcessingState == DETAIL_SECTION_WAIT)
{
if (keepWithNext)
{
final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
final OfficeStyle style = deriveStyle(OfficeToken.TABLE, styleName);
final Element tableProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, TABLE_PROPERTIES);
// A keep-with-next does not work, if the may-break-betweek rows is not set to false ..
tableProps.setAttribute(OfficeNamespaces.STYLE_NS, MAY_BREAK_BETWEEN_ROWS, OfficeToken.FALSE);
final String hasGroupFooter = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "has-group-footer");
if (hasGroupFooter != null && hasGroupFooter.equals(OfficeToken.TRUE))
{
tableProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_WITH_NEXT, ALWAYS);
}
attrs.setAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME, style.getStyleName());
}
detailBandProcessingState = DETAIL_SECTION_FIRST_STARTED;
}
else if (detailBandProcessingState == DETAIL_SECTION_FIRST_PRINTED)
{
detailBandProcessingState = DETAIL_SECTION_OTHER_STARTED;
}
}
// process the styles as usual
performStyleProcessing(attrs);
}
final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
final AttributeList attrList = buildAttributeList(attrs);
xmlWriter.writeTag(namespace, elementType, attrList, XmlWriterSupport.OPEN);
}
private boolean isParentKeepTogether()
{
PageContext context = getCurrentContext();
if (context != null)
{
context = context.getParent();
if (context != null)
{
return context.getKeepTogether() == PageContext.KEEP_TOGETHER_GROUP;
}
}
return false;
}
private boolean isTableMergeActive()
{
return getCurrentRole() == ROLE_DETAIL && tableLayoutConfig == TABLE_LAYOUT_SINGLE_DETAIL_TABLE;
}
private void openSection()
throws IOException
{
if (isRepeatingSection())
{
// repeating sections have other ways of defining columns ..
return;
}
if (getCurrentRole() == ROLE_TEMPLATE || getCurrentRole() == ROLE_SPREADSHEET_PAGE_HEADER || getCurrentRole() == ROLE_SPREADSHEET_PAGE_FOOTER)
{
// the template section would break the multi-column stuff and we dont open up sections there
// anyway ..
return;
}
final PageContext pageContext = getCurrentContext();
final Integer columnCount = pageContext.getColumnCount();
if (columnCount != null && !pageContext.isSectionOpen())
{
final AttributeList attrs = new AttributeList();
attrs.setAttribute(OfficeNamespaces.TEXT_NS, OfficeToken.STYLE_NAME, generateSectionStyle(columnCount));
attrs.setAttribute(OfficeNamespaces.TEXT_NS, NAME, sectionNames.generateName("Section"));
getXmlWriter().writeTag(OfficeNamespaces.TEXT_NS, "section", attrs, XmlWriterSupport.OPEN);
pageContext.setSectionOpen(true);
}
}
protected void startReportSection(final AttributeMap attrs, final int role)
throws IOException, DataSourceException, ReportProcessingException
{
sectionHeight = new LengthCalculator();
if (role == OfficeDocumentReportTarget.ROLE_TEMPLATE || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_HEADER || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_FOOTER)
{
// Start buffering with an dummy styles-collection, so that the global styles dont get polluted ..
startBuffering(new OfficeStylesCollection(), true);
}
else if (role == OfficeDocumentReportTarget.ROLE_PAGE_HEADER)
{
startBuffering(getGlobalStylesCollection(), true);
pageHeaderOnReportHeader = PageSection.isPrintWithReportHeader(attrs);
pageHeaderOnReportFooter = PageSection.isPrintWithReportFooter(attrs);
}
else if (role == OfficeDocumentReportTarget.ROLE_PAGE_FOOTER)
{
startBuffering(getGlobalStylesCollection(), true);
pageFooterOnReportHeader = PageSection.isPrintWithReportHeader(attrs);
pageFooterOnReportFooter = PageSection.isPrintWithReportFooter(attrs);
}
else if (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER || role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER)
{
startBuffering(getGlobalStylesCollection(), true);
}
else if (role == OfficeDocumentReportTarget.ROLE_VARIABLES)
{
startBuffering(getGlobalStylesCollection(), false);
}
else
{
contentProcessingState = TextRawReportTarget.CP_FIRST_TABLE;
if (role == OfficeDocumentReportTarget.ROLE_GROUP_HEADER || role == OfficeDocumentReportTarget.ROLE_GROUP_FOOTER)
{
// if we have a repeating header, then skip the first one ..
// if this is a repeating footer, skip the last one. This means,
// we have to buffer all group footers and wait for the next section..
startBuffering(getContentStylesCollection(), true);
}
if (role != OfficeDocumentReportTarget.ROLE_DETAIL)
{
// reset the detail-state. The flag will be updated on startTable and endOther(Table) if the
// current role is ROLE_DETAIL
detailBandProcessingState = DETAIL_SECTION_WAIT;
}
}
}
protected void startGroup(final AttributeMap attrs)
throws IOException, DataSourceException, ReportProcessingException
{
super.startGroup(attrs);
final PageContext pageContext = new PageContext(getCurrentContext());
activePageContext.push(pageContext);
final Object resetPageNumber = attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "reset-page-number");
if (OfficeToken.TRUE.equals(resetPageNumber))
{
setPagebreakDefinition(new PageBreakDefinition(true));
}
final Object keepTogether = attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, KEEP_TOGETHER);
if ("whole-group".equals(keepTogether))
{
pageContext.setKeepTogether(PageContext.KEEP_TOGETHER_GROUP);
}
else if ("with-first-detail".equals(keepTogether) && pageContext.getKeepTogether() != PageContext.KEEP_TOGETHER_GROUP)
{
pageContext.setKeepTogether(PageContext.KEEP_TOGETHER_FIRST_DETAIL);
}
final Object columnCountRaw = attrs.getAttribute(OfficeNamespaces.FO_NS, "column-count");
final Integer colCount = parseInt(columnCountRaw);
if (colCount != null)
{
pageContext.setColumnCount(colCount);
}
final Object newColumn = attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "start-new-column");
if (OfficeToken.TRUE.equals(newColumn))
{
setColumnBreakPending(true);
}
}
protected void startGroupInstance(final AttributeMap attrs)
throws IOException, DataSourceException, ReportProcessingException
{
if (getGroupContext().isGroupWithRepeatingSection())
{
setPagebreakDefinition(new PageBreakDefinition(isResetPageNumber()));
}
}
protected void endGroup(final AttributeMap attrs)
throws IOException, DataSourceException, ReportProcessingException
{
if (getGroupContext().isGroupWithRepeatingSection())
{
setPagebreakDefinition(new PageBreakDefinition(isResetPageNumber()));
}
super.endGroup(attrs);
finishSection();
activePageContext.pop();
}
private void finishSection()
throws ReportProcessingException
{
final PageContext pageContext = getCurrentContext();
if (pageContext.isSectionOpen())
{
pageContext.setSectionOpen(false);
try
{
getXmlWriter().writeCloseTag();
}
catch (IOException e)
{
throw new ReportProcessingException("IOError", e);
}
}
}
protected void endReportSection(final AttributeMap attrs, final int role)
throws IOException, DataSourceException, ReportProcessingException
{
if (role == ROLE_TEMPLATE || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_HEADER || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_FOOTER)
{
finishBuffering();
return;
}
final CSSNumericValue result = sectionHeight.getResult();
if (role == OfficeDocumentReportTarget.ROLE_PAGE_HEADER)
{
final PageContext pageContext = getCurrentContext();
pageContext.setHeader(applyColumnsToPageBand(finishBuffering(), pageContext.getActiveColumns()).getXmlBuffer(), result);
}
else if (role == OfficeDocumentReportTarget.ROLE_PAGE_FOOTER)
{
final PageContext pageContext = getCurrentContext();
pageContext.setFooter(applyColumnsToPageBand(finishBuffering(), pageContext.getActiveColumns()).getXmlBuffer(), result);
}
else if (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER)
{
final PageContext pageContext = getCurrentContext();
pageContext.setHeader(applyColumnsToPageBand(finishBuffering(), pageContext.getActiveColumns()).getXmlBuffer(), result);
}
else if (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER)
{
final PageContext pageContext = getCurrentContext();
pageContext.setFooter(applyColumnsToPageBand(finishBuffering(), pageContext.getActiveColumns()).getXmlBuffer(), result);
}
else if (role == OfficeDocumentReportTarget.ROLE_VARIABLES)
{
if (variables == null)
{
variables = finishBuffering().getXmlBuffer();
}
else
{
variables += finishBuffering().getXmlBuffer();
}
}
else if (role == OfficeDocumentReportTarget.ROLE_GROUP_HEADER)
{
final String headerText = finishBuffering().getXmlBuffer();
final int iterationCount = getGroupContext().getParent().getIterationCount();
final boolean repeat = OfficeToken.TRUE.equals(attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "repeat-section"));
if (!repeat || iterationCount > 0)
{
getXmlWriter().writeText(headerText);
}
}
else if (role == OfficeDocumentReportTarget.ROLE_GROUP_FOOTER)
{
final String footerText = finishBuffering().getXmlBuffer();
// how do we detect whether this is the last group footer?
getXmlWriter().writeText(footerText);
}
}
public void endReport(final ReportStructureRoot report)
throws DataSourceException, ReportProcessingException
{
super.endReport(report);
variablesDeclarations = null;
try
{
// Write the settings ..
final AttributeList rootAttributes = new AttributeList();
rootAttributes.addNamespaceDeclaration("office", OfficeNamespaces.OFFICE_NS);
rootAttributes.addNamespaceDeclaration("config", OfficeNamespaces.CONFIG);
rootAttributes.addNamespaceDeclaration("ooo", OfficeNamespaces.OO2004_NS);
rootAttributes.setAttribute(OfficeNamespaces.OFFICE_NS, "version",
OfficeDocumentReportTarget.ODF_VERSION);
final OutputStream outputStream = getOutputRepository().createOutputStream("settings.xml", "text/xml");
final XmlWriter xmlWriter = new XmlWriter(new OutputStreamWriter(outputStream, "UTF-8"), createTagDescription());
xmlWriter.setAlwaysAddNamespace(true);
xmlWriter.writeXmlDeclaration("UTF-8");
xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "document-settings", rootAttributes, XmlWriterSupport.OPEN);
xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "settings", XmlWriterSupport.OPEN);
xmlWriter.writeTag(OfficeNamespaces.CONFIG, "config-item-set", NAME, "ooo:configuration-settings", XmlWriterSupport.OPEN);
final AttributeList configAttributes = new AttributeList();
configAttributes.setAttribute(OfficeNamespaces.CONFIG, NAME, "TableRowKeep");
configAttributes.setAttribute(OfficeNamespaces.CONFIG, "type", "boolean");
xmlWriter.writeTag(OfficeNamespaces.CONFIG, "config-item", configAttributes, XmlWriterSupport.OPEN);
xmlWriter.writeText(OfficeToken.TRUE);
xmlWriter.writeCloseTag();
xmlWriter.writeCloseTag();
xmlWriter.writeCloseTag();
xmlWriter.writeCloseTag();
xmlWriter.close();
copyMeta();
}
catch (IOException ioe)
{
throw new ReportProcessingException("Failed to write settings document");
}
}
protected void endOther(final AttributeMap attrs)
throws IOException, DataSourceException, ReportProcessingException
{
final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
final boolean isInternalNS = ObjectUtilities.equal(JFreeReportInfo.REPORT_NAMESPACE, namespace);
final boolean isTableNs = ObjectUtilities.equal(OfficeNamespaces.TABLE_NS, namespace);
if (isTableMergeActive() && detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED && isTableNs && ObjectUtilities.equal(OfficeToken.TABLE_COLUMNS, elementType))
{
finishBuffering();
return;
}
if (isInternalNS && (ObjectUtilities.equal(OfficeToken.IMAGE, elementType) || ObjectUtilities.equal(OfficeToken.OBJECT_OLE, elementType)))
{
return;
}
final XmlWriter xmlWriter = getXmlWriter();
if (tableLayoutConfig != TABLE_LAYOUT_VARIABLES_PARAGRAPH && isTableNs && ObjectUtilities.equal(OfficeToken.TABLE_CELL, elementType) && !isRepeatingSection())
{
if (variables != null)
{
// This cannot happen as long as the report sections only contain tables. But at some point in the
// future they will be made of paragraphs, and then we are prepared ..
//LOGGER.debug("Variables-Section " + variables);
final String tag;
if (sectionKeepTogether && expectedTableRowCount > 0)
{
tag = TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT;
}
else
{
tag = TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITHOUT_KEEPWNEXT;
}
StyleUtilities.copyStyle(OfficeToken.PARAGRAPH,
tag, getStylesCollection(),
getGlobalStylesCollection(), getPredefinedStylesCollection());
xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME,
tag, XmlWriterSupport.OPEN);
xmlWriter.writeText(variables);
xmlWriter.writeCloseTag();
variables = null;
}
/**
// Only generate the empty paragraph, if we have to add the keep-together ..
else if (cellEmpty && expectedTableRowCount > 0 &&
sectionKeepTogether && !firstCellSeen)
{
// we have no variables ..
StyleUtilities.copyStyle(OfficeToken.PARAGRAPH,
TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, getStylesCollection(),
getGlobalStylesCollection(), getPredefinedStylesCollection());
xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME,
TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, XmlWriterSupport.CLOSE);
}
*/
}
if (isTableNs && (ObjectUtilities.equal(OfficeToken.TABLE_CELL, elementType) || ObjectUtilities.equal(OfficeToken.COVERED_TABLE_CELL, elementType)))
{
firstCellSeen = true;
}
if (isTableNs && ObjectUtilities.equal(OfficeToken.TABLE, elementType))
{
if (getCurrentRole() == ROLE_DETAIL)
{
if (!isTableMergeActive())
{
// We do not merge the detail bands, so an ordinary close will do.
xmlWriter.writeCloseTag();
}
else if (detailBandProcessingState == DETAIL_SECTION_FIRST_STARTED)
{
final int keepTogetherState = getCurrentContext().getKeepTogether();
if (keepTogetherState == PageContext.KEEP_TOGETHER_FIRST_DETAIL)
{
xmlWriter.writeCloseTag();
detailBandProcessingState = DETAIL_SECTION_FIRST_PRINTED;
}
else
{
detailBandProcessingState = DETAIL_SECTION_OTHER_PRINTED;
}
}
else if (detailBandProcessingState == DETAIL_SECTION_OTHER_STARTED)
{
detailBandProcessingState = DETAIL_SECTION_OTHER_PRINTED;
}
}
else
{
xmlWriter.writeCloseTag();
}
if (isSectionPagebreakAfter(attrs))
{
setPagebreakDefinition(new PageBreakDefinition(false));
}
}
else
{
xmlWriter.writeCloseTag();
}
}
protected void endGroupBody(final AttributeMap attrs)
throws IOException, DataSourceException, ReportProcessingException
{
if (tableLayoutConfig == TABLE_LAYOUT_SINGLE_DETAIL_TABLE && detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED)
{
// closes the table ..
final XmlWriter xmlWriter = getXmlWriter();
xmlWriter.writeCloseTag();
detailBandProcessingState = DETAIL_SECTION_WAIT;
}
}
protected void endContent(final AttributeMap attrs)
throws IOException, DataSourceException, ReportProcessingException
{
finishSection();
final BufferState bodyText = finishBuffering();
final XmlWriter writer = getXmlWriter();
final Map definedMappings = variablesDeclarations.getDefinedMappings();
if (!definedMappings.isEmpty())
{
writer.writeTag(OfficeNamespaces.TEXT_NS, "variable-decls", XmlWriterSupport.OPEN);
final Iterator mappingsIt = definedMappings.entrySet().iterator();
while (mappingsIt.hasNext())
{
final Map.Entry entry = (Map.Entry) mappingsIt.next();
final AttributeList entryList = new AttributeList();
entryList.setAttribute(OfficeNamespaces.TEXT_NS, NAME, (String) entry.getKey());
entryList.setAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE, (String) entry.getValue());
writer.writeTag(OfficeNamespaces.TEXT_NS, "variable-decl", entryList, XmlWriterSupport.CLOSE);
}
writer.writeCloseTag();
}
writer.writeStream(bodyText.getXmlAsReader());
writer.setLineEmpty(true);
writer.writeCloseTag();
}
public String getExportDescriptor()
{
return "raw/" + PentahoReportEngineMetaData.OPENDOCUMENT_TEXT;
}
}