summaryrefslogtreecommitdiffstats
path: root/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor
diff options
context:
space:
mode:
Diffstat (limited to 'reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor')
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/AbstractReportElementLayoutController.java139
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FixedTextLayoutController.java74
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormatValueUtility.java333
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormattedTextLayoutController.java145
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementContext.java61
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementLayoutController.java308
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ObjectOleLayoutController.java110
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeDetailLayoutController.java150
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupInstanceSectionLayoutController.java173
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupLayoutController.java207
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupSectionLayoutController.java97
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficePageSectionLayoutController.java44
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeRepeatingStructureLayoutController.java34
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeReportLayoutController.java258
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableLayoutController.java66
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableTemplateLayoutController.java177
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/TableCellLayoutController.java220
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesCollection.java70
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesDeclarationLayoutController.java177
19 files changed, 2843 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 000000000..54de0f4f4
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/AbstractReportElementLayoutController.java
@@ -0,0 +1,139 @@
+/*
+ * 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.ReportElement;
+
+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.ReportTarget;
+import org.jfree.report.flow.layoutprocessor.AbstractLayoutController;
+import org.jfree.report.flow.layoutprocessor.LayoutController;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 05.03.2007
+ */
+@SuppressWarnings({"CloneableClassWithoutClone"})
+public abstract class AbstractReportElementLayoutController
+ extends AbstractLayoutController
+{
+
+ private 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 incorporates 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 000000000..3f9631792
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FixedTextLayoutController.java
@@ -0,0 +1,74 @@
+/*
+ * 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 specification.
+ * 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.
+ *
+ * @since 05.03.2007
+ */
+@SuppressWarnings({"CloneableClassWithoutClone"})
+public class FixedTextLayoutController
+ extends AbstractReportElementLayoutController
+{
+
+ @Override
+ public boolean isValueChanged()
+ {
+ final FlowController controller = getFlowController();
+ final GlobalMasterRow masterRow = controller.getMasterRow();
+ final ReportDataRow reportDataRow = masterRow.getReportDataRow();
+ return reportDataRow.getCursor() == 0;
+ }
+
+ @Override
+ 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 000000000..eab7c5122
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormatValueUtility.java
@@ -0,0 +1,333 @@
+/*
+ * 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.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.jfree.report.structure.DetailSection;
+
+import org.pentaho.reporting.libraries.formula.lvalues.ContextLookup;
+import org.pentaho.reporting.libraries.formula.lvalues.LValue;
+
+/**
+ * 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";
+ private 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, "date");
+ ret = formatDate((Date) value);
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, "date-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, "void");
+ }
+ return ret;
+ }
+
+ public static void applyValueForCell(final Object value, final AttributeMap variableSection, final String valueType)
+ {
+ if (value instanceof Time)
+ {
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "time");
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, "time-value", formatTime((Time) value));
+ }
+ else if (value instanceof java.sql.Date)
+ {
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "date");
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, "date-value", formatDate((Date) value));
+ }
+ else if (value instanceof Date)
+ {
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "date");
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, "date-value", formatDate((Date) value));
+ }
+ else if (value instanceof BigDecimal)
+ {
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "float");
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE, String.valueOf(value));
+ }
+ 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)
+ {
+ 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");
+ }
+ // work around fdo#68024
+ //variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, STRING_VALUE, String.valueOf(value));
+ }
+ else
+ {
+ variableSection.setAttribute(OfficeNamespaces.OFFICE_NS, VALUE_TYPE, "void");
+ }
+ }
+
+ 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.config("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;
+ }
+
+ private static boolean isGroupChanged(LayoutController ref)
+ {
+ // search the group.
+ final SectionLayoutController slc = findGroupOrDetail(ref);
+ if (slc == null)
+ {
+ // {Page, Report} x {Header, Footer} have no usable iteration count
+ // err on the side of showing them rather than not showing them
+ return true;
+ }
+
+ // we are in the first iteration, so yes, the group has changed recently.
+ return slc.getIterationCount() == 0;
+ }
+
+ private static SectionLayoutController findGroupOrDetail(LayoutController ref)
+ {
+ LayoutController parent = ref.getParent();
+ while (parent != null)
+ {
+ if (!(parent instanceof SectionLayoutController))
+ {
+ parent = parent.getParent();
+ }
+ else
+ {
+ final SectionLayoutController slc = (SectionLayoutController) parent;
+ final Element element = slc.getElement();
+ if (!(element instanceof Group || element instanceof DetailSection))
+ {
+ 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 000000000..7959b5857
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/FormattedTextLayoutController.java
@@ -0,0 +1,145 @@
+/*
+ * 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.util.logging.Logger;
+
+import org.jfree.report.DataFlags;
+import org.jfree.report.DataSourceException;
+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 Logger LOGGER = Logger.getLogger(FormattedTextLayoutController.class.getName());
+
+ @Override
+ public boolean isValueChanged()
+ {
+ try
+ {
+ final FormattedTextElement element = (FormattedTextElement) getNode();
+ final FormulaExpression formulaExpression = element.getValueExpression();
+ if (formulaExpression.getFormulaExpression() == null)
+ return false;
+ final Formula formula = formulaExpression.getCompiledFormula();
+ final LValue lValue = formula.getRootReference();
+ return FormatValueUtility.isReferenceChanged(this, lValue);
+ }
+ catch (final ParseException e)
+ {
+ LOGGER.config("Parse Exception: " + e);
+ return false;
+ }
+ }
+
+ @Override
+ protected LayoutController delegateContentGeneration(final ReportTarget target)
+ throws ReportProcessingException, ReportDataFactoryException,
+ DataSourceException
+ {
+ final FormattedTextElement element = (FormattedTextElement) getNode();
+ // LEM 20130812 I have absolutely no clue why it wants to go via
+ // a variable like that. It complicates things, is fragile
+ // (because the variable-set is done in *every* detail section
+ // again and again. This in itself is not that bad, but when
+ // the detail section is of height zero, the "set" is never done...
+ // and this whole schema fails). For now, keep the code in case
+ // something break. If we survive the 4.2 cycle (in its entirety)
+ // without regression traced to this, then remove it (for 4.4 or
+ // something like that).
+ // 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 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;
+ }
+
+}
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 000000000..99888fa00
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementContext.java
@@ -0,0 +1,61 @@
+/*
+ * 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 String[] rowStyles;
+ private String[] colStyles;
+
+ public ImageElementContext(final int colSpan, final int rowSpan)
+ {
+ this.colStyles = new String[colSpan];
+ this.rowStyles = new String[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;
+ }
+
+
+
+
+}
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 000000000..6fc68e816
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ImageElementLayoutController.java
@@ -0,0 +1,308 @@
+/*
+ * 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 java.util.logging.Logger;
+
+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 Logger LOGGER = Logger.getLogger(ImageElementLayoutController.class.getName());
+ private ImageElementContext context;
+
+ @Override
+ 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. Don't 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.warning("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.warning("Rowspan or colspan for image-size calculation was invalid.");
+ return null;
+ }
+
+ final LayoutController rowController = cellController.getParent();
+ if (rowController == null)
+ {
+ LOGGER.warning("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 won't support such advanced techniques for the next few centuries...
+ final int columnPos = findNodeInSection(tableRow, tableCell, OfficeToken.COVERED_TABLE_CELL);
+ if (columnPos == -1)
+ {
+ LOGGER.warning("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.warning("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 too large. The table definition is therefore invalid. We do not try to fix this.
+ LOGGER.warning(
+ "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.warning("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;
+ }
+
+ @Override
+ 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 000000000..a7e4d4da0
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/ObjectOleLayoutController.java
@@ -0,0 +1,110 @@
+/*
+ * 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
+{
+
+ @Override
+ 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;
+ }
+
+ @Override
+ 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 000000000..8b0ea883b
--- /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;
+
+ /**
+ * 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.</p>
+ *
+ * @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.
+ */
+ @Override
+ 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.
+ */
+ @Override
+ 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);
+ }
+
+ @Override
+ 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 incorporates all changes from the
+ * delegate.
+ */
+ @Override
+ 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 000000000..923056ca2
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupInstanceSectionLayoutController.java
@@ -0,0 +1,173 @@
+/*
+ * 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;
+
+ @Override
+ 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;
+ }
+
+ @Override
+ 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 once the sun-cvs contains version 0.9.2.
+ @Override
+ 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);
+ }
+ }
+
+ @Override
+ 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);
+ }
+
+ @Override
+ 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 incorporates all changes from the
+ * delegate.
+ */
+ @Override
+ 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);
+ }
+
+ @Override
+ 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 000000000..e44bbcc71
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupLayoutController.java
@@ -0,0 +1,207 @@
+/*
+ * 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
+{
+
+ private static final int STATE_PROCESS_REPEATING_HEADER = 0;
+ private 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;
+
+ /**
+ * 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.</p>
+ *
+ * @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.
+ */
+ @Override
+ 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());
+ }
+
+ @Override
+ 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();
+
+ if (header == null)
+ {
+ return controller;
+ }
+
+ 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();
+
+ if (footer == null)
+ {
+ return controller;
+ }
+
+ 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 incorporates all changes from the
+ * delegate.
+ */
+ @Override
+ 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;
+ }
+
+ @Override
+ 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 000000000..956a69283
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeGroupSectionLayoutController.java
@@ -0,0 +1,97 @@
+/*
+ * 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 an OfficeGroupLayoutController and whether this layout controller is
+ * processing the normal flow or a 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
+{
+
+ @Override
+ 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;
+ }
+
+ @Override
+ 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 000000000..187c17001
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficePageSectionLayoutController.java
@@ -0,0 +1,44 @@
+/*
+ * 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
+{
+
+ @Override
+ 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 000000000..1de1f354a
--- /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
+ */
+interface OfficeRepeatingStructureLayoutController extends LayoutController
+{
+
+ boolean isNormalFlowProcessing();
+
+ 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 000000000..7fd2c78a1
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeReportLayoutController.java
@@ -0,0 +1,258 @@
+/*
+ * 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;
+
+ /**
+ * 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.</p>
+ *
+ * @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.
+ */
+ @Override
+ 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.
+ */
+ @Override
+ 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 incorporates 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 000000000..e2c2b5f4b
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableLayoutController.java
@@ -0,0 +1,66 @@
+/*
+ * 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
+{
+
+ @Override
+ 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 000000000..9030a18ef
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/OfficeTableTemplateLayoutController.java
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+ /**
+ * 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 an IllegalStateException.</p>
+ *
+ * @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.
+ */
+ @Override
+ 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);
+ }
+ }
+ }
+ }
+
+ @Override
+ 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 000000000..b61c640bf
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/TableCellLayoutController.java
@@ -0,0 +1,220 @@
+/*
+ * 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 one ore more paragraphs inside. The paragraph contains a single report element, but may contain additional
+ * other content.
+ *
+ * @since 05.03.2007
+ */
+@SuppressWarnings({"CloneableClassWithoutClone"})
+public class TableCellLayoutController extends SectionLayoutController
+{
+
+ @Override
+ 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);
+ }
+ // #i114108#: except on form elements, the only value-type that can
+ // occur without an accompanying value attribute is "string";
+ // the content is then in the body.
+ 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, "void");
+ 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)
+ {
+ 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 000000000..4f29d8c87
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesCollection.java
@@ -0,0 +1,70 @@
+/*
+ * 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 String namePrefix;
+ private List<FormattedTextElement> variables;
+
+ public VariablesCollection(final String namePrefix)
+ {
+ if (namePrefix == null)
+ {
+ throw new NullPointerException("NamePrefix cannot be null");
+ }
+
+ this.namePrefix = namePrefix;
+ this.variables = new ArrayList<FormattedTextElement>();
+ }
+
+ public String getNamePrefix()
+ {
+ return namePrefix;
+ }
+
+
+
+ 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 000000000..5d3f62120
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/layoutprocessor/VariablesDeclarationLayoutController.java
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+ 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 incorporates 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");
+ }
+}