diff options
Diffstat (limited to 'reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor')
19 files changed, 3011 insertions, 0 deletions
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/AbstractReportElementLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/AbstractReportElementLayoutController.java new file mode 100644 index 000000000000..a690062bf83f --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/AbstractReportElementLayoutController.java @@ -0,0 +1,150 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.pentaho.model.OfficeGroupSection; +import org.libreoffice.report.pentaho.model.ReportElement; + +import org.jfree.report.DataFlags; +import org.jfree.report.DataRow; +import org.jfree.report.DataSourceException; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.expressions.Expression; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.AbstractLayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutControllerUtil; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; +import org.jfree.report.structure.Element; +import org.jfree.report.structure.Group; + +import org.pentaho.reporting.libraries.formula.lvalues.ContextLookup; +import org.pentaho.reporting.libraries.formula.lvalues.LValue; + +/** + * Todo: Document me! + * + * @since 05.03.2007 + * @noinspection CloneableClassWithoutClone + */ +public abstract class AbstractReportElementLayoutController + extends AbstractLayoutController +{ + + public static final int NOT_STARTED = 0; + public static final int FINISHED = 2; + private int state; + + protected AbstractReportElementLayoutController() + { + } + + /** + * Advances the processing position. + * + * @param target the report target that receives generated events. + * @return the new layout controller instance representing the new state. + * + * @throws org.jfree.report.DataSourceException if there was a problem reading data from + * the datasource. + * @throws org.jfree.report.ReportProcessingException if there was a general problem during + * the report processing. + * @throws org.jfree.report.ReportDataFactoryException if a query failed. + */ + public LayoutController advance(final ReportTarget target) + throws DataSourceException, ReportDataFactoryException, + ReportProcessingException + { + if (state != AbstractReportElementLayoutController.NOT_STARTED) + { + throw new IllegalStateException(); + } + + if (FormatValueUtility.shouldPrint(this, (ReportElement)getNode())) + { + // delegate to the handler .. + return delegateContentGeneration(target); + } + else + { + // There is no printable content at all. Set the state to FINISHED + return join(getFlowController()); + } + } + + public abstract boolean isValueChanged(); + + /** + * Joins with a delegated process flow. This is generally called from a child + * flow and should *not* (I mean it!) be called from outside. If you do, + * you'll suffer. + * + * @param flowController the flow controller of the parent. + * @return the joined layout controller that incorperates all changes from the + * delegate. + */ + public LayoutController join(final FlowController flowController) + throws DataSourceException, ReportDataFactoryException, + ReportProcessingException + { + final AbstractReportElementLayoutController alc = + (AbstractReportElementLayoutController) clone(); + alc.state = AbstractReportElementLayoutController.FINISHED; + return alc; + // That's how this method is implemented in classes of pentaho itself; + // I'm not sure why we do something different, but I haven't been able + // to pinpoint a bug attributable to the above implementation. + // final LayoutController parent = getParent(); + // if (parent == null) + // { + // // skip to the next step .. + // throw new IllegalStateException("There is no parent to join with. " + + // "This should not happen in a sane environment!"); + // } + + // return parent.join(getFlowController()); + } + + protected abstract LayoutController delegateContentGeneration(final ReportTarget target) + throws ReportProcessingException, ReportDataFactoryException, + DataSourceException; + + /** + * Checks, whether the layout controller would be advanceable. If this method + * returns true, it is generally safe to call the 'advance()' method. + * + * @return true, if the layout controller is advanceable, false otherwise. + */ + public boolean isAdvanceable() + { + return state != AbstractReportElementLayoutController.FINISHED; + } + + public int getState() + { + return state; + } + + protected void setState(final int state) + { + this.state = state; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FixedTextLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FixedTextLayoutController.java new file mode 100644 index 000000000000..1dd0a26174b7 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FixedTextLayoutController.java @@ -0,0 +1,76 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.pentaho.model.FixedTextElement; + +import org.jfree.report.DataSourceException; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.data.GlobalMasterRow; +import org.jfree.report.data.ReportDataRow; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportContext; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutControllerFactory; +import org.jfree.report.structure.Section; + +/** + * Processes a fixed-text element of the OpenOffice reporting specifciation. + * The element itself contains a single paragraph which contains the content. + * After checking, whether this element should be printed, this layout + * controller simply delegates the dirty work to a suitable handler. + * + * @noinspection CloneableClassWithoutClone + * @since 05.03.2007 + */ +public class FixedTextLayoutController + extends AbstractReportElementLayoutController +{ + + public FixedTextLayoutController() + { + } + + public boolean isValueChanged() + { + final FlowController controller = getFlowController(); + final GlobalMasterRow masterRow = controller.getMasterRow(); + final ReportDataRow reportDataRow = masterRow.getReportDataRow(); + return reportDataRow.getCursor() == 0; + } + + protected LayoutController delegateContentGeneration(final ReportTarget target) + throws ReportProcessingException, ReportDataFactoryException, + DataSourceException + { + final FixedTextElement fte = (FixedTextElement) getNode(); + final Section content = fte.getContent(); + + final FlowController flowController = getFlowController(); + final ReportContext reportContext = flowController.getReportContext(); + final LayoutControllerFactory layoutControllerFactory = + reportContext.getLayoutControllerFactory(); + + final FixedTextLayoutController flc = (FixedTextLayoutController) clone(); + flc.setState(AbstractReportElementLayoutController.FINISHED); + return layoutControllerFactory.create(flowController, content, flc); + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormatValueUtility.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormatValueUtility.java new file mode 100644 index 000000000000..f5f65db53d52 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormatValueUtility.java @@ -0,0 +1,363 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.OfficeToken; +import org.libreoffice.report.pentaho.OfficeNamespaces; +import org.libreoffice.report.pentaho.model.FormattedTextElement; +import org.libreoffice.report.pentaho.model.OfficeGroupSection; +import org.libreoffice.report.pentaho.model.ReportElement; +import java.math.BigDecimal; + +import java.sql.Time; + +import java.text.SimpleDateFormat; + +import java.util.Date; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataFlags; +import org.jfree.report.DataRow; +import org.jfree.report.DataSourceException; +import org.jfree.report.data.DefaultDataFlags; +import org.jfree.report.expressions.Expression; +import org.jfree.report.expressions.FormulaExpression; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutControllerUtil; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; +import org.jfree.report.structure.Element; +import org.jfree.report.structure.Group; + +import org.pentaho.reporting.libraries.formula.lvalues.ContextLookup; +import org.pentaho.reporting.libraries.formula.lvalues.LValue; +import org.pentaho.reporting.libraries.formula.util.HSSFDateUtil; + +/** + * Creation-Date: 06.06.2007, 17:03:30 + * + */ +public class FormatValueUtility +{ + + private static final String BOOLEAN_VALUE = "boolean-value"; + private static final String STRING_VALUE = "string-value"; + public static final String VALUE_TYPE = "value-type"; + public static final String VALUE = "value"; + private static SimpleDateFormat dateFormat; + private static SimpleDateFormat timeFormat; + + private FormatValueUtility() + { + } + + public static String applyValueForVariable(final Object value, final AttributeMap variableSection) + { + String ret = null; + if (value instanceof Time) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "time"); + ret = formatTime((Time) value); + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, "time-value", ret); + } + else if (value instanceof java.sql.Date) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "date"); + ret = formatDate((Date) value); + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, "date-value", ret); + } + else if (value instanceof Date) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "float"); + ret = HSSFDateUtil.getExcelDate((Date) value, false, 2).toString(); + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE, ret); + } + else if (value instanceof Number) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "float"); + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE, String.valueOf(value)); + } + else if (value instanceof Boolean) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "boolean"); + if (Boolean.TRUE.equals(value)) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, BOOLEAN_VALUE, OfficeToken.TRUE); + } + else + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, BOOLEAN_VALUE, OfficeToken.FALSE); + } + } + else if (value != null) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "string"); + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, STRING_VALUE, String.valueOf(value)); + } + else + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "string"); + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, STRING_VALUE, ""); + } + return ret; + } + + public static void applyValueForCell(final Object value, final AttributeMap variableSection, final String valueType) + { + if (value instanceof Time) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, "time-value", formatTime((Time) value)); + } + else if (value instanceof java.sql.Date) + { + if ("float".equals(valueType))//@see http://qa.openoffice.org/issues/show_bug.cgi?id=108954 + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE, HSSFDateUtil.getExcelDate((Date) value, false, 2).toString()); + } + else + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, "date-value", formatDate((Date) value)); + } + } + else if (value instanceof Date) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "float"); + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE, HSSFDateUtil.getExcelDate((Date) value, false, 2).toString()); + } + else if (value instanceof BigDecimal) + { + if ("date".equals(valueType)) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, "date-value", formatDate(HSSFDateUtil.getJavaDate((BigDecimal) value, false, 0))); + } + else + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE, String.valueOf(value)); + } + } + else if (value instanceof Number) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE, String.valueOf(value)); + } + else if (value instanceof Boolean) + { + if ("float".equals(valueType)) + { + float fvalue = Boolean.TRUE.equals(value) ? 1 : 0; + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE, String.valueOf(fvalue)); + } + else + { + if (Boolean.TRUE.equals(value)) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, BOOLEAN_VALUE, OfficeToken.TRUE); + } + else + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, BOOLEAN_VALUE, OfficeToken.FALSE); + } + } + } + else if (value != null) + { + try + { + final Float number = Float.valueOf(String.valueOf(value)); + applyValueForCell(number, variableSection, valueType); + return; + } + catch (NumberFormatException e) + { + } + if (!"string".equals(valueType)) + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "string"); + } + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, STRING_VALUE, String.valueOf(value)); + } + else + { + variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, STRING_VALUE, ""); + } + } + + private static synchronized String formatDate(final Date date) + { + if (dateFormat == null) + { + dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'S'Z'"); + } + return dateFormat.format(date); + } + + private static synchronized String formatTime(final Date date) + { + if (timeFormat == null) + { + timeFormat = new SimpleDateFormat("'PT'HH'H'mm'M'ss'S'"); + } + return timeFormat.format(date); + } + + public static DataFlags computeDataFlag(final FormattedTextElement element, + final FlowController flowController) + throws DataSourceException + { + // here it is relatively easy. We have to evaluate the expression, convert + // the result into a string, and print that string. + final FormulaExpression formulaExpression = element.getValueExpression(); + final Object result = LayoutControllerUtil.evaluateExpression(flowController, element, formulaExpression); + if (result == null) + { + // ignore it. Ignoring it is much better than printing 'null'. + // LOGGER.debug("Formula '" + formulaExpression.getFormula() + "' evaluated to null."); + return null; + } + else if (result instanceof DataFlags) + { + return (DataFlags) result; + } + else + { + return new DefaultDataFlags(null, result, true); + } + } + + public static boolean shouldPrint(final LayoutController ref, final ReportElement text) + throws DataSourceException + { + final boolean isValueChanged; + if (ref instanceof AbstractReportElementLayoutController) + isValueChanged=((AbstractReportElementLayoutController)ref).isValueChanged(); + else if (ref instanceof TableCellLayoutController) + isValueChanged=((TableCellLayoutController)ref).isValueChanged(); + else + throw new AssertionError("org.libreoffice.report.pentaho.layoutprocessor.FormatValueUtility.shouldPrint expects an implementor of isValueChanged as first argument"); + + // Tests we have to perform: + // 1. If repeated values are supposed to be printed, then print. + // (this is always the case for static text and static elements) + // 2. If value changed, then print. + // 3. If (printing should be forced on group change AND group changed), then print + if ( !( isValueChanged + || text.isPrintRepeatedValues() + || ( text.isPrintWhenGroupChange() && isGroupChanged(ref) ))) + { + return false; + } + + final Expression dc = text.getDisplayCondition(); + if (dc != null) + { + final Object o = LayoutControllerUtil.evaluateExpression(ref.getFlowController(), text, dc); + if (Boolean.FALSE.equals(o)) + { + return false; + } + } + + return true; + } + + public static boolean isGroupChanged(LayoutController ref) + { + // search the group. + final SectionLayoutController slc = findGroup(ref); + if (slc == null) + { + // Always print the content of the report header and footer and + // the page header and footer. + return true; + } + + // we are in the first iteration, so yes, the group has changed recently. + return slc.getIterationCount() == 0; + } + + public static SectionLayoutController findGroup(LayoutController ref) + { + LayoutController parent = ref.getParent(); + boolean skipNext = false; + while (parent != null) + { + if (!(parent instanceof SectionLayoutController)) + { + parent = parent.getParent(); + } + else + { + final SectionLayoutController slc = (SectionLayoutController) parent; + final Element element = slc.getElement(); + if (element instanceof OfficeGroupSection) + { + // This is a header or footer. So we take the next group instead. + skipNext = true; + parent = parent.getParent(); + } + else if (!(element instanceof Group)) + { + parent = parent.getParent(); + } + else if (skipNext) + { + skipNext = false; + parent = parent.getParent(); + } + else + { + return (SectionLayoutController) parent; + } + } + } + return null; + } + + public static boolean isReferenceChanged(LayoutController ref, final LValue lValue) + { + if (lValue instanceof ContextLookup) + { + final ContextLookup rval = (ContextLookup) lValue; + final String s = rval.getName(); + final DataRow view = ref.getFlowController().getMasterRow().getGlobalView(); + try + { + final DataFlags flags = view.getFlags(s); + if (flags != null && flags.isChanged()) + { + return true; + } + } + catch (DataSourceException e) + { + // ignore .. assume that the reference has not changed. + } + } + final LValue[] childValues = lValue.getChildValues(); + for (int i = 0; i < childValues.length; i++) + { + final LValue value = childValues[i]; + if (isReferenceChanged(ref, value)) + { + return true; + } + } + return false; + } + +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormattedTextLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormattedTextLayoutController.java new file mode 100644 index 000000000000..dcc153c71962 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormattedTextLayoutController.java @@ -0,0 +1,219 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.OfficeToken; +import org.libreoffice.report.pentaho.OfficeNamespaces; +import org.libreoffice.report.pentaho.model.FormattedTextElement; +import org.libreoffice.report.pentaho.model.OfficeDocument; +import org.libreoffice.report.pentaho.model.OfficeStyle; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataFlags; +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.expressions.FormulaExpression; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.structure.Element; + +import org.pentaho.reporting.libraries.formula.Formula; +import org.pentaho.reporting.libraries.formula.lvalues.LValue; +import org.pentaho.reporting.libraries.formula.parser.ParseException; + +/** + * Todo: Document me! + * + * @since 05.03.2007 + */ +public class FormattedTextLayoutController + extends AbstractReportElementLayoutController +{ + + private static final Log LOGGER = LogFactory.getLog(FormattedTextLayoutController.class); + + public FormattedTextLayoutController() + { + } + + private VariablesCollection getVariablesCollection() + { + LayoutController parent = getParent(); + while (parent != null) + { + if (parent instanceof OfficeRepeatingStructureLayoutController) + { + final OfficeRepeatingStructureLayoutController orslc = + (OfficeRepeatingStructureLayoutController) parent; + if (orslc.isNormalFlowProcessing()) + { + return null; + } + + return orslc.getVariablesCollection(); + } + parent = parent.getParent(); + } + return null; + } + + public boolean isValueChanged() + { + try + { + final FormattedTextElement element = (FormattedTextElement) getNode(); + final FormulaExpression formulaExpression = element.getValueExpression(); + final Formula formula = formulaExpression.getCompiledFormula(); + final LValue lValue = formula.getRootReference(); + return FormatValueUtility.isReferenceChanged(this, lValue); + } + catch (final ParseException e) + { + LOGGER.debug("Parse Exception", e); + return false; + } + } + + protected LayoutController delegateContentGeneration(final ReportTarget target) + throws ReportProcessingException, ReportDataFactoryException, + DataSourceException + { + final FormattedTextElement element = (FormattedTextElement) getNode(); + final VariablesCollection vc = getVariablesCollection(); + if (vc != null) + { + final String name = vc.addVariable(element); + final AttributeMap variablesGet = new AttributeMap(); + variablesGet.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, + Element.TYPE_ATTRIBUTE, "variable-get"); + variablesGet.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, + Element.NAMESPACE_ATTRIBUTE, OfficeNamespaces.TEXT_NS); + variablesGet.setAttribute(OfficeNamespaces.TEXT_NS, "name", name); + + final String dataStyleName = computeValueStyle(); + if (dataStyleName != null) + { + variablesGet.setAttribute(OfficeNamespaces.STYLE_NS, "data-style-name", dataStyleName); + } + + final String valueType = computeValueType(); + variablesGet.setAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE, valueType); + target.startElement(variablesGet); + + target.endElement(variablesGet); + } + else + { + final DataFlags df = FormatValueUtility.computeDataFlag(element, getFlowController()); + if (df != null) + { + if (df.getValue() instanceof String) + { + target.processContent(df); + } + else //@see http://qa.openoffice.org/issues/show_bug.cgi?id=108954 + { + Element cell = getParentTableCell(); + if (cell != null && "string".equals(cell.getAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE))) + { + target.processContent(df); + } + } + } + } + + return join(getFlowController()); + } + + private OfficeDocument getDocument() + { + LayoutController parent = getParent(); + while (parent != null) + { + final Object node = parent.getNode(); + if (node instanceof OfficeDocument) + { + return (OfficeDocument) node; + } + parent = parent.getParent(); + } + return null; + } + + private Element getParentTableCell() + { + LayoutController parent = getParent(); + while (parent != null) + { + if (parent instanceof TableCellLayoutController) + { + final TableCellLayoutController cellController = (TableCellLayoutController) parent; + return cellController.getElement(); + } + parent = parent.getParent(); + } + return null; + } + + private String computeValueStyle() + { + final Element tce = getParentTableCell(); + if (tce == null) + { + return null; + } + + final String cellStyleName = (String) tce.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME); + if (cellStyleName == null) + { + return null; + } + final OfficeDocument document = getDocument(); + if (document == null) + { + return null; + } + + final OfficeStyle style = document.getStylesCollection().getStyle("table-cell", cellStyleName); + return (String) style.getAttribute(OfficeNamespaces.STYLE_NS, "data-style-name"); + } + + private String computeValueType() + { + final Element tce = getParentTableCell(); + if (tce == null) + { + // NO particular format means: Fallback to string and hope and pray .. + throw new IllegalStateException("A formatted text element must be a child of a Table-Cell."); + } + + final String type = (String) tce.getAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE); + if (type == null) + { + LOGGER.error("The Table-Cell does not have a office:value attribute defined. Your content will be messed up."); + return "string"; + } + return type; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementContext.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementContext.java new file mode 100644 index 000000000000..91cf767eab2d --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementContext.java @@ -0,0 +1,81 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +/** + * Todo: Document me! + * + * @since 30.03.2007 + */ +public class ImageElementContext +{ + + private final int colSpan; + private final int rowSpan; + private String[] rowStyles; + private String[] colStyles; + + public ImageElementContext(final int colSpan, final int rowSpan) + { + this.colSpan = colSpan; + this.rowSpan = rowSpan; + this.colStyles = new String[colSpan]; + this.rowStyles = new String[rowSpan]; + } + + public int getColSpan() + { + return colSpan; + } + + public int getRowSpan() + { + return rowSpan; + } + + public String[] getRowStyles() + { + return rowStyles; + } + + public String[] getColStyles() + { + return colStyles; + } + + public void setRowStyle(final int pos, final String styleName) + { + rowStyles[pos] = styleName; + } + + public void setColStyle(final int pos, final String styleName) + { + colStyles[pos] = styleName; + } + + public String getRowStyle(final int pos) + { + return rowStyles[pos]; + } + + public String getColStyle(final int pos) + { + return colStyles[pos]; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementLayoutController.java new file mode 100644 index 000000000000..bd5d529553d5 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementLayoutController.java @@ -0,0 +1,311 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.OfficeToken; +import org.libreoffice.report.pentaho.OfficeNamespaces; +import org.libreoffice.report.pentaho.model.ImageElement; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.data.GlobalMasterRow; +import org.jfree.report.data.ReportDataRow; +import org.jfree.report.expressions.FormulaExpression; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutControllerUtil; +import org.jfree.report.structure.Element; +import org.jfree.report.structure.Node; +import org.jfree.report.structure.Section; +import org.jfree.report.util.TextUtilities; + +import org.pentaho.reporting.libraries.base.util.ObjectUtilities; +import org.pentaho.reporting.libraries.formula.Formula; +import org.pentaho.reporting.libraries.formula.lvalues.LValue; +import org.pentaho.reporting.libraries.formula.parser.ParseException; + +/** + * Produces an image. The image-structures itself (draw:frame and so on) are not generated here. This element produces a + * place-holder element and relies on the output target to compute a sensible position for the element. The report + * definition does not give any hints about the size of the image, so we have to derive this from the surrounding + * context. + * + * @since 05.03.2007 + */ +public class ImageElementLayoutController + extends AbstractReportElementLayoutController +{ + + private static final Log LOGGER = LogFactory.getLog(ImageElementLayoutController.class); + private ImageElementContext context; + + public ImageElementLayoutController() + { + } + + protected LayoutController delegateContentGeneration(final ReportTarget target) + throws ReportProcessingException, ReportDataFactoryException, + DataSourceException + { + final ImageElement imageElement = (ImageElement) getNode(); + final FormulaExpression formulaExpression = imageElement.getFormula(); + if (formulaExpression == null) + { + // A static image is easy. At least at this level. Dont ask about the weird things we have to do in the + // output targets ... + final String linkTarget = imageElement.getImageData(); + generateImage(target, linkTarget, imageElement.getScaleMode(), imageElement.isPreserveIRI()); + } + else + { + final Object value = + LayoutControllerUtil.evaluateExpression(getFlowController(), imageElement, formulaExpression); + generateImage(target, value, imageElement.getScaleMode(), imageElement.isPreserveIRI()); + } + return join(getFlowController()); + } + + private void generateImage(final ReportTarget target, + final Object linkTarget, + final String scale, + final boolean preserveIri) + throws ReportProcessingException, DataSourceException + { + if (linkTarget == null) + { + return; + } + + final AttributeMap image = new AttributeMap(); + image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.NAMESPACE_ATTRIBUTE, JFreeReportInfo.REPORT_NAMESPACE); + image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.TYPE_ATTRIBUTE, OfficeToken.IMAGE); + image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.SCALE, scale); + image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.PRESERVE_IRI, String.valueOf(preserveIri)); + image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "image-context", createContext()); + image.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.IMAGE_DATA, linkTarget); + target.startElement(image); + target.endElement(image); + } + + protected ImageElementContext createContext() + { + if (context == null) + { + + // Step 1: Find the parent cell. + final LayoutController cellController = findParentCell(); + if (cellController == null) + { + LOGGER.warn("Image is not contained in a table. Unable to calculate the image-size."); + return null; + } + final Element tableCell = (Element) cellController.getNode(); + final int rowSpan = TextUtilities.parseInt((String) tableCell.getAttribute(OfficeNamespaces.TABLE_NS, "number-rows-spanned"), 1); + final int colSpan = TextUtilities.parseInt((String) tableCell.getAttribute(OfficeNamespaces.TABLE_NS, "number-columns-spanned"), 1); + if (rowSpan < 1 || colSpan < 1) + { + LOGGER.warn("Rowspan or colspan for image-size calculation was invalid."); + return null; + } + + final LayoutController rowController = cellController.getParent(); + if (rowController == null) + { + LOGGER.warn("Table-Cell has no parent. Unable to calculate the image-size."); + return null; + } + final Section tableRow = (Section) rowController.getNode(); + // we are now making the assumption, that the row is a section, that contains the table-cell. + // This breaks the ability to return nodes or to construct reports on the fly, but the OO-report format + // is weird anyway and wont support such advanced techniques for the next few centuries .. + final int columnPos = findNodeInSection(tableRow, tableCell, OfficeToken.COVERED_TABLE_CELL); + if (columnPos == -1) + { + LOGGER.warn("Table-Cell is not a direct child of the table-row. Unable to calculate the image-size."); + return null; + } + + final LayoutController tableController = rowController.getParent(); + if (tableController == null) + { + LOGGER.warn("Table-Row has no Table. Unable to calculate the image-size."); + return null; + } + + final Section table = (Section) tableController.getNode(); + // ok, we got a table, so as next we have to search for the columns now. + final Section columns = (Section) table.findFirstChild(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_COLUMNS); + if (columns.getNodeCount() <= columnPos + colSpan) + { + // the colspan is to large. The table definition is therefore invalid. We do not try to fix this. + LOGGER.warn( + "The Table's defined columns do not match the col-span or col-position. Unable to calculate the image-size."); + return null; + } + + final ImageElementContext context = new ImageElementContext(colSpan, rowSpan); + addColumnStyles(context, columns, columnPos, colSpan); + // finally search the styles for the row now. + final int rowPos = findNodeInSection(table, tableRow, null); + if (rowPos == -1) + { + LOGGER.warn("Table-Cell is not a direct child of the table-row. Unable to calculate the image-size."); + return null; + } + + addRowStyles(context, table, rowPos, rowSpan); + this.context = context; + } + return this.context; + } + + private int findNodeInSection(final Section tableRow, + final Element tableCell, + final String secondType) + { + int retval = 0; + final Node[] nodes = tableRow.getNodeArray(); + final String namespace = tableCell.getNamespace(); + final String type = tableCell.getType(); + for (final Node node : nodes) + { + if (!(node instanceof Element)) + { + continue; + } + final Element child = (Element) node; + if (!ObjectUtilities.equal(child.getNamespace(), namespace) || (!ObjectUtilities.equal(child.getType(), type) && (secondType == null || !ObjectUtilities.equal(child.getType(), secondType)))) + { + continue; + } + + if (node == tableCell) + { + return retval; + } + retval += 1; + } + return -1; + } + + private LayoutController findParentCell() + { + LayoutController parent = getParent(); + while (parent != null) + { + final Object node = parent.getNode(); + if (node instanceof Element) + { + final Element element = (Element) node; + if (OfficeNamespaces.TABLE_NS.equals(element.getNamespace()) && "table-cell".equals(element.getType())) + { + return parent; + } + } + parent = parent.getParent(); + } + return null; + } + + public boolean isValueChanged() + { + final ImageElement imageElement = (ImageElement) getNode(); + final FormulaExpression formulaExpression = imageElement.getFormula(); + if (formulaExpression == null) + { + final FlowController controller = getFlowController(); + final GlobalMasterRow masterRow = controller.getMasterRow(); + final ReportDataRow reportDataRow = masterRow.getReportDataRow(); + return reportDataRow.getCursor() == 0; + } + + try + { + final Formula formula = formulaExpression.getCompiledFormula(); + final LValue lValue = formula.getRootReference(); + return FormatValueUtility.isReferenceChanged(this, lValue); + } + catch (ParseException e) + { + return false; + } + } + + void addColumnStyles(final ImageElementContext context, final Section columns, final int columnPos, final int colSpan) + { + final Node[] columnDefs = columns.getNodeArray(); + int columnCounter = 0; + for (Node columnDef : columnDefs) + { + final Element column = (Element) columnDef; + + if (!ObjectUtilities.equal(column.getNamespace(), OfficeNamespaces.TABLE_NS) || !ObjectUtilities.equal(column.getType(), OfficeToken.TABLE_COLUMN)) + { + continue; + } + if (columnCounter >= columnPos) + { + final String colStyle = (String) column.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME); + context.setColStyle(columnCounter - columnPos, colStyle); + } + + columnCounter += 1; + + if (columnCounter >= (columnPos + colSpan)) + { + break; + } + + } + } + + void addRowStyles(final ImageElementContext context, final Section table, final int rowPos, final int rowSpan) + { + final Node[] rows = table.getNodeArray(); + int rowCounter = 0; + for (Node row1 : rows) + { + final Element row = (Element) row1; + + if (!ObjectUtilities.equal(row.getNamespace(), OfficeNamespaces.TABLE_NS) || !ObjectUtilities.equal(row.getType(), OfficeToken.TABLE_ROW)) + { + continue; + } + if (rowCounter >= rowPos) + { + final String rowStyle = (String) row.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME); + context.setRowStyle(rowCounter - rowPos, rowStyle); + } + + rowCounter += 1; + + if (rowCounter >= (rowPos + rowSpan)) + { + break; + } + } + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ObjectOleLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ObjectOleLayoutController.java new file mode 100644 index 000000000000..3a5c31dd1435 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ObjectOleLayoutController.java @@ -0,0 +1,112 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.OfficeToken; +import org.libreoffice.report.SDBCReportDataFactory; +import org.libreoffice.report.pentaho.model.ObjectOleElement; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataFlags; +import org.jfree.report.DataRow; +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.structure.Element; + +public class ObjectOleLayoutController extends AbstractReportElementLayoutController +{ + + public ObjectOleLayoutController() + { + } + + public boolean isValueChanged() + { + final ObjectOleElement element = (ObjectOleElement) getNode(); + final List masterfields = element.getMasterfields(); + final DataRow view = getFlowController().getMasterRow().getGlobalView(); + for (final Iterator iter = masterfields.iterator(); iter.hasNext();) + { + final String master = (String) iter.next(); + try + { + final DataFlags flags = view.getFlags(master); + if (flags != null && flags.isChanged()) + { + return true; + } + } + catch (DataSourceException e) + { + // ignore .. assume that the reference has not changed. + } + } + return false; + } + + protected LayoutController delegateContentGeneration(final ReportTarget target) throws ReportProcessingException, ReportDataFactoryException, DataSourceException + { + final ObjectOleElement element = (ObjectOleElement) getNode(); + final String url = element.getUrl(); + if (url != null) + { + final AttributeMap ole = new AttributeMap(); + ole.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.NAMESPACE_ATTRIBUTE, JFreeReportInfo.REPORT_NAMESPACE); + ole.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.TYPE_ATTRIBUTE, OfficeToken.OBJECT_OLE); + ole.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "href", url); + ole.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "class-id", element.getClassid()); + final List<String> masterfields = element.getMasterfields(); + final List<Object> values = new ArrayList<Object>(); + final DataRow view = getFlowController().getMasterRow().getGlobalView(); + for (final Iterator<String> iter = masterfields.iterator(); iter.hasNext();) + { + final String master = iter.next(); + try + { + final DataFlags flags = view.getFlags(master); + if (flags != null) + { + values.add(flags.getValue()); + } + } + catch (DataSourceException e) + { + // ignore .. assume that the reference has not changed. + } + } + ole.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_COLUMNS, masterfields); + ole.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_VALUES, values); + ole.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.DETAIL_COLUMNS, element.getDetailfields()); + + target.startElement(ole); + target.endElement(ole); + } + + return join(getFlowController()); + } +} + diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeDetailLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeDetailLayoutController.java new file mode 100644 index 000000000000..40dd5c0488f6 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeDetailLayoutController.java @@ -0,0 +1,150 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.pentaho.model.VariablesDeclarationSection; + +import org.jfree.report.DataSourceException; +import org.jfree.report.ReportData; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.data.GlobalMasterRow; +import org.jfree.report.data.ReportDataRow; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.ElementLayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; + +/** + * Creation-Date: 11.04.2007, 11:04:02 + * + */ +public class OfficeDetailLayoutController extends SectionLayoutController +{ + + public static final int STATE_PROCESS_VARIABLES = 2; + public static final int STATE_PROCESS_NORMAL_FLOW = 3; + private boolean waitForJoin; + private int state; + + public OfficeDetailLayoutController() + { + } + + /** + * Initializes the layout controller. This method is called exactly once. It + * is the creators responsibility to call this method. + * <p/> + * Calling initialize after the first advance must result in a + * IllegalStateException. + * + * @param node the currently processed object or layout node. + * @param flowController the current flow controller. + * @param parent the parent layout controller that was responsible for + * instantiating this controller. + * @throws org.jfree.report.DataSourceException + * if there was a problem reading data from the datasource. + * @throws org.jfree.report.ReportProcessingException + * if there was a general problem during the report processing. + * @throws org.jfree.report.ReportDataFactoryException + * if a query failed. + */ + public void initialize(final Object node, + final FlowController flowController, + final LayoutController parent) + throws DataSourceException, ReportDataFactoryException, + ReportProcessingException + { + super.initialize(node, flowController, parent); + state = OfficeDetailLayoutController.STATE_PROCESS_VARIABLES; + } + + /** + * This method is called for each newly instantiated layout controller. The returned layout controller instance should + * have a processing state of either 'OPEN' or 'FINISHING' depending on whether there is any content or any child + * nodes to process. + * + * @param target the report target that receives generated events. + * @return the new layout controller instance representing the new state. + * @throws org.jfree.report.DataSourceException + * if there was a problem reading data from the datasource. + * @throws org.jfree.report.ReportProcessingException + * if there was a general problem during the report processing. + * @throws org.jfree.report.ReportDataFactoryException + * if a query failed. + */ + protected LayoutController startElement(final ReportTarget target) + throws DataSourceException, ReportProcessingException, ReportDataFactoryException + { + final FlowController fc = getFlowController(); + final GlobalMasterRow masterRow = fc.getMasterRow(); + final ReportDataRow reportDataRow = masterRow.getReportDataRow(); + final ReportData reportData = reportDataRow.getReportData(); + if (!reportData.isReadable()) + { + reportData.isReadable(); + // If this report has no data, then do not print the detail section. The detail section + // is the only section that behaves this way, and for now this is only done in the OO-implementation + final SectionLayoutController derived = (SectionLayoutController) clone(); + derived.setProcessingState(ElementLayoutController.FINISHED); + derived.setFlowController(fc); + return derived; + } + + if (state == OfficeDetailLayoutController.STATE_PROCESS_VARIABLES) + { + final VariablesDeclarationSection variables = new VariablesDeclarationSection(); + final OfficeDetailLayoutController controller = (OfficeDetailLayoutController) clone(); + controller.state = OfficeDetailLayoutController.STATE_PROCESS_NORMAL_FLOW; + controller.waitForJoin = true; + return processChild(controller, variables, fc); + } + + return super.startElement(target); + } + + protected void resetSectionForRepeat() + { + super.resetSectionForRepeat(); + state = STATE_PROCESS_VARIABLES; + } + + /** + * Joins with a delegated process flow. This is generally called from a child + * flow and should *not* (I mean it!) be called from outside. If you do, + * you'll suffer. + * + * @param flowController the flow controller of the parent. + * @return the joined layout controller that incorperates all changes from the + * delegate. + */ + public LayoutController join(final FlowController flowController) + { + if (waitForJoin) + { + final OfficeDetailLayoutController derived = (OfficeDetailLayoutController) clone(); + derived.setProcessingState(ElementLayoutController.NOT_STARTED); + derived.setFlowController(flowController); + derived.waitForJoin = false; + return derived; + } + return super.join(flowController); + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupInstanceSectionLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupInstanceSectionLayoutController.java new file mode 100644 index 000000000000..ad402e03a994 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupInstanceSectionLayoutController.java @@ -0,0 +1,170 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.pentaho.model.OfficeGroupSection; +import org.libreoffice.report.pentaho.model.VariablesDeclarationSection; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.expressions.Expression; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportContext; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.ElementLayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutControllerFactory; +import org.jfree.report.flow.layoutprocessor.LayoutControllerUtil; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; +import org.jfree.report.structure.Element; +import org.jfree.report.structure.Node; + +/** + * Creation-Date: 25.07.2007, 14:50:45 + * + */ +public class OfficeGroupInstanceSectionLayoutController extends SectionLayoutController +{ + + public static final int STATE_PROCESS_VARIABLES = 2; + public static final int STATE_PROCESS_NORMAL_FLOW = 3; + private int state; + private boolean waitForJoin; + + public OfficeGroupInstanceSectionLayoutController() + { + } + + public void initialize(final Object node, final FlowController flowController, final LayoutController parent) + throws DataSourceException, ReportDataFactoryException, ReportProcessingException + { + super.initialize(node, flowController, parent); + state = STATE_PROCESS_VARIABLES; + } + + protected LayoutController processContent(final ReportTarget target) + throws DataSourceException, ReportProcessingException, ReportDataFactoryException + { + if (state == OfficeGroupInstanceSectionLayoutController.STATE_PROCESS_VARIABLES) + { + // todo: Fill the variables section with something sensible .. + final VariablesDeclarationSection variables = new VariablesDeclarationSection(); + final OfficeGroupInstanceSectionLayoutController controller = + (OfficeGroupInstanceSectionLayoutController) clone(); + controller.state = + OfficeGroupLayoutController.STATE_PROCESS_NORMAL_FLOW; + controller.waitForJoin = true; + return processChild(controller, variables, getFlowController()); + } + return super.processContent(target); + } + + // isDisplayable is private in version 0.9.1, so until the upgrade we keep this copy of the method + // todo: Delete it unce the sun-cvs contains version 0.9.2. + protected LayoutController processChild(final SectionLayoutController derived, + final Node node, + final FlowController flowController) + throws DataSourceException, ReportProcessingException, + ReportDataFactoryException + { + final ReportContext reportContext = flowController.getReportContext(); + final LayoutControllerFactory layoutControllerFactory = reportContext.getLayoutControllerFactory(); + if (isDisplayable(node)) + { + derived.setProcessingState(ElementLayoutController.WAITING_FOR_JOIN); + return layoutControllerFactory.create(flowController, node, derived); + } + else + { + derived.setProcessingState(ElementLayoutController.WAITING_FOR_JOIN); + final LayoutController childLc = layoutControllerFactory.create(flowController, node, derived); + return LayoutControllerUtil.skipInvisibleElement(childLc); + } + } + + protected boolean isDisplayable(final Node node) throws DataSourceException + { + if (!(node instanceof OfficeGroupSection)) + { + return _isDisplayable(node); + } + + final OfficeGroupSection section = (OfficeGroupSection) node; + return !section.isRepeatSection() && _isDisplayable(node); + } + + protected boolean _isDisplayable(final Node node) + throws DataSourceException + { + // temp method until the pending upgrade to 0.9.2. Later we just call super.isDisplayable(..) instead. + if (!node.isEnabled()) + { + return false; + } + + final Expression expression = node.getDisplayCondition(); + if (expression == null) + { + return true; + } + + final Object result = LayoutControllerUtil.evaluateExpression(getFlowController(), node, expression); + return Boolean.TRUE.equals(result); + } + + protected void resetSectionForRepeat() + { + super.resetSectionForRepeat(); + state = STATE_PROCESS_VARIABLES; + } + + /** + * Joins with a delegated process flow. This is generally called from a child + * flow and should *not* (I mean it!) be called from outside. If you do, + * you'll suffer. + * + * @param flowController the flow controller of the parent. + * @return the joined layout controller that incorperates all changes from the + * delegate. + */ + public LayoutController join(final FlowController flowController) + { + if (waitForJoin) + { + final OfficeGroupInstanceSectionLayoutController derived = (OfficeGroupInstanceSectionLayoutController) clone(); + derived.setProcessingState(ElementLayoutController.OPENED); + derived.setFlowController(flowController); + derived.waitForJoin = false; + return derived; + } + return super.join(flowController); + } + + protected AttributeMap computeAttributes(final FlowController fc, final Element element, final ReportTarget target) + throws DataSourceException + { + final AttributeMap map = new AttributeMap(super.computeAttributes(fc, element, target)); + map.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "iteration-count", getIterationCount()); + map.makeReadOnly(); + return map; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupLayoutController.java new file mode 100644 index 000000000000..293a6dbdd001 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupLayoutController.java @@ -0,0 +1,195 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.pentaho.model.OfficeGroup; +import org.libreoffice.report.pentaho.model.OfficeGroupSection; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.ElementLayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; +import org.jfree.report.structure.Element; + +/** + * Todo: Document me! + * + * @since 15.03.2007 + */ +public class OfficeGroupLayoutController extends SectionLayoutController + implements OfficeRepeatingStructureLayoutController +{ + + public static final int STATE_PROCESS_REPEATING_HEADER = 0; + public static final int STATE_PROCESS_REPEATING_FOOTER = 1; + public static final int STATE_PROCESS_NORMAL_FLOW = 3; + private boolean waitForJoin; + private int state; + private VariablesCollection variablesCollection; + private boolean repeatHeader; + private boolean repeatFooter; + + public OfficeGroupLayoutController() + { + } + + /** + * Initializes the layout controller. This method is called exactly once. It + * is the creators responsibility to call this method. + * <p/> + * Calling initialize after the first advance must result in a + * IllegalStateException. + * + * @param node the currently processed object or layout node. + * @param flowController the current flow controller. + * @param parent the parent layout controller that was responsible for + * instantiating this controller. + * @throws org.jfree.report.DataSourceException + * if there was a problem reading data from the datasource. + * @throws org.jfree.report.ReportProcessingException + * if there was a general problem during the report processing. + * @throws org.jfree.report.ReportDataFactoryException + * if a query failed. + */ + public void initialize(final Object node, + final FlowController flowController, + final LayoutController parent) + throws DataSourceException, ReportDataFactoryException, + ReportProcessingException + { + super.initialize(node, flowController, parent); + state = OfficeGroupLayoutController.STATE_PROCESS_REPEATING_HEADER; + variablesCollection = new VariablesCollection(computeVariablesPrefix()); + + + final OfficeGroup group = (OfficeGroup) getElement(); + final OfficeGroupSection header = group.getHeader(); + repeatHeader = (header != null && header.isRepeatSection()); + + final OfficeGroupSection footer = group.getFooter(); + repeatFooter = (footer != null && footer.isRepeatSection()); + } + + protected LayoutController processContent(final ReportTarget target) + throws DataSourceException, ReportProcessingException, + ReportDataFactoryException + { + if (state == OfficeGroupLayoutController.STATE_PROCESS_REPEATING_HEADER) + { + + final OfficeGroupLayoutController controller = + (OfficeGroupLayoutController) clone(); + controller.state = + OfficeGroupLayoutController.STATE_PROCESS_REPEATING_FOOTER; + + if (!repeatHeader) + { + return controller; + } + + final OfficeGroup group = (OfficeGroup) getElement(); + final OfficeGroupSection header = group.getHeader(); + controller.waitForJoin = true; + return processChild(controller, header, getFlowController()); + } + + if (state == OfficeGroupLayoutController.STATE_PROCESS_REPEATING_FOOTER) + { + + final OfficeGroupLayoutController controller = + (OfficeGroupLayoutController) clone(); + controller.state = OfficeGroupLayoutController.STATE_PROCESS_NORMAL_FLOW; + + if (!repeatFooter) + { + return controller; + } + + final OfficeGroup group = (OfficeGroup) getElement(); + final OfficeGroupSection footer = group.getFooter(); + controller.waitForJoin = true; + return processChild(controller, footer, getFlowController()); + } + + return super.processContent(target); + } + + /** + * Joins with a delegated process flow. This is generally called from a child + * flow and should *not* (I mean it!) be called from outside. If you do, + * you'll suffer. + * + * @param flowController the flow controller of the parent. + * @return the joined layout controller that incorperates all changes from the + * delegate. + */ + public LayoutController join(final FlowController flowController) + { + if (waitForJoin) + { + final OfficeGroupLayoutController derived = (OfficeGroupLayoutController) clone(); + derived.setProcessingState(ElementLayoutController.OPENED); + derived.setFlowController(flowController); + derived.waitForJoin = false; + return derived; + } + return super.join(flowController); + } + + public boolean isNormalFlowProcessing() + { + return state == OfficeGroupLayoutController.STATE_PROCESS_NORMAL_FLOW; + } + + private String computeVariablesPrefix() + { + int count = 0; + LayoutController lc = this; + while (lc != null) + { + if (lc instanceof OfficeGroupLayoutController) + { + count++; + } + lc = lc.getParent(); + } + return "auto_group_" + count + "_"; + } + + public VariablesCollection getVariablesCollection() + { + return variablesCollection; + } + + protected AttributeMap computeAttributes(final FlowController fc, final Element element, final ReportTarget target) + throws DataSourceException + { + final AttributeMap map = new AttributeMap(super.computeAttributes(fc, element, target)); + final String value = String.valueOf(repeatHeader || repeatFooter); + map.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "repeating-header-or-footer", value); + map.makeReadOnly(); + return map; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupSectionLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupSectionLayoutController.java new file mode 100644 index 000000000000..a709bdce9ec4 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupSectionLayoutController.java @@ -0,0 +1,99 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.OfficeToken; +import org.libreoffice.report.pentaho.model.OfficeGroupSection; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.ElementLayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; +import org.jfree.report.structure.Element; + +/** + * This layoutcontroller simply checks, whether the parent layout controller + * is a OfficeGroupLayoutController and whether this layout controller is + * processing the normal flow or an repeating section. If a repeating section + * is being processed, an marker attribute is added to the element's call + * to OutputProcessor.startElement() and OutputProcessor.endElement(). + * + * @since 19.03.2007 + */ +public class OfficeGroupSectionLayoutController extends SectionLayoutController +{ + + public OfficeGroupSectionLayoutController() + { + } + + protected LayoutController startElement(final ReportTarget target) + throws DataSourceException, ReportProcessingException, ReportDataFactoryException + { + final OfficeGroupSection section = (OfficeGroupSection) getElement(); + if (!section.isRepeatSection()) + { + return super.startElement(target); + } + + final LayoutController controller = getParent(); + if (!(controller instanceof OfficeGroupLayoutController)) + { + return super.startElement(target); + } + final OfficeGroupLayoutController oglc = (OfficeGroupLayoutController) controller; + if (!oglc.isNormalFlowProcessing()) + { + return super.startElement(target); + } + + // Skip the processing if the section is a repeating header or footer and we are processing the normal flow .. + final ElementLayoutController clone = (ElementLayoutController) this.clone(); + clone.setProcessingState(ElementLayoutController.FINISHED); + return clone; + } + + protected AttributeMap computeAttributes(final FlowController fc, + final Element element, + final ReportTarget target) + throws DataSourceException + { + final AttributeMap attrs = super.computeAttributes(fc, element, target); + final LayoutController controller = getParent(); + if (!(controller instanceof OfficeGroupLayoutController)) + { + return attrs; + } + final OfficeGroupLayoutController oglc = (OfficeGroupLayoutController) controller; + if (oglc.isNormalFlowProcessing()) + { + return attrs; + } + + final AttributeMap retval = new AttributeMap(attrs); + retval.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "repeated-section", OfficeToken.TRUE); + retval.makeReadOnly(); + return retval; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficePageSectionLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficePageSectionLayoutController.java new file mode 100644 index 000000000000..069ec7dfa298 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficePageSectionLayoutController.java @@ -0,0 +1,47 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; +import org.jfree.report.structure.Element; + +/** + * Todo: Document Me + * + */ +public class OfficePageSectionLayoutController extends SectionLayoutController +{ + + public OfficePageSectionLayoutController() + { + } + + protected AttributeMap computeAttributes(final FlowController flowController, final Element element, final ReportTarget reportTarget) throws DataSourceException + { + final AttributeMap map = new AttributeMap(super.computeAttributes(flowController, element, reportTarget)); + map.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "role", "spreadsheet-section"); + map.makeReadOnly(); + return map; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeRepeatingStructureLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeRepeatingStructureLayoutController.java new file mode 100644 index 000000000000..a07aaf9a2b5c --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeRepeatingStructureLayoutController.java @@ -0,0 +1,34 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.jfree.report.flow.layoutprocessor.LayoutController; + +/** + * Todo: Document me! + * + * @since 22.03.2007 + */ +public interface OfficeRepeatingStructureLayoutController extends LayoutController +{ + + public boolean isNormalFlowProcessing(); + + public VariablesCollection getVariablesCollection(); +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeReportLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeReportLayoutController.java new file mode 100644 index 000000000000..a9cc10fc8de5 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeReportLayoutController.java @@ -0,0 +1,260 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.pentaho.model.OfficeReport; +import org.libreoffice.report.pentaho.model.VariablesDeclarationSection; + +import org.jfree.report.DataSourceException; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportContext; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.ElementLayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutControllerFactory; +import org.jfree.report.structure.Node; + +/** + * Todo: Document me! + * + * @since 06.03.2007 + */ +public class OfficeReportLayoutController extends ElementLayoutController + implements OfficeRepeatingStructureLayoutController +{ + + private static final int STATE_NOT_STARTED = 0; + private static final int STATE_TEMPLATES = 1; + private static final int STATE_PAGE_HEADER_DONE = 2; + private static final int STATE_PAGE_FOOTER_DONE = 3; + private static final int STATE_SPREADSHEET_PAGE_HEADER_DONE = 4; + private static final int STATE_SPREADSHEET_PAGE_FOOTER_DONE = 5; + private static final int STATE_COLUMN_HEADER_DONE = 6; + private static final int STATE_COLUMN_FOOTER_DONE = 7; + private static final int STATE_INITIAL_VARIABLES_DONE = 8; + private static final int STATE_REPORT_HEADER_DONE = 9; + private static final int STATE_REPORT_BODY_DONE = 10; + private static final int STATE_REPORT_FOOTER_VARIABLES = 11; + private static final int STATE_REPORT_FOOTER_DONE = 12; + private int state; + private VariablesCollection variablesCollection; + + public OfficeReportLayoutController() + { + } + + /** + * Initializes the layout controller. This method is called exactly once. It + * is the creators responsibility to call this method. + * <p/> + * Calling initialize after the first advance must result in a + * IllegalStateException. + * + * @param node the currently processed object or layout node. + * @param flowController the current flow controller. + * @param parent the parent layout controller that was responsible for + * instantiating this controller. + * @throws org.jfree.report.DataSourceException + * if there was a problem reading data from the datasource. + * @throws org.jfree.report.ReportProcessingException + * if there was a general problem during the report processing. + * @throws org.jfree.report.ReportDataFactoryException + * if a query failed. + */ + public void initialize(final Object node, final FlowController flowController, + final LayoutController parent) + throws DataSourceException, ReportDataFactoryException, + ReportProcessingException + { + super.initialize(node, flowController, parent); + variablesCollection = new VariablesCollection("auto_report_"); + } + + /** + * Processes any content in this element. This method is called when the + * processing state is 'OPENED'. The returned layout controller will retain + * the 'OPENED' state as long as there is more content available. Once all + * content has been processed, the returned layout controller should carry a + * 'FINISHED' state. + * + * @param target the report target that receives generated events. + * @return the new layout controller instance representing the new state. + * + * @throws org.jfree.report.DataSourceException + * if there was a problem reading data from the datasource. + * @throws org.jfree.report.ReportProcessingException + * if there was a general problem during the report processing. + * @throws org.jfree.report.ReportDataFactoryException + * if a query failed. + */ + protected LayoutController processContent(final ReportTarget target) + throws DataSourceException, ReportProcessingException, + ReportDataFactoryException + { + final OfficeReport or = (OfficeReport) getElement(); + + switch (state) + { + case OfficeReportLayoutController.STATE_NOT_STARTED: + { + return delegateToTemplates(OfficeReportLayoutController.STATE_TEMPLATES); + } + case OfficeReportLayoutController.STATE_TEMPLATES: + { + return delegateSection(or.getPageHeader(), + OfficeReportLayoutController.STATE_PAGE_HEADER_DONE); + } + case OfficeReportLayoutController.STATE_PAGE_HEADER_DONE: + { + return delegateSpreadsheetSection(or.getPageHeader(), + OfficeReportLayoutController.STATE_SPREADSHEET_PAGE_HEADER_DONE); + } + case OfficeReportLayoutController.STATE_SPREADSHEET_PAGE_HEADER_DONE: + { + return delegateSection(or.getPageFooter(), + OfficeReportLayoutController.STATE_PAGE_FOOTER_DONE); + } + case OfficeReportLayoutController.STATE_PAGE_FOOTER_DONE: + { + return delegateSection(or.getColumnHeader(), + OfficeReportLayoutController.STATE_COLUMN_HEADER_DONE); + } + case OfficeReportLayoutController.STATE_COLUMN_HEADER_DONE: + { + return delegateSection(or.getColumnFooter(), + OfficeReportLayoutController.STATE_COLUMN_FOOTER_DONE); + } + case OfficeReportLayoutController.STATE_COLUMN_FOOTER_DONE: + { + return delegateSection(new VariablesDeclarationSection(), + OfficeReportLayoutController.STATE_INITIAL_VARIABLES_DONE); + } + case OfficeReportLayoutController.STATE_INITIAL_VARIABLES_DONE: + { + return delegateSection(or.getReportHeader(), + OfficeReportLayoutController.STATE_REPORT_HEADER_DONE); + } + case OfficeReportLayoutController.STATE_REPORT_HEADER_DONE: + { + return delegateSection(or.getBodySection(), + OfficeReportLayoutController.STATE_REPORT_BODY_DONE); + } + case OfficeReportLayoutController.STATE_REPORT_BODY_DONE: + { + return delegateSection(new VariablesDeclarationSection(), + OfficeReportLayoutController.STATE_REPORT_FOOTER_VARIABLES); + } + case OfficeReportLayoutController.STATE_REPORT_FOOTER_VARIABLES: + { + return delegateSection(or.getReportFooter(), + OfficeReportLayoutController.STATE_REPORT_FOOTER_DONE); + } + case OfficeReportLayoutController.STATE_REPORT_FOOTER_DONE: + { + return delegateSpreadsheetSection(or.getPageFooter(), + OfficeReportLayoutController.STATE_SPREADSHEET_PAGE_FOOTER_DONE); + } + case OfficeReportLayoutController.STATE_SPREADSHEET_PAGE_FOOTER_DONE: + { + final OfficeReportLayoutController olc = (OfficeReportLayoutController) clone(); + olc.setProcessingState(ElementLayoutController.FINISHING); + return olc; + } + default: + { + throw new IllegalStateException("Invalid processing state encountered."); + } + } + } + + private LayoutController delegateSpreadsheetSection(final Node node, final int nextState) + throws DataSourceException, ReportProcessingException, ReportDataFactoryException + { + final OfficeReportLayoutController olc = (OfficeReportLayoutController) clone(); + olc.state = nextState; + + if (node == null) + { + return olc; + } + + final OfficePageSectionLayoutController templateLc = new OfficePageSectionLayoutController(); + templateLc.initialize(node, getFlowController(), olc); + return templateLc; + } + + private LayoutController delegateToTemplates(final int nextState) + throws ReportProcessingException, ReportDataFactoryException, + DataSourceException + { + final OfficeReportLayoutController olc = (OfficeReportLayoutController) clone(); + olc.state = nextState; + + final OfficeTableTemplateLayoutController templateLc = new OfficeTableTemplateLayoutController(); + templateLc.initialize(getElement(), getFlowController(), olc); + return templateLc; + + } + + private LayoutController delegateSection(final Node n, final int nextState) + throws ReportProcessingException, ReportDataFactoryException, + DataSourceException + { + final OfficeReportLayoutController olc = (OfficeReportLayoutController) clone(); + olc.state = nextState; + if (n == null) + { + return olc; + } + + final FlowController flowController = getFlowController(); + final ReportContext reportContext = flowController.getReportContext(); + final LayoutControllerFactory layoutControllerFactory = + reportContext.getLayoutControllerFactory(); + return layoutControllerFactory.create(flowController, n, olc); + + } + + /** + * Joins with a delegated process flow. This is generally called from a child + * flow and should *not* (I mean it!) be called from outside. If you do, + * you'll suffer. + * + * @param flowController the flow controller of the parent. + * @return the joined layout controller that incorperates all changes from the + * delegate. + */ + public LayoutController join(final FlowController flowController) + { + final OfficeReportLayoutController derived = (OfficeReportLayoutController) clone(); + derived.setFlowController(flowController); + return derived; + } + + public boolean isNormalFlowProcessing() + { + return state != OfficeReportLayoutController.STATE_PAGE_HEADER_DONE && state != OfficeReportLayoutController.STATE_PAGE_FOOTER_DONE; + } + + public VariablesCollection getVariablesCollection() + { + return variablesCollection; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableLayoutController.java new file mode 100644 index 000000000000..ed5d63887051 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableLayoutController.java @@ -0,0 +1,69 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.OfficeToken; +import org.libreoffice.report.pentaho.OfficeNamespaces; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; +import org.jfree.report.structure.Element; +import org.jfree.report.structure.Node; +import org.jfree.report.structure.Section; +import org.jfree.report.util.IntegerCache; + +/** + * Creation-Date: 24.04.2007, 14:40:20 + * + */ +public class OfficeTableLayoutController extends SectionLayoutController +{ + + public OfficeTableLayoutController() + { + } + + protected AttributeMap computeAttributes(final FlowController fc, final Element element, final ReportTarget target) + throws DataSourceException + { + final AttributeMap attributeMap = new AttributeMap(super.computeAttributes(fc, element, target)); + final Section s = (Section) element; + int rowCount = 0; + final Node[] nodeArray = s.getNodeArray(); + for (int i = 0; i < nodeArray.length; i++) + { + final Node node = nodeArray[i]; + if (node instanceof Element) + { + final Element child = (Element) node; + if (OfficeNamespaces.TABLE_NS.equals(child.getNamespace()) && OfficeToken.TABLE_ROW.equals(child.getType())) + { + rowCount += 1; + } + } + } + + attributeMap.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "table-row-count", IntegerCache.getInteger(rowCount)); + attributeMap.makeReadOnly(); + return attributeMap; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableTemplateLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableTemplateLayoutController.java new file mode 100644 index 000000000000..e610fc421cb7 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableTemplateLayoutController.java @@ -0,0 +1,179 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.pentaho.OfficeNamespaces; +import org.libreoffice.report.pentaho.model.OfficeGroup; +import org.libreoffice.report.pentaho.model.OfficeReport; + +import java.util.ArrayList; +import java.util.List; + +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; +import org.jfree.report.structure.Element; +import org.jfree.report.structure.Node; +import org.jfree.report.structure.Section; + + +/** + * Creation-Date: 24.04.2007, 16:06:52 + * + */ +public class OfficeTableTemplateLayoutController extends SectionLayoutController +{ + + private Node[] nodes; + + public OfficeTableTemplateLayoutController() + { + } + + /** + * Initializes the layout controller. This method is called exactly once. It is the creators responsibility to call + * this method. + * <p/> + * Calling initialize after the first advance must result in a IllegalStateException. + * + * @param node the currently processed object or layout node. + * @param flowController the current flow controller. + * @param parent the parent layout controller that was responsible for instantiating this controller. + * @throws org.jfree.report.DataSourceException + * if there was a problem reading data from the datasource. + * @throws org.jfree.report.ReportProcessingException + * if there was a general problem during the report processing. + * @throws org.jfree.report.ReportDataFactoryException + * if a query failed. + */ + public void initialize(final Object node, final FlowController flowController, final LayoutController parent) + throws DataSourceException, ReportDataFactoryException, ReportProcessingException + { + final Section section = new Section(); + section.setNamespace(JFreeReportInfo.REPORT_NAMESPACE); + section.setType("template"); + super.initialize(section, flowController, parent); + + final OfficeReport report = (OfficeReport) node; + final ArrayList<Node> tables = new ArrayList<Node>(); + if (report.getPageHeader() != null) + { + addFromSection(tables, (Section) report.getPageHeader()); + } + if (report.getReportHeader() != null) + { + addFromSection(tables, (Section) report.getReportHeader()); + } + addPBody(tables, (Section) report.getPreBodySection()); + addFromBody(tables, (Section) report.getBodySection()); + addPBody(tables, (Section) report.getPostBodySection()); + if (report.getReportFooter() != null) + { + addFromSection(tables, (Section) report.getReportFooter()); + } + if (report.getPageFooter() != null) + { + addFromSection(tables, (Section) report.getPageFooter()); + } + + this.nodes = tables.toArray(new Node[tables.size()]); + } + + private void addPBody(final List<Node> tables, final Section section) + { + if (section != null) + { + // tables.add(section); + final Node[] nodeArray = section.getNodeArray(); + for (int i = 0; i < nodeArray.length; i++) + { + final Node node = nodeArray[i]; + tables.add(node); + } + + } + } + + private void addFromBody(final List<Node> tables, final Section section) + { + final Node[] nodeArray = section.getNodeArray(); + for (int i = 0; i < nodeArray.length; i++) + { + final Node node = nodeArray[i]; + if (node instanceof Section) + { + final Section child = (Section) node; + if (node instanceof OfficeGroup) + { + addFromGroup(tables, child); + } + else + { + addFromSection(tables, child); + } + } + } + } + + private void addFromGroup(final List<Node> tables, final Section section) + { + final Node[] nodeArray = section.getNodeArray(); + for (int i = 0; i < nodeArray.length; i++) + { + final Node node = nodeArray[i]; + if (node instanceof Section) + { + final Section element = (Section) node; + if (JFreeReportInfo.REPORT_NAMESPACE.equals(element.getNamespace()) && "group-body".equals(element.getType())) + { + addFromBody(tables, element); + } + else + { + addFromSection(tables, element); + } + } + } + } + + private void addFromSection(final List<Node> tables, final Section section) + { + final Node[] nodeArray = section.getNodeArray(); + for (int i = 0; i < nodeArray.length; i++) + { + final Node node = nodeArray[i]; + if (node instanceof Element) + { + final Element element = (Element) node; + if (OfficeNamespaces.TABLE_NS.equals(element.getNamespace()) && "table".equals(element.getType())) + { + tables.add(element); + } + } + } + } + + public Node[] getNodes() + { + return nodes; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/TableCellLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/TableCellLayoutController.java new file mode 100644 index 000000000000..dd07f8b2133d --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/TableCellLayoutController.java @@ -0,0 +1,228 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.OfficeToken; +import org.libreoffice.report.pentaho.OfficeNamespaces; +import org.libreoffice.report.pentaho.model.FormatCondition; +import org.libreoffice.report.pentaho.model.FormattedTextElement; +import org.libreoffice.report.pentaho.model.ReportElement; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataFlags; +import org.jfree.report.DataSourceException; +import org.jfree.report.expressions.Expression; +import org.jfree.report.expressions.FormulaExpression; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.LayoutControllerUtil; +import org.jfree.report.flow.layoutprocessor.SectionLayoutController; +import org.jfree.report.structure.Element; +import org.jfree.report.structure.Node; +import org.jfree.report.structure.Section; +import org.pentaho.reporting.libraries.formula.Formula; +import org.pentaho.reporting.libraries.formula.lvalues.LValue; +import org.pentaho.reporting.libraries.formula.parser.ParseException; + +import org.pentaho.reporting.libraries.base.util.ObjectUtilities; + +/** + * Before writing the table cell, we have to evaluate the children of the cell. The cell itself can either be empty or it + * has a one ore more paragraphs inside. The paragraph contains a single report element, but may contain additional + * other content. + * + * @noinspection CloneableClassWithoutClone + * @since 05.03.2007 + */ +public class TableCellLayoutController extends SectionLayoutController +{ + + public TableCellLayoutController() + { + } + + protected AttributeMap computeAttributes(final FlowController fc, + final Element element, + final ReportTarget target) + throws DataSourceException + { + final AttributeMap attributeMap = new AttributeMap(super.computeAttributes(fc, element, target)); + final String definedStyle = (String) attributeMap.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME); + attributeMap.setAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME, getDisplayStyleName((Section) element, definedStyle)); + + try + { + final DataFlags value = computeValue(attributeMap); + final String valueType = (String) attributeMap.getAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE); + if (value != null) + { + FormatValueUtility.applyValueForCell(value.getValue(), attributeMap, valueType); + } + else if ( "float".equals(valueType)) + { + attributeMap.setAttribute(OfficeNamespaces.OFFICE_NS, + FormatValueUtility.VALUE, "NaN"); + } + // #i114108#: except on form elements, the only value-type that can + // occur without an accompanying value attribute is "string" + else if (!"string".equals(valueType)) + { + attributeMap.setAttribute(OfficeNamespaces.OFFICE_NS, + FormatValueUtility.VALUE_TYPE, "string"); + } + } + catch (Exception e) + { + // ignore .. + } + attributeMap.makeReadOnly(); + return attributeMap; + } + + private DataFlags computeValue(final AttributeMap attributeMap) throws DataSourceException + { + // Search for the first FormattedTextElement + final Section cell = (Section) getElement(); + final FormattedTextElement element = findFormattedTextElement(cell); + if (element == null) + { + return null; + } + if (!FormatValueUtility.shouldPrint(this, element)) + { + attributeMap.setAttribute(OfficeNamespaces.OFFICE_NS, + FormatValueUtility.VALUE_TYPE, "string"); + return null; + } + return FormatValueUtility.computeDataFlag(element, getFlowController()); + } + + public boolean isValueChanged() + { + try + { + final Section cell = (Section) getElement(); + final FormattedTextElement element = findFormattedTextElement(cell); + if (element == null) + return false; + else + { + final FormulaExpression formulaExpression = element.getValueExpression(); + final Formula formula = formulaExpression.getCompiledFormula(); + final LValue lValue = formula.getRootReference(); + return FormatValueUtility.isReferenceChanged(this, lValue); + } + } + catch (final ParseException e) + { + //LOGGER.debug("Parse Exception", e); + return false; + } + } + + private FormattedTextElement findFormattedTextElement(final Section section) + { + final Node[] nodeArray = section.getNodeArray(); + for (int i = 0; i < nodeArray.length; i++) + { + final Node node = nodeArray[i]; + if (node instanceof FormattedTextElement) + { + return (FormattedTextElement) node; + } + else if (node instanceof Section) + { + final FormattedTextElement retval = findFormattedTextElement((Section) node); + if (retval != null) + { + return retval; + } + } + } + return null; + } + + private String getDisplayStyleName(final Section section, + final String defaultStyle) + { + if (!section.isEnabled() || section.getNodeCount() == 0) + { + return defaultStyle; + } + + final Node[] nodes = section.getNodeArray(); + for (int i = 0; i < nodes.length; i++) + { + final Node child = nodes[i]; + if (child instanceof ReportElement && child.isEnabled()) + { + final ReportElement element = (ReportElement) child; + if (element.getFormatConditionCount() > 0) + { + final Expression displayCond = element.getDisplayCondition(); + if (displayCond != null) + { + try + { + if (Boolean.FALSE.equals(LayoutControllerUtil.evaluateExpression(getFlowController(), element, displayCond))) + { + continue; + } + } + catch (DataSourceException e) + { + // ignore silently .. + } + } + + final FormatCondition[] conditions = element.getFormatConditions(); + for (int j = 0; j < conditions.length; j++) + { + final FormatCondition formCond = conditions[j]; + if (formCond.isEnabled()) + { + try + { + final Object o = LayoutControllerUtil.evaluateExpression(getFlowController(), element, formCond.getFormula()); + if (Boolean.TRUE.equals(o)) + { + return formCond.getStyleName(); + } + } + catch (DataSourceException e) + { + // ignore silently .. + } + } + } + } + } + + if (child instanceof Section) + { + final String childFormatCondition = + getDisplayStyleName((Section) child, defaultStyle); + if (!ObjectUtilities.equal(childFormatCondition, defaultStyle)) + { + return childFormatCondition; + } + } + } + return defaultStyle; + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesCollection.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesCollection.java new file mode 100644 index 000000000000..6cd025206eb9 --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesCollection.java @@ -0,0 +1,87 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.pentaho.model.FormattedTextElement; + +import java.util.ArrayList; +import java.util.List; + + +/** + * A variables collection is used to collect all FormattedTextElement objects + * of a repeated header or footer. Later, for each of these elements a variable + * setter is inserted into a hidden (in fact just very small) paragraph. These + * variables can later be read using the 'variable-get' construct. + * + * From the idea, this is equal to the 'strings' declaration of CSS3, although + * this code is explicit instead of declarative. + * + * @since 22.03.2007 + */ +public class VariablesCollection +{ + + private VariablesCollection parent; + private String namePrefix; + private List<FormattedTextElement> variables; + + public VariablesCollection(final String namePrefix) + { + this(namePrefix, null); + } + + public VariablesCollection(final String namePrefix, final VariablesCollection parent) + { + if (namePrefix == null) + { + throw new NullPointerException("NamePrefix cannot be null"); + } + + this.namePrefix = namePrefix; + this.parent = parent; + this.variables = new ArrayList<FormattedTextElement>(); + } + + public VariablesCollection getParent() + { + return parent; + } + + public String getNamePrefix() + { + return namePrefix; + } + + public String addVariable(final FormattedTextElement element) + { + variables.add(element); + final int size = variables.size(); + return namePrefix + size; + } + + public FormattedTextElement[] getVariables() + { + return variables.toArray(new FormattedTextElement[variables.size()]); + } + + public int getVariablesCount() + { + return variables.size(); + } +} diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesDeclarationLayoutController.java b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesDeclarationLayoutController.java new file mode 100644 index 000000000000..7edacec14e9e --- /dev/null +++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesDeclarationLayoutController.java @@ -0,0 +1,181 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ +package org.libreoffice.report.pentaho.layoutprocessor; + +import org.libreoffice.report.pentaho.OfficeNamespaces; +import org.libreoffice.report.pentaho.model.FormattedTextElement; + +import java.text.SimpleDateFormat; + +import java.util.Date; + +import org.jfree.layouting.util.AttributeMap; +import org.jfree.report.DataSourceException; +import org.jfree.report.JFreeReportInfo; +import org.jfree.report.ReportDataFactoryException; +import org.jfree.report.ReportProcessingException; +import org.jfree.report.expressions.FormulaExpression; +import org.jfree.report.flow.FlowController; +import org.jfree.report.flow.ReportTarget; +import org.jfree.report.flow.layoutprocessor.AbstractLayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutController; +import org.jfree.report.flow.layoutprocessor.LayoutControllerUtil; +import org.jfree.report.structure.Element; + +/** + * Writes a full variables-declaration section. + * + * @since 20.03.2007 + */ +public class VariablesDeclarationLayoutController + extends AbstractLayoutController +{ + + private boolean processed; + + public VariablesDeclarationLayoutController() + { + } + + private OfficeRepeatingStructureLayoutController getRepeatingParent() + { + LayoutController parent = getParent(); + while (parent != null) + { + if (parent instanceof OfficeRepeatingStructureLayoutController) + { + return (OfficeRepeatingStructureLayoutController) parent; + } + parent = parent.getParent(); + } + return null; + } + + /** + * Advances the processing position. + * + * @param target the report target that receives generated events. + * @return the new layout controller instance representing the new state. + * + * @throws org.jfree.report.DataSourceException + * if there was a problem reading data from the datasource. + * @throws org.jfree.report.ReportProcessingException + * if there was a general problem during the report processing. + * @throws org.jfree.report.ReportDataFactoryException + * if a query failed. + */ + public LayoutController advance(final ReportTarget target) + throws DataSourceException, ReportDataFactoryException, + ReportProcessingException + { + if (processed) + { + throw new IllegalStateException("Already processed."); + } + + final VariablesDeclarationLayoutController vlc = + (VariablesDeclarationLayoutController) clone(); + vlc.processed = true; + + final OfficeRepeatingStructureLayoutController orslc = getRepeatingParent(); + if (orslc == null) + { + // There is no repeating parent. What the heck are we doing here .. + return vlc; + } + + final VariablesCollection collection = orslc.getVariablesCollection(); + if (collection.getVariablesCount() == 0) + { + // no processing necessary, as the header or footer contain no variables at all .. + return vlc; + } + + + final Element node = (Element) getNode(); + final AttributeMap vdSection = node.getAttributeMap(); + target.startElement(vdSection); + + final FormattedTextElement[] variables = collection.getVariables(); + for (int i = 0; i < variables.length; i++) + { + final FormattedTextElement variable = variables[i]; + final String varName = collection.getNamePrefix() + (i + 1); + final AttributeMap map = generateVariableSetSection(variable); + map.setAttribute(OfficeNamespaces.TEXT_NS, "name", varName); + target.startElement(map); + target.endElement(map); + + } + target.endElement(vdSection); + return vlc; + } + + private AttributeMap generateVariableSetSection(final FormattedTextElement variable) + throws DataSourceException + { + final AttributeMap variableSection = new AttributeMap(); + variableSection.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.NAMESPACE_ATTRIBUTE, OfficeNamespaces.TEXT_NS); + variableSection.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.TYPE_ATTRIBUTE, "variable-set"); + variableSection.setAttribute(OfficeNamespaces.TEXT_NS, "display", "none"); + + final FormulaExpression valueExpression = variable.getValueExpression(); + final Object value = LayoutControllerUtil.evaluateExpression(getFlowController(), variable, valueExpression); + String formula = FormatValueUtility.applyValueForVariable(value, variableSection); + if (formula == null) + { + formula = "" + value; + } + if (value instanceof java.sql.Date) + { + final Date date = (Date) value; + final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy;MM;dd"); + formula = "Date(" + dateFormat.format(date) + ")"; + } + variableSection.setAttribute(OfficeNamespaces.TEXT_NS, "formula", "ooow:" + formula); + + return variableSection; + } + + /** + * Checks, whether the layout controller would be advanceable. If this method + * returns true, it is generally safe to call the 'advance()' method. + * + * @return true, if the layout controller is advanceable, false otherwise. + */ + public boolean isAdvanceable() + { + return !processed; + } + + /** + * Joins with a delegated process flow. This is generally called from a child + * flow and should *not* (I mean it!) be called from outside. If you do, + * you'll suffer. + * + * @param flowController the flow controller of the parent. + * @return the joined layout controller that incorperates all changes from the + * delegate. + */ + public LayoutController join(final FlowController flowController) + throws DataSourceException, ReportDataFactoryException, + ReportProcessingException + { + throw new UnsupportedOperationException("Join is not supported in this layout controller"); + } +} |