summaryrefslogtreecommitdiffstats
path: root/reportbuilder/java
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /reportbuilder/java
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'reportbuilder/java')
-rw-r--r--reportbuilder/java/jfreereport.properties21
-rw-r--r--reportbuilder/java/libformula.properties34
-rw-r--r--reportbuilder/java/loader.properties22
-rw-r--r--reportbuilder/java/manifest.mf2
-rw-r--r--reportbuilder/java/org/libreoffice/report/DataRow.java36
-rw-r--r--reportbuilder/java/org/libreoffice/report/DataSource.java38
-rw-r--r--reportbuilder/java/org/libreoffice/report/DataSourceException.java55
-rw-r--r--reportbuilder/java/org/libreoffice/report/DataSourceFactory.java33
-rw-r--r--reportbuilder/java/org/libreoffice/report/ImageService.java43
-rw-r--r--reportbuilder/java/org/libreoffice/report/InputRepository.java78
-rw-r--r--reportbuilder/java/org/libreoffice/report/JobDefinitionException.java54
-rw-r--r--reportbuilder/java/org/libreoffice/report/JobProperties.java36
-rw-r--r--reportbuilder/java/org/libreoffice/report/OfficeToken.java52
-rw-r--r--reportbuilder/java/org/libreoffice/report/OutputRepository.java61
-rw-r--r--reportbuilder/java/org/libreoffice/report/ParameterMap.java32
-rw-r--r--reportbuilder/java/org/libreoffice/report/ReportEngineMetaData.java34
-rw-r--r--reportbuilder/java/org/libreoffice/report/ReportEngineParameterNames.java46
-rw-r--r--reportbuilder/java/org/libreoffice/report/ReportExecutionException.java77
-rw-r--r--reportbuilder/java/org/libreoffice/report/ReportJob.java58
-rw-r--r--reportbuilder/java/org/libreoffice/report/ReportJobDefinition.java47
-rw-r--r--reportbuilder/java/org/libreoffice/report/ReportJobFactory.java28
-rw-r--r--reportbuilder/java/org/libreoffice/report/SDBCReportData.java367
-rw-r--r--reportbuilder/java/org/libreoffice/report/SDBCReportDataFactory.java539
-rw-r--r--reportbuilder/java/org/libreoffice/report/SOImageService.java162
-rw-r--r--reportbuilder/java/org/libreoffice/report/StorageRepository.java330
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/Author-Function.properties21
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/Author-Function_en_US.properties21
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/AuthorFunction.java48
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/AuthorFunctionDescription.java57
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/MetaDataFunctionCategory.java33
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/Title-Function.properties21
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/Title-Function_en_US.properties21
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/TitleFunction.java48
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/TitleFunctionDescription.java57
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/category.properties21
-rw-r--r--reportbuilder/java/org/libreoffice/report/function/metadata/category_en_US.properties21
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/DefaultNameGenerator.java147
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/Manifest.mf7
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/OfficeNamespaces.java60
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/PentahoFormulaContext.java84
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportEngine.java53
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportEngineMetaData.java67
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportJob.java381
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/SOFormulaOpCodeMapper.java143
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/SOFormulaParser.java430
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/SOFunctionManager.java157
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/SOReportJobFactory.java453
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/StarFunctionCategory.java166
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/StarFunctionDescription.java196
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/StarReportData.java155
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/StarReportDataFactory.java111
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/StarReportModule.java48
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/configuration.properties147
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/expressions/SumExpression.java23
-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
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/loader/InputRepositoryLoader.java162
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/loader/InputRepositoryResourceData.java76
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/loader/InputResourceKey.java54
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/DataStyle.java37
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/FixedTextElement.java42
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/FontFaceDeclsSection.java64
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/FontFaceElement.java37
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/FormatCondition.java57
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/FormattedTextElement.java44
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/ImageElement.java68
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/ObjectOleElement.java75
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeDetailSection.java30
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeDocument.java59
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroup.java80
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroupInstanceSection.java42
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroupSection.java40
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeMasterPage.java52
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeMasterStyles.java73
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeReport.java122
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStyle.java104
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStyles.java180
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStylesCollection.java113
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeTableSection.java29
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/PageLayout.java58
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/PageSection.java46
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/RawText.java36
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/ReportElement.java100
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/TableCellElement.java30
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/model/VariablesDeclarationSection.java42
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/module.properties36
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/oasis-datastyle.css23
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/oasis-draw.css5
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/oasis-form.css5
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/oasis-style.css28
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/oasis-table.css55
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/oasis-text.css27
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/ImageProducer.java483
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/OfficeDocumentReportTarget.java1692
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/OleProducer.java124
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/StyleUtilities.java590
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/StylesWriter.java379
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/chart/ChartRawReportProcessor.java98
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/chart/ChartRawReportTarget.java255
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/spreadsheet/SpreadsheetRawReportProcessor.java110
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/spreadsheet/SpreadsheetRawReportTarget.java944
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/text/MasterPageFactory.java382
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/text/PageBreakDefinition.java39
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/text/PageContext.java218
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/text/TextRawReportProcessor.java108
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/text/TextRawReportTarget.java1423
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/output/text/VariablesDeclarations.java98
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/ElementReadHandler.java78
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/OfficeDocumentXmlResourceFactory.java39
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/OfficeStylesXmlResourceFactory.java47
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/StarStyleXmlFactoryModule.java50
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/StarXmlFactoryModule.java50
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/chart/ChartReadHandler.java102
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/data/DataStyleReadHandler.java125
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/draw/ObjectOleReadHandler.java77
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/office/BodyReadHandler.java85
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/office/DocumentContentReadHandler.java225
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/office/DocumentStylesReadHandler.java98
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/office/FontFaceDeclsReadHandler.java105
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/office/MasterStylesReadHandler.java111
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ConditionalPrintExpressionReadHandler.java72
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/DetailRootTableReadHandler.java29
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FixedContentReadHandler.java90
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FormatConditionReadHandler.java91
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FormattedTextReadHandler.java111
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FunctionReadHandler.java103
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/GroupReadHandler.java181
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/GroupSectionReadHandler.java29
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ImageReadHandler.java134
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/MasterDetailReadHandler.java99
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ReportElementReadHandler.java103
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ReportReadHandler.java235
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/RootTableReadHandler.java99
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/SubDocumentReadHandler.java121
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/style/FontFaceReadHandler.java47
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/style/MasterPageReadHandler.java98
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/style/OfficeStyleReadHandler.java96
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/style/OfficeStylesReadHandler.java133
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/style/PageLayoutReadHandler.java97
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/style/StyleDefinitionReadHandler.java93
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/table/CoveredCellReadHandler.java45
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableCellReadHandler.java36
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableColumnReadHandler.java44
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableColumnsReadHandler.java96
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableReadHandler.java139
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableRowReadHandler.java119
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableRowsReadHandler.java92
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/text/NoCDATATextContentReadHandler.java185
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/text/TextContentReadHandler.java56
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/parser/xlink/XLinkReadHandler.java65
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/smil.css5
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/star-office.css5
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/star-report.css91
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/star-rpt.css5
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/LengthCalculator.java95
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapper.java86
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperKey.java90
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperXmlFactoryModule.java57
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperXmlResourceFactory.java44
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingDocumentReadHandler.java98
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingReadHandler.java88
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingRule.java54
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/stylemapper.xml763
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/styles/stylemapper.xsd81
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/svg.css5
-rw-r--r--reportbuilder/java/org/libreoffice/report/pentaho/xsl-fo.css5
-rw-r--r--reportbuilder/java/org/libreoffice/report/util/DefaultJobProperties.java71
-rw-r--r--reportbuilder/java/org/libreoffice/report/util/DefaultParameterMap.java57
-rw-r--r--reportbuilder/java/org/libreoffice/report/util/DefaultReportJobDefinition.java53
-rw-r--r--reportbuilder/java/reportbuilder.component21
187 files changed, 23303 insertions, 0 deletions
diff --git a/reportbuilder/java/jfreereport.properties b/reportbuilder/java/jfreereport.properties
new file mode 100644
index 000000000..b646efecc
--- /dev/null
+++ b/reportbuilder/java/jfreereport.properties
@@ -0,0 +1,21 @@
+#
+# 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 .
+#
+# x-no-translate
+
+org.jfree.report.modules.sun.report.Module=org.libreoffice.report.pentaho.StarReportModule
+
diff --git a/reportbuilder/java/libformula.properties b/reportbuilder/java/libformula.properties
new file mode 100644
index 000000000..79022b607
--- /dev/null
+++ b/reportbuilder/java/libformula.properties
@@ -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 .
+#
+# x-no-translate
+
+##
+# Any configuration will happen here.
+org.pentaho.reporting.libraries.formula.ZeroDate=1899
+org.pentaho.reporting.libraries.formula.ExcelDateBugAware=false
+
+#
+# A list of all known functions.
+#
+
+##
+# Meta data functions
+org.pentaho.reporting.libraries.formula.functions.metadata.Author.class=org.libreoffice.report.function.metadata.AuthorFunction
+org.pentaho.reporting.libraries.formula.functions.metadata.Author.description=org.libreoffice.report.function.metadata.AuthorFunctionDescription
+org.pentaho.reporting.libraries.formula.functions.metadata.Title.class=org.libreoffice.report.function.metadata.TitleFunction
+org.pentaho.reporting.libraries.formula.functions.metadata.Title.description=org.libreoffice.report.function.metadata.TitleFunctionDescription
diff --git a/reportbuilder/java/loader.properties b/reportbuilder/java/loader.properties
new file mode 100644
index 000000000..87120b50b
--- /dev/null
+++ b/reportbuilder/java/loader.properties
@@ -0,0 +1,22 @@
+#
+# 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 .
+#
+# x-no-translate
+
+org.pentaho.reporting.libraries.resourceloader.factory.type.org.libreoffice.report.pentaho.model.OfficeDocument=org.libreoffice.report.pentaho.parser.OfficeDocumentXmlResourceFactory
+org.pentaho.reporting.libraries.resourceloader.factory.type.org.libreoffice.report.pentaho.model.OfficeStylesCollection=org.libreoffice.report.pentaho.parser.OfficeStylesXmlResourceFactory
+org.pentaho.reporting.libraries.resourceloader.factory.type.org.libreoffice.report.pentaho.styles.StyleMapper=org.libreoffice.report.pentaho.styles.StyleMapperXmlResourceFactory
diff --git a/reportbuilder/java/manifest.mf b/reportbuilder/java/manifest.mf
new file mode 100644
index 000000000..2b335b640
--- /dev/null
+++ b/reportbuilder/java/manifest.mf
@@ -0,0 +1,2 @@
+RegistrationClassName: org.libreoffice.report.pentaho.SOReportJobFactory
+UNO-Type-Path:
diff --git a/reportbuilder/java/org/libreoffice/report/DataRow.java b/reportbuilder/java/org/libreoffice/report/DataRow.java
new file mode 100644
index 000000000..5c0566199
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/DataRow.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * This feeds data into the reporting engine, in case the data has been provided
+ * by the caller. The methods are a mix of TableModel methods and methods borrowed
+ * from the java.sql.ResultSet interface.
+ *
+ * The column and row index starts at 1 (as it is done in JDBC).
+ *
+ */
+public interface DataRow
+{
+
+ int getColumnCount() throws DataSourceException;
+
+ String getColumnName(int column) throws DataSourceException;
+
+ Object getObject(int column) throws DataSourceException;
+}
diff --git a/reportbuilder/java/org/libreoffice/report/DataSource.java b/reportbuilder/java/org/libreoffice/report/DataSource.java
new file mode 100644
index 000000000..ebdc314ee
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/DataSource.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * This feeds data into the reporting engine, in case the data has been provided
+ * by the caller. The methods are a mix of TableModel methods and methods borrowed
+ * from the java.sql.ResultSet interface.
+ *
+ * The column and row index starts at 1 (as it is done in JDBC).
+ *
+ */
+public interface DataSource extends DataRow
+{
+
+ int getRowCount() throws DataSourceException;
+
+ boolean absolute(int row) throws DataSourceException;
+
+ boolean next() throws DataSourceException;
+
+ void close() throws DataSourceException;
+}
diff --git a/reportbuilder/java/org/libreoffice/report/DataSourceException.java b/reportbuilder/java/org/libreoffice/report/DataSourceException.java
new file mode 100644
index 000000000..5990b030f
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/DataSourceException.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+/**
+ * A general exception to indicate that there was an error while accessing the
+ * datasource.
+ *
+ */
+public class DataSourceException extends Exception
+{
+
+ /**
+ * Constructs a new exception with <code>null</code> as its detail message.
+ * The cause is not initialized, and may subsequently be initialized by a call
+ * to {@link #initCause}.
+ */
+ public DataSourceException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message and cause.
+ * <p>Note that the detail message associated with <code>cause</code> is
+ * <i>not</i> automatically incorporated in this exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval by
+ * the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the {@link
+ * #getCause()} method). (A <tt>null</tt> value is permitted,
+ * and indicates that the cause is nonexistent or unknown.)
+ * @since 1.4
+ */
+ public DataSourceException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/DataSourceFactory.java b/reportbuilder/java/org/libreoffice/report/DataSourceFactory.java
new file mode 100644
index 000000000..9f0eee8df
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/DataSourceFactory.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+import java.util.Map;
+
+/**
+ * Allows to query the data repository and returns a datasource for the
+ * specified name and parameters. The parameters-map can be null, if there
+ * are no parameters required.
+ *
+ */
+public interface DataSourceFactory
+{
+
+ DataSource queryData(String name, Map<String,Object> parameters)
+ throws DataSourceException;
+}
diff --git a/reportbuilder/java/org/libreoffice/report/ImageService.java b/reportbuilder/java/org/libreoffice/report/ImageService.java
new file mode 100644
index 000000000..fbcfab4b9
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/ImageService.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+import com.sun.star.awt.Size;
+
+public interface ImageService
+{
+
+
+
+ /**
+ * @param image
+ * @return the mime-type of the image as string.
+ */
+ String getMimeType(final byte[] image) throws ReportExecutionException;
+
+
+
+ /**
+ * @param image
+ * @return the dimension in 100th mm.
+ *
+ * @throws ReportExecutionException
+ **/
+ Size getImageSize(final byte[] image) throws ReportExecutionException;
+}
+
diff --git a/reportbuilder/java/org/libreoffice/report/InputRepository.java b/reportbuilder/java/org/libreoffice/report/InputRepository.java
new file mode 100644
index 000000000..1e26bfea7
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/InputRepository.java
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This allows the job processor to load data from a repository. It is assumed,
+ * that all resource names are given as strings and furthermore, that the names
+ * identify a resource uniquely within the input repository.
+ *
+ * An input repository connects the report processing to the xml definitions.
+ * Unless defined otherwise, it is assumed, that the input-name is 'content.xml';
+ * possible other files are 'settings.xml' and 'styles.xml' (see the Oasis standard
+ * for details on these files and their contents).
+ *
+ */
+public interface InputRepository
+{
+
+ /**
+ * Returns a unique identifier for this repository. Two repositories accessing
+ * the same location should return the same id. The identifier must never
+ * be null.
+ *
+ * @return the repository id
+ */
+ Object getId();
+
+ InputStream createInputStream(final String name) throws IOException;
+
+ /** allows to access sub repositories inside this repository
+ *
+ * @param name describes the path to the sub repository
+ * @return the sub repository
+ * @throws java.io.IOException when the sub repository doesn't exist.
+ */
+ InputRepository openInputRepository(final String name) throws IOException;
+
+ /**
+ * This returns a version number for the given resource. Return zero, if
+ * the resource is not versionable, else return a unique number for each version.
+ * As rule of thumb: Increase the version number by at least one for each change
+ * made to the resource.
+ *
+ * @param name the name of the resource
+ * @return the version number
+ */
+ long getVersion(final String name);
+
+
+
+ boolean isReadable(final String name);
+
+ void closeInputRepository();
+
+ /** returns the URL of the database document
+ *
+ * @return the URL of the database document
+ */
+ String getRootURL();
+}
diff --git a/reportbuilder/java/org/libreoffice/report/JobDefinitionException.java b/reportbuilder/java/org/libreoffice/report/JobDefinitionException.java
new file mode 100644
index 000000000..06e7ac001
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/JobDefinitionException.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+/**
+ * Creation-Date: 05.02.2006, 17:36:33
+ *
+ */
+public class JobDefinitionException extends RuntimeException
+{
+
+ /**
+ * Creates a StackableRuntimeException with no message and no parent.
+ */
+ public JobDefinitionException()
+ {
+ }
+
+ /**
+ * Creates an exception.
+ *
+ * @param message the exception message.
+ */
+ public JobDefinitionException(final String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Creates an exception.
+ *
+ * @param message the exception message.
+ * @param ex the parent exception.
+ */
+ public JobDefinitionException(final String message, final Exception ex)
+ {
+ super(message, ex);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/JobProperties.java b/reportbuilder/java/org/libreoffice/report/JobProperties.java
new file mode 100644
index 000000000..42813428d
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/JobProperties.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+public interface JobProperties
+{
+
+ void setProperty(String key, Object value)
+ throws JobDefinitionException;
+
+ Object getProperty(String key);
+
+ /**
+ * A type safe clone operation. We derive a copy of all properties,
+ * so that changes to the original job properties collection does not
+ * affect the copy.
+ *
+ * @return a copy.
+ */
+ JobProperties copy();
+}
diff --git a/reportbuilder/java/org/libreoffice/report/OfficeToken.java b/reportbuilder/java/org/libreoffice/report/OfficeToken.java
new file mode 100644
index 000000000..9c2b59dca
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/OfficeToken.java
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+public class OfficeToken
+{
+
+ public static final String GRAPHIC = "graphic";
+ public static final String GRAPHICS = "Graphics";
+ public static final String GRAPHIC_PROPERTIES = "graphic-properties";
+ public static final String PARAGRAPH = "paragraph";
+ public static final String TRUE = "true";
+ public static final String FALSE = "false";
+ public static final String FRAME = "frame";
+ public static final String STYLE_NAME = "style-name";
+ public static final String BACKGROUND_COLOR = "background-color";
+ public static final String COVERED_TABLE_CELL = "covered-table-cell";
+ public static final String TABLE = "table";
+ public static final String TABLE_COLUMN = "table-column";
+ public static final String TABLE_COLUMNS = "table-columns";
+ public static final String TABLE_HEADER_COLUMNS = "table-header-columns";
+ public static final String TABLE_HEADER_ROWS = "table-header-rows";
+ public static final String TABLE_ROWS = "table-rows";
+ public static final String TABLE_ROW = "table-row";
+ public static final String TABLE_CELL = "table-cell";
+ public static final String P = "p";
+ public static final String OBJECT_OLE = "object-ole";
+ public static final String IMAGE = "image";
+ public static final String IMAGE_DATA = "image-data";
+ public static final String PRESERVE_IRI = "preserve-IRI";
+ public static final String SCALE = "scale";
+
+ public static final String SHAPES = "shapes";
+ public static final String ISOTROPIC = "isotropic";
+ public static final String ANISOTROPIC = "anisotropic";
+ public static final String NONE = "none";
+}
diff --git a/reportbuilder/java/org/libreoffice/report/OutputRepository.java b/reportbuilder/java/org/libreoffice/report/OutputRepository.java
new file mode 100644
index 000000000..62c1243f7
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/OutputRepository.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;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A repository for writing. Providing a repository always assumes,
+ * that more than one stream can be written.
+ *
+ */
+public interface OutputRepository
+{
+
+ /**
+ * Creates an output stream for writing the data. If there is an entry with
+ * that name already contained in the repository, try to overwrite it.
+ *
+ * @param name
+ * the name of the output stream
+ * @param mimeType
+ * the mime type of the to-be-created output stream. Repository implementations which do not support
+ * associating a mime time with a stream might ignore this parameter.
+ * @return the outputstream
+ * @throws IOException if opening the stream fails
+ */
+ OutputStream createOutputStream(final String name, final String mimeType) throws IOException;
+
+ /** allows to access sub repositories inside this repository
+ *
+ * @param name describes the path to the sub repository
+ * @param mimeType
+ * @return the sub repository
+ * @throws java.io.IOException when the sub repository doesn't exist.
+ */
+ OutputRepository openOutputRepository(final String name, final String mimeType) throws IOException;
+
+ boolean exists(final String name);
+
+ boolean existsStorage(final String name);
+
+
+
+ void closeOutputRepository();
+}
diff --git a/reportbuilder/java/org/libreoffice/report/ParameterMap.java b/reportbuilder/java/org/libreoffice/report/ParameterMap.java
new file mode 100644
index 000000000..4facd66ef
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/ParameterMap.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+public interface ParameterMap
+{
+ /**
+ * Retrieves the value stored for a key in this properties collection.
+ *
+ * @param key the property key.
+ * @return The stored value, or <code>null</code> if the key does not exist in this
+ * collection.
+ */
+ Object get(final String key);
+
+ String[] keys();
+}
diff --git a/reportbuilder/java/org/libreoffice/report/ReportEngineMetaData.java b/reportbuilder/java/org/libreoffice/report/ReportEngineMetaData.java
new file mode 100644
index 000000000..d99b2da9b
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/ReportEngineMetaData.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;
+
+public interface ReportEngineMetaData
+{
+
+
+
+
+
+ Class getParameterType(String parameter);
+
+
+
+
+
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/ReportEngineParameterNames.java b/reportbuilder/java/org/libreoffice/report/ReportEngineParameterNames.java
new file mode 100644
index 000000000..8d76cd1c6
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/ReportEngineParameterNames.java
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+/**
+ * Making this enumeration typesafe and fully defined here would
+ * be nice, wouldn't it?
+ */
+public class ReportEngineParameterNames
+{
+
+ public static final String CONTENT_TYPE = "content-type";
+ public static final String INPUT_NAME = "input.name";
+ public static final String INPUT_REPOSITORY = "input.repository";
+ public static final String OUTPUT_NAME = "output.name";
+ public static final String OUTPUT_REPOSITORY = "output.repository";
+ public static final String INPUT_DATASOURCE_FACTORY = "input.datasource-factory";
+ public static final String IMAGE_SERVICE = "ImageService";
+ public static final String INPUT_REPORTJOB_FACTORY = "input.reportjob-factory";
+ public static final String INPUT_MASTER_COLUMNS = "input.master-columns";
+ public static final String INPUT_MASTER_VALUES = "input.master-values";
+ public static final String INPUT_DETAIL_COLUMNS = "input.detail-columns";
+
+ public static final String AUTHOR = "Author";
+ public static final String TITLE = "Title";
+ public static final String MAXROWS = "MaxRows";
+
+ private ReportEngineParameterNames()
+ {
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/ReportExecutionException.java b/reportbuilder/java/org/libreoffice/report/ReportExecutionException.java
new file mode 100644
index 000000000..3d7334d68
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/ReportExecutionException.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+public class ReportExecutionException extends Exception
+{
+
+ /**
+ * Constructs a new exception with <code>null</code> as its detail message. The cause is
+ * not initialized, and may subsequently be initialized by a call to {@link
+ * #initCause}.
+ */
+ public ReportExecutionException()
+ {
+ }
+
+ /**
+ * Constructs a new exception with the specified cause and a detail message of
+ * <tt>(cause==null ? null : cause.toString())</tt> (which typically contains the class
+ * and detail message of <tt>cause</tt>). This constructor is useful for exceptions that
+ * are little more than wrappers for other throwables (for example, {@link
+ * java.security.PrivilegedActionException}).
+ *
+ * @param cause the cause (which is saved for later retrieval by the {@link #getCause()}
+ * method). (A <tt>null</tt> value is permitted, and indicates that the
+ * cause is nonexistent or unknown.)
+ * @since 1.4
+ */
+ public ReportExecutionException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message. The cause is not
+ * initialized, and may subsequently be initialized by a call to {@link #initCause}.
+ *
+ * @param message the detail message. The detail message is saved for later retrieval by
+ * the {@link #getMessage()} method.
+ */
+ public ReportExecutionException(String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Constructs a new exception with the specified detail message and cause. <p>Note that
+ * the detail message associated with <code>cause</code> is <i>not</i> automatically
+ * incorporated in this exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval by the {@link
+ * #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the {@link
+ * #getCause()} method). (A <tt>null</tt> value is permitted, and
+ * indicates that the cause is nonexistent or unknown.)
+ * @since 1.4
+ */
+ public ReportExecutionException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/ReportJob.java b/reportbuilder/java/org/libreoffice/report/ReportJob.java
new file mode 100644
index 000000000..f10d505d7
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/ReportJob.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import java.io.IOException;
+
+/**
+ * This allows some simple job control. A job can be interrupted (or if it has
+ * not yet been started, canceled), and the job status can be queried (scheduled,
+ * running, finished).
+ *
+ * <table summary="Job status values" border="1">
+ * <tr>
+ * <th>JobStatus</th><th>running</th><th>finished</th>
+ * </tr>
+ * <tr>
+ * <td>Scheduled</td><td>false</td><td>false</td>
+ * </tr>
+ * <tr>
+ * <td>Running</td><td>true</td><td>false</td>
+ * </tr>
+ * <tr>
+ * <td>Finished</td><td>false</td><td>true</td>
+ * </tr>
+ * </table>
+ *
+ */
+public interface ReportJob
+{
+
+ /**
+ * Although we might want to run the job as soon as it has been
+ * created, sometimes it is wiser to let the user add some listeners
+ * first. If we execute at once, the user either has to deal with
+ * threading code or won't receive any progress information in single
+ * threaded environments.
+ * @throws java.io.IOException
+ * @throws ReportExecutionException
+ */
+ void execute()
+ throws ReportExecutionException, IOException;
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/ReportJobDefinition.java b/reportbuilder/java/org/libreoffice/report/ReportJobDefinition.java
new file mode 100644
index 000000000..896d40264
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/ReportJobDefinition.java
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package org.libreoffice.report;
+
+/**
+ * The report job is created by the report job factory and holds all properties
+ * required to complete the reporting task.
+ *
+ */
+public interface ReportJobDefinition
+{
+
+ /**
+ * The parameters of the root report definition. The report parameters are using
+ * by the query factory to parametrize the query statement.
+ *
+ * The query parameters for the subreports are defined using mappings, it would not
+ * make sense to define them here.
+ *
+ * @return a map containing the report parameters
+ */
+ ParameterMap getQueryParameters();
+
+ /**
+ * The report processing parameters control the behaviour of the report. There are
+ * several mandatory parameters, some optional and possibly some not-yet-understood
+ * parameters. Use the engine meta data to find out, which parameters are supported.
+ *
+ * @return the processing parameters
+ */
+ JobProperties getProcessingParameters();
+}
diff --git a/reportbuilder/java/org/libreoffice/report/ReportJobFactory.java b/reportbuilder/java/org/libreoffice/report/ReportJobFactory.java
new file mode 100644
index 000000000..eeb16f656
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/ReportJobFactory.java
@@ -0,0 +1,28 @@
+/*
+ * 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;
+
+import com.sun.star.beans.NamedValue;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.uno.Exception;
+
+public interface ReportJobFactory
+{
+
+ ReportJob createReportJob(final NamedValue[] namedValue) throws IllegalArgumentException, ReportExecutionException, Exception;
+}
diff --git a/reportbuilder/java/org/libreoffice/report/SDBCReportData.java b/reportbuilder/java/org/libreoffice/report/SDBCReportData.java
new file mode 100644
index 000000000..a07006bfe
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/SDBCReportData.java
@@ -0,0 +1,367 @@
+/*
+ * 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;
+
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.lang.IndexOutOfBoundsException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.sdb.XParametersSupplier;
+import com.sun.star.sdbc.DataType;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XResultSetMetaData;
+import com.sun.star.sdbc.XResultSetMetaDataSupplier;
+import com.sun.star.sdbc.XRow;
+import com.sun.star.sdbc.XRowSet;
+import com.sun.star.sdbcx.XColumnsSupplier;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.util.DateTime;
+import com.sun.star.util.Time;
+
+import java.sql.Timestamp;
+
+public class SDBCReportData implements DataSource
+{
+
+ private final XRowSet rowSet;
+ private final XRow row;
+ private int rowCount;
+ private XIndexAccess parameters;
+ private int firstParameterIndex = -1;
+ private int columnCount;
+ private final String[] columnNames;
+ private final int[] columnTypes;
+
+ public SDBCReportData(final XRowSet rowSet) throws SQLException
+ {
+ row = UnoRuntime.queryInterface(XRow.class, rowSet);
+ this.rowSet = rowSet;
+
+ if (rowSet == null)
+ {
+ rowCount = 0;
+ columnCount = 0;
+ columnTypes = new int[1];
+ columnNames = new String[1];
+ }
+ else
+ {
+ final XParametersSupplier xSuppParams = UnoRuntime.queryInterface(
+ XParametersSupplier.class, rowSet);
+ if (xSuppParams != null)
+ {
+ parameters = xSuppParams.getParameters();
+ }
+
+ final XColumnsSupplier columnsSup = UnoRuntime.queryInterface(XColumnsSupplier.class, rowSet);
+ final XNameAccess columns = columnsSup.getColumns();
+ final String[] columnNamesList = columns.getElementNames();
+ final XResultSetMetaDataSupplier sup = UnoRuntime.queryInterface(XResultSetMetaDataSupplier.class, rowSet);
+ final XResultSetMetaData resultSetMetaData = sup.getMetaData();
+
+ columnCount = resultSetMetaData.getColumnCount();
+ firstParameterIndex = columnCount + 1;
+ if (parameters != null)
+ {
+ columnCount += parameters.getCount();
+ }
+
+ columnTypes = new int[columnCount];
+ columnNames = new String[columnCount];
+
+ for (int i = 1; i <= columnCount; ++i)
+ {
+ if (i < firstParameterIndex)
+ {
+ columnNames[i - 1] = columnNamesList[i - 1];// resultSetMetaData.getColumnName(i);
+ columnTypes[i - 1] = resultSetMetaData.getColumnType(i);
+ }
+ else
+ {
+ try
+ {
+ final XPropertySet paramColumn = UnoRuntime.queryInterface(
+ XPropertySet.class, parameters.getByIndex(i - firstParameterIndex));
+ columnNames[i - 1] = (String) paramColumn.getPropertyValue("Name");
+ columnTypes[i - 1] = (Integer) paramColumn.getPropertyValue("Type");
+ }
+ catch (Exception e)
+ {
+ columnNames[i - 1] = "Error";
+ columnTypes[i - 1] = DataType.CHAR;
+ }
+ }
+ }
+
+ if (rowSet.last())
+ {
+ rowCount = rowSet.getRow();
+ rowSet.beforeFirst();
+ }
+ else
+ {
+ rowCount = 0;
+ }
+ }
+ }
+
+ public int getColumnCount() throws DataSourceException
+ {
+ return columnCount;
+ }
+
+ public int getRowCount()
+ {
+ return rowCount;
+ }
+
+ public String getColumnName(final int column) throws DataSourceException
+ {
+ return columnNames[column - 1];
+ }
+
+ public boolean absolute(final int row) throws DataSourceException
+ {
+ if (rowSet == null)
+ {
+ return false;
+ }
+ try
+ {
+ if (row == 0)
+ {
+ rowSet.beforeFirst();
+ return true;
+ }
+ return rowSet.absolute(row);
+ }
+ catch (SQLException e)
+ {
+ throw new DataSourceException(e.getMessage(), e);
+ }
+ }
+
+ public boolean next() throws DataSourceException
+ {
+ if (rowSet == null)
+ {
+ return false;
+ }
+ try
+ {
+ return rowSet.next();
+ }
+ catch (SQLException e)
+ {
+ throw new DataSourceException(e.getMessage(), e);
+ }
+ }
+
+ public void close() throws DataSourceException
+ {
+ }
+
+ private static java.sql.Date getDate(final Object obj)
+ {
+ final java.sql.Date date;
+ if (obj instanceof com.sun.star.util.Date)
+ {
+ final com.sun.star.util.Date unodate = (com.sun.star.util.Date) obj;
+ date = java.sql.Date.valueOf(getDateString(unodate.Year, unodate.Month, unodate.Day).toString());
+ }
+ else
+ {
+ date = null;
+ }
+ return date;
+ }
+
+ private static StringBuffer getTimeString(final int hours, final int minutes, final int seconds)
+ {
+ final StringBuffer timeString = new StringBuffer();
+ if (hours < 10)
+ {
+ timeString.append('0');
+ }
+ timeString.append(hours);
+ timeString.append(':');
+ if (minutes < 10)
+ {
+ timeString.append('0');
+ }
+ timeString.append(minutes);
+ timeString.append(':');
+ if (seconds < 10)
+ {
+ timeString.append('0');
+ }
+ timeString.append(seconds);
+ return timeString;
+ }
+
+ private static StringBuffer getDateString(final int years, final int months, final int days)
+ {
+ final StringBuffer str = new StringBuffer();
+ str.append(years);
+ final StringBuffer str2 = new StringBuffer("0000");
+ str2.delete(0, str.length());
+ str.insert(0, str2);
+ str.append('-');
+ if (months < 10)
+ {
+ str.append('0');
+ }
+ str.append(months);
+ str.append('-');
+ if (days < 10)
+ {
+ str.append('0');
+ }
+ str.append(days);
+ return str;
+ }
+
+ private static java.sql.Time getTime(final Object obj)
+ {
+ final java.sql.Time time;
+ if (obj instanceof Time)
+ {
+ final Time unoTime = (Time) obj;
+ time = java.sql.Time.valueOf(getTimeString(unoTime.Hours, unoTime.Minutes, unoTime.Seconds).toString());
+ }
+ else
+ {
+ time = null;
+ }
+ return time;
+ }
+
+ private static Timestamp getTimestamp(final Object obj)
+ {
+ final Timestamp ts;
+ if (obj instanceof DateTime)
+ {
+ final DateTime unoTs = (DateTime) obj;
+ final StringBuffer str = getDateString(unoTs.Year, unoTs.Month, unoTs.Day);
+ str.append(' ');
+ str.append(getTimeString(unoTs.Hours, unoTs.Minutes, unoTs.Seconds));
+ str.append('.');
+ str.append(String.format("%09d", unoTs.NanoSeconds));
+ ts = java.sql.Timestamp.valueOf(str.toString());
+ }
+ else
+ {
+ ts = null;
+ }
+ return ts;
+ }
+
+ public Object getObject(final int column) throws DataSourceException
+ {
+ if (rowSet == null)
+ {
+ return null;
+ }
+ try
+ {
+ final boolean isParameterValue = (parameters != null) && (column >= firstParameterIndex);
+ Object obj;
+ final boolean wasNull;
+ if (isParameterValue)
+ {
+ final XPropertySet paramCol = UnoRuntime.queryInterface(
+ XPropertySet.class, parameters.getByIndex(column - firstParameterIndex));
+ obj = paramCol.getPropertyValue("Value");
+ wasNull = obj == null;
+ }
+ else
+ {
+ obj = row.getObject(column, null);
+ wasNull = row.wasNull();
+ }
+
+ if (wasNull)
+ {
+ obj = null;
+ }
+ else
+ {
+ obj = convertObject(columnTypes[column - 1], obj);
+ }
+ return obj;
+ }
+ catch (SQLException ex)
+ {
+ throw new DataSourceException(ex.getMessage(), ex);
+ }
+ catch (UnknownPropertyException ex)
+ {
+ throw new DataSourceException(ex.getMessage(), ex);
+ }
+ catch (IndexOutOfBoundsException ex)
+ {
+ throw new DataSourceException(ex.getMessage(), ex);
+ }
+ catch (WrappedTargetException ex)
+ {
+ throw new DataSourceException(ex.getMessage(), ex);
+ }
+ }
+
+ private Object convertObject(final int type, final Object obj)
+ {
+ Object ret;
+ switch (type)
+ {
+ case DataType.DATE:
+ ret = getDate(obj);
+ break;
+ case DataType.TIME:
+ ret = getTime(obj);
+ break;
+ case DataType.TIMESTAMP:
+ ret = getTimestamp(obj);
+ break;
+ case DataType.DECIMAL:
+ case DataType.NUMERIC:
+ if (!(obj instanceof Any))
+ {
+ try
+ {
+ ret = new java.math.BigDecimal(String.valueOf(obj));
+ }
+ catch (NumberFormatException ex)
+ {
+ ret = obj;
+ }
+ }
+ else
+ {
+ ret = obj;
+ }
+ break;
+ default:
+ ret = obj;
+ break;
+ }
+ return ret;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/SDBCReportDataFactory.java b/reportbuilder/java/org/libreoffice/report/SDBCReportDataFactory.java
new file mode 100644
index 000000000..b3c450866
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/SDBCReportDataFactory.java
@@ -0,0 +1,539 @@
+/*
+ * 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;
+
+import com.sun.star.awt.XWindow;
+import com.sun.star.beans.NamedValue;
+import com.sun.star.beans.PropertyVetoException;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.NoSuchElementException;
+import com.sun.star.container.XChild;
+import com.sun.star.container.XIndexAccess;
+import com.sun.star.container.XNameAccess;
+import com.sun.star.frame.XController;
+import com.sun.star.frame.XFrame;
+import com.sun.star.frame.XModel;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.IndexOutOfBoundsException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.sdb.CommandType;
+import com.sun.star.sdb.XCompletedExecution;
+import com.sun.star.sdb.XDocumentDataSource;
+import com.sun.star.sdb.XParametersSupplier;
+import com.sun.star.sdb.XQueriesSupplier;
+import com.sun.star.sdb.XSingleSelectQueryComposer;
+import com.sun.star.sdb.tools.XConnectionTools;
+import com.sun.star.sdbc.SQLException;
+import com.sun.star.sdbc.XConnection;
+import com.sun.star.sdbc.XParameters;
+import com.sun.star.sdbc.XRowSet;
+import com.sun.star.task.XInteractionHandler;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+import java.math.BigDecimal;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * Very primitive implementation, just to show how this could be used ...
+ *
+ */
+public class SDBCReportDataFactory implements DataSourceFactory
+{
+
+ private static final String ESCAPEPROCESSING = "EscapeProcessing";
+
+ private static class RowSetProperties
+ {
+
+ final Boolean escapeProcessing;
+ final int commandType;
+ final Integer maxRows;
+ final String command;
+ final String filter;
+
+ public RowSetProperties(final Boolean escapeProcessing, final int commandType, final String command, final String filter, final Integer maxRows)
+ {
+ this.escapeProcessing = escapeProcessing;
+ this.commandType = commandType;
+ this.command = command;
+ this.filter = filter;
+ this.maxRows = maxRows;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ {
+ return false;
+ }
+ if (getClass() != obj.getClass())
+ {
+ return false;
+ }
+ final RowSetProperties other = (RowSetProperties) obj;
+ if ((this.escapeProcessing == null) ? (other.escapeProcessing != null) : !this.escapeProcessing.equals(other.escapeProcessing))
+ {
+ return false;
+ }
+ if (this.commandType != other.commandType)
+ {
+ return false;
+ }
+ if ((this.maxRows == null) ? (other.maxRows != null) : !this.maxRows.equals(other.maxRows))
+ {
+ return false;
+ }
+ if ((this.command == null) ? (other.command != null) : !this.command.equals(other.command))
+ {
+ return false;
+ }
+ if ((this.filter == null) ? (other.filter != null) : !this.filter.equals(other.filter))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int hash = 3;
+ hash = 59 * hash + (this.escapeProcessing != null ? this.escapeProcessing.hashCode() : 0);
+ hash = 59 * hash + this.commandType;
+ hash = 59 * hash + (this.maxRows != null ? this.maxRows.hashCode() : 0);
+ hash = 59 * hash + (this.command != null ? this.command.hashCode() : 0);
+ hash = 59 * hash + (this.filter != null ? this.filter.hashCode() : 0);
+ return hash;
+ }
+ }
+
+ private static class ParameterDefinition
+ {
+ private int parameterCount = 0;
+ private final ArrayList<Integer> parameterIndex = new ArrayList<Integer>();
+ }
+ private static final Logger LOGGER = Logger.getLogger(SDBCReportDataFactory.class.getName());
+ public static final String COMMAND_TYPE = "command-type";
+ public static final String ESCAPE_PROCESSING = "escape-processing";
+ public static final String SORT_EXPRESSIONS = "sort-expressions";
+ public static final String GROUP_EXPRESSIONS = "group-expressions";
+ public static final String MASTER_VALUES = "master-values";
+ public static final String MASTER_COLUMNS = "master-columns";
+ public static final String DETAIL_COLUMNS = "detail-columns";
+ public static final String UNO_FILTER = "Filter";
+ private static final String APPLY_FILTER = "ApplyFilter";
+ private static final String UNO_COMMAND = "Command";
+ private static final String UNO_COMMAND_TYPE = "CommandType";
+ private final XConnection connection;
+ private final XComponentContext m_cmpCtx;
+ private final Map<RowSetProperties,XRowSet> rowSetProperties = new HashMap<RowSetProperties,XRowSet>();
+ private final Map<RowSetProperties,ParameterDefinition> parameterMap = new HashMap<RowSetProperties,ParameterDefinition>();
+ private boolean rowSetCreated = false;
+
+ public SDBCReportDataFactory(final XComponentContext cmpCtx, final XConnection connection)
+ {
+ this.connection = connection;
+ m_cmpCtx = cmpCtx;
+ }
+
+ public XWindow getParentWindow()
+ {
+ final XChild child = UnoRuntime.queryInterface(XChild.class, connection);
+ if (child == null)
+ return null;
+ final XDocumentDataSource docSource = UnoRuntime.queryInterface(XDocumentDataSource.class, child.getParent());
+ if (docSource == null)
+ return null;
+ final XModel model = UnoRuntime.queryInterface(XModel.class, docSource.getDatabaseDocument());
+ if (model == null)
+ return null;
+ final XController controller = model.getCurrentController();
+ if (controller == null)
+ return null;
+ final XFrame frame = controller.getFrame();
+ if (frame == null)
+ return null;
+ return frame.getContainerWindow();
+ }
+
+ public DataSource queryData(final String command, final Map<String,Object> parameters) throws DataSourceException
+ {
+ try
+ {
+ if (command == null)
+ {
+ return new SDBCReportData(null);
+ }
+ int commandType = CommandType.COMMAND;
+ final String commandTypeValue = (String) parameters.get(COMMAND_TYPE);
+ if (commandTypeValue != null)
+ {
+ if ("query".equals(commandTypeValue))
+ {
+ commandType = CommandType.QUERY;
+ }
+ else if ("table".equals(commandTypeValue))
+ {
+ commandType = CommandType.TABLE;
+ }
+ else
+ {
+ commandType = CommandType.COMMAND;
+ }
+ }
+ final Boolean escapeProcessing = (Boolean) parameters.get(ESCAPE_PROCESSING);
+ final String filter = (String) parameters.get(UNO_FILTER);
+ final Integer maxRows = (Integer) parameters.get("MaxRows");
+ final RowSetProperties rowSetProps = new RowSetProperties(escapeProcessing, commandType, command, filter, maxRows);
+
+ final Object[] p = createRowSet(rowSetProps, parameters);
+ final XRowSet rowSet = (XRowSet) p[0];
+
+ if (command.length() != 0)
+ {
+ final ParameterDefinition paramDef = (ParameterDefinition) p[1];
+ fillParameter(parameters, rowSet, paramDef);
+ rowSetCreated = rowSetCreated && (maxRows == null || maxRows == 0);
+
+ final XCompletedExecution execute = UnoRuntime.queryInterface(XCompletedExecution.class, rowSet);
+ if (rowSetCreated && execute != null && paramDef.parameterCount > 0)
+ {
+ final XWindow window = getParentWindow();
+ final XInteractionHandler handler = UnoRuntime.queryInterface(XInteractionHandler.class, m_cmpCtx.getServiceManager().createInstanceWithArgumentsAndContext("com.sun.star.sdb.InteractionHandler", new Object[] { new NamedValue("Parent", window) }, m_cmpCtx));
+ execute.executeWithCompletion(handler);
+ }
+ else
+ {
+ rowSet.execute();
+ }
+ }
+
+ rowSetCreated = false;
+ return new SDBCReportData(rowSet);
+ }
+ catch (Exception ex)
+ {
+ rowSetCreated = false;
+ throw new DataSourceException(ex.getMessage(), ex);
+ }
+ }
+
+ private String getOrderStatement(final List sortExpressions)
+ {
+ final StringBuffer order = new StringBuffer();
+ final int count = sortExpressions.size();
+ String quote;
+ try
+ {
+ quote = connection.getMetaData().getIdentifierQuoteString();
+ }
+ catch (SQLException ex)
+ {
+ LOGGER.severe("ReportProcessing failed / getOrderStatement could not get quote character: " + ex);
+ // fall back to the SQL standard
+ quote="";
+ }
+ for (int i = 0; i < count; i++)
+ {
+ final Object[] pair = (Object[]) sortExpressions.get(i);
+ String expression = (String) pair[0];
+
+ // LEM FIXME: ${EXPLETIVE}! Either the values we get are *always* already quoted
+ // (and then this whole work is not useful)
+ // or they are *never* quoted
+ // (and then just quote them unconditionally)
+ // The current mess gives an ambiguity when the column name starts with a quote character.
+ // It *seems* they are never quoted, but this needs further testing.
+ if (!expression.startsWith(quote))
+ {
+ expression = quote + expression + quote;
+ // LEM TODO: we should escape quotes in expression?
+ }
+ expression = expression.trim(); // Trim away white spaces
+
+ if (expression.length() > 0)
+ {
+ order.append(expression);
+ if (order.length() > 0)
+ {
+ order.append(' ');
+ }
+ final String sorting = (String) pair[1];
+ if (sorting == null || sorting.equals(OfficeToken.FALSE))
+ {
+ order.append("DESC");
+ }
+ if ((i + 1) < count)
+ {
+ order.append(", ");
+ }
+ }
+ }
+ return order.toString();
+ }
+
+ private XSingleSelectQueryComposer getComposer(final XConnectionTools tools,
+ final String command,
+ final int commandType)
+ {
+ return tools.getComposer(commandType, command);
+ }
+
+ private void fillParameter(final Map parameters,
+ final XRowSet rowSet, final ParameterDefinition paramDef)
+ throws SQLException,
+ IllegalArgumentException
+ {
+ final ArrayList<?> masterValues = (ArrayList<?>) parameters.get(MASTER_VALUES);
+ if (masterValues != null && !masterValues.isEmpty())
+ {
+ final XParameters para = UnoRuntime.queryInterface(XParameters.class, rowSet);
+
+ for (int i = 0;
+ i < masterValues.size();
+ i++)
+ {
+ Object object = masterValues.get(i);
+ if (object instanceof BigDecimal)
+ {
+ object = ((BigDecimal) object).toString();
+ }
+ final Integer pos = paramDef.parameterIndex.get(i);
+ para.setObject(pos + 1, object);
+ }
+ }
+ }
+
+ private final Object[] createRowSet(final RowSetProperties rowSetProps, final Map<String,Object> parameters)
+ throws Exception
+ {
+ final ArrayList<?> detailColumns = (ArrayList<?>) parameters.get(DETAIL_COLUMNS);
+ if (rowSetProperties.containsKey(rowSetProps) && detailColumns != null && !detailColumns.isEmpty())
+ {
+ return new Object[]
+ {
+ rowSetProperties.get(rowSetProps), parameterMap.get(rowSetProps)
+ };
+ }
+
+ rowSetCreated = true;
+ final XRowSet rowSet = UnoRuntime.queryInterface(XRowSet.class, m_cmpCtx.getServiceManager().createInstanceWithContext("com.sun.star.sdb.RowSet", m_cmpCtx));
+ final XPropertySet rowSetProp = UnoRuntime.queryInterface(XPropertySet.class, rowSet);
+
+ rowSetProp.setPropertyValue("ActiveConnection", connection);
+ rowSetProp.setPropertyValue(ESCAPEPROCESSING, rowSetProps.escapeProcessing);
+ rowSetProp.setPropertyValue(UNO_COMMAND_TYPE, Integer.valueOf(rowSetProps.commandType));
+ rowSetProp.setPropertyValue(UNO_COMMAND, rowSetProps.command);
+
+ if (rowSetProps.filter != null)
+ {
+ rowSetProp.setPropertyValue("Filter", rowSetProps.filter);
+ rowSetProp.setPropertyValue(APPLY_FILTER, Boolean.valueOf(rowSetProps.filter.length() != 0));
+ }
+ else
+ {
+ rowSetProp.setPropertyValue(APPLY_FILTER, Boolean.FALSE);
+ }
+
+ if (rowSetProps.maxRows != null)
+ {
+ rowSetProp.setPropertyValue("MaxRows", rowSetProps.maxRows);
+ }
+
+ final XConnectionTools tools = UnoRuntime.queryInterface(XConnectionTools.class, connection);
+ fillOrderStatement(rowSetProps.command, rowSetProps.commandType, parameters, tools, rowSetProp);
+ final ParameterDefinition paramDef = createParameter(parameters, tools, rowSetProps, rowSet);
+
+ rowSetProperties.put(rowSetProps, rowSet);
+ parameterMap.put(rowSetProps, paramDef);
+
+ return new Object[]
+ {
+ rowSet, paramDef
+ };
+ }
+
+ private ParameterDefinition createParameter(final Map parameters,
+ final XConnectionTools tools,
+ RowSetProperties rowSetProps, final XRowSet rowSet)
+ throws SQLException,
+ UnknownPropertyException,
+ PropertyVetoException,
+ IllegalArgumentException,
+ WrappedTargetException
+ {
+ final ParameterDefinition paramDef = new ParameterDefinition();
+ final XSingleSelectQueryComposer composer = getComposer(tools, rowSetProps.command, rowSetProps.commandType);
+ if (composer != null)
+ {
+ final XPropertySet rowSetProp = UnoRuntime.queryInterface(XPropertySet.class, rowSet);
+ if ((Boolean) rowSetProp.getPropertyValue(APPLY_FILTER))
+ {
+ composer.setFilter((String) rowSetProp.getPropertyValue("Filter"));
+ }
+ // get old parameter count
+ final ArrayList<?> detailColumns = (ArrayList<?>) parameters.get(DETAIL_COLUMNS);
+ final ArrayList<String> handledColumns = new ArrayList<String>();
+ final XParametersSupplier paraSup = UnoRuntime.queryInterface(XParametersSupplier.class, composer);
+ if (paraSup != null)
+ {
+ final XIndexAccess params = paraSup.getParameters();
+ if (params != null)
+ {
+ final int oldParameterCount = params.getCount();
+ paramDef.parameterCount = oldParameterCount;
+ if (detailColumns != null)
+ {
+ for (int i = 0; i < oldParameterCount; i++)
+ {
+ try
+ {
+ final XPropertySet parameter = UnoRuntime.queryInterface(XPropertySet.class, params.getByIndex(i));
+ if (parameter != null)
+ {
+ final String name = (String) parameter.getPropertyValue("Name");
+ for (int j = 0; j < detailColumns.size(); j++)
+ {
+ if (name.equals(detailColumns.get(j)))
+ {
+ handledColumns.add(name);
+ paramDef.parameterIndex.add(i);
+ --paramDef.parameterCount;
+ break;
+ }
+ }
+ }
+ }
+ catch (IndexOutOfBoundsException ex)
+ {
+ Logger.getLogger(SDBCReportDataFactory.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+ }
+ }
+ final ArrayList<?> masterValues = (ArrayList<?>) parameters.get(MASTER_VALUES);
+ if (masterValues != null && !masterValues.isEmpty() && paramDef.parameterIndex.size() != detailColumns.size())
+ {
+ // create the new filter
+ final String quote = connection.getMetaData().getIdentifierQuoteString();
+ final StringBuffer oldFilter = new StringBuffer();
+ oldFilter.append(composer.getFilter());
+ if (oldFilter.length() != 0)
+ {
+ oldFilter.append(" AND ");
+ }
+ int newParamterCounter = 1;
+ for (final Iterator it = detailColumns.iterator(); it.hasNext();
+ ++newParamterCounter)
+ {
+ final String detail = (String) it.next();
+ if (!handledColumns.contains(detail))
+ {
+ oldFilter.append(quote);
+ oldFilter.append(detail);
+ oldFilter.append(quote);
+ oldFilter.append(" = :link_");
+ oldFilter.append(newParamterCounter);
+ if (it.hasNext())
+ {
+ oldFilter.append(" AND ");
+ }
+ paramDef.parameterIndex.add(newParamterCounter + paramDef.parameterCount - 1);
+ }
+ }
+
+ composer.setFilter(oldFilter.toString());
+
+ final String sQuery = composer.getQuery();
+ rowSetProp.setPropertyValue(UNO_COMMAND, sQuery);
+ rowSetProp.setPropertyValue(UNO_COMMAND_TYPE, Integer.valueOf(CommandType.COMMAND));
+ }
+ }
+ return paramDef;
+ }
+
+ private void fillOrderStatement(final String command,
+ final int commandType, final Map parameters,
+ final XConnectionTools tools,
+ final XPropertySet rowSetProp)
+ throws SQLException,
+ UnknownPropertyException,
+ PropertyVetoException,
+ IllegalArgumentException,
+ WrappedTargetException,
+ NoSuchElementException
+ {
+ final StringBuffer order = new StringBuffer(getOrderStatement((ArrayList<?>) parameters.get(SORT_EXPRESSIONS)));
+ if (order.length() > 0 && commandType != CommandType.TABLE)
+ {
+ String statement = command;
+ final XSingleSelectQueryComposer composer = getComposer(tools, command, commandType);
+ if (composer != null)
+ {
+ statement = composer.getQuery();
+ composer.setQuery(statement);
+ final String sOldOrder = composer.getOrder();
+ if (sOldOrder.length() > 0)
+ {
+ order.append(',');
+ order.append(sOldOrder);
+ composer.setOrder("");
+ statement = composer.getQuery();
+ }
+ }
+ else
+ {
+ if (commandType == CommandType.QUERY)
+ {
+ final XQueriesSupplier xSupplyQueries = UnoRuntime.queryInterface(XQueriesSupplier.class, connection);
+ final XNameAccess queries = xSupplyQueries.getQueries();
+ if (queries.hasByName(command))
+ {
+ final XPropertySet prop = UnoRuntime.queryInterface(XPropertySet.class, queries.getByName(command));
+ final Boolean escape = (Boolean) prop.getPropertyValue(ESCAPEPROCESSING);
+ rowSetProp.setPropertyValue(ESCAPEPROCESSING, escape);
+ final String queryCommand = (String) prop.getPropertyValue(UNO_COMMAND);
+ statement = "SELECT * FROM (" + queryCommand + ") \"__LibreOffice_report_result\"";
+ }
+
+ }
+ else
+ {
+ statement = "SELECT * FROM (" + command + ") \"__LibreOffice_report_result\"";
+ }
+ }
+ rowSetProp.setPropertyValue(UNO_COMMAND, statement);
+ rowSetProp.setPropertyValue(UNO_COMMAND_TYPE, Integer.valueOf(CommandType.COMMAND));
+ }
+ rowSetProp.setPropertyValue("Order", order.toString());
+ }
+}
+
diff --git a/reportbuilder/java/org/libreoffice/report/SOImageService.java b/reportbuilder/java/org/libreoffice/report/SOImageService.java
new file mode 100644
index 000000000..f472d284d
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/SOImageService.java
@@ -0,0 +1,162 @@
+/*
+ * 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;
+
+import com.sun.star.awt.Size;
+import com.sun.star.beans.PropertyValue;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.beans.XPropertySetInfo;
+import com.sun.star.graphic.XGraphicProvider;
+import com.sun.star.io.IOException;
+import com.sun.star.io.XInputStream;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XMultiComponentFactory;
+import com.sun.star.lib.uno.adapter.ByteArrayToXInputStreamAdapter;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+
+public class SOImageService implements ImageService
+{
+
+ private final XGraphicProvider m_xGraphicProvider;
+
+ /**
+ * Creates a new instance of SOImageService
+ */
+ public SOImageService(final XComponentContext xCompContext)
+ throws ReportExecutionException, com.sun.star.uno.Exception
+ {
+ if (xCompContext == null)
+ {
+ throw new ReportExecutionException("SOImageService constructed with null Component Context");
+ }
+
+
+ final XMultiComponentFactory xMCF = xCompContext.getServiceManager();
+ m_xGraphicProvider = UnoRuntime.queryInterface(XGraphicProvider.class,
+ xMCF.createInstanceWithContext("com.sun.star.graphic.GraphicProvider", xCompContext));
+
+ if (m_xGraphicProvider == null)
+ {
+ throw new ReportExecutionException("There is no graphic-provider available for SOImageService.");
+ }
+ }
+
+ private Size getImageSize(final XInputStream image) throws ReportExecutionException
+ {
+ final Size dim = new Size();
+ try
+ {
+ final PropertyValue[] value = new PropertyValue[]
+ {
+ new PropertyValue()
+ };
+ value[0].Name = "InputStream";
+ value[0].Value = image;
+
+ final XPropertySet xImage = UnoRuntime.queryInterface(XPropertySet.class,
+ m_xGraphicProvider.queryGraphic(value));
+
+ if (xImage != null)
+ {
+ final XPropertySetInfo xInfo = xImage.getPropertySetInfo();
+ if (xInfo.hasPropertyByName("Size100thMM"))
+ {
+ Size imageSize = (Size) xImage.getPropertyValue("Size100thMM");
+ dim.Width = imageSize.Width;
+ dim.Height = imageSize.Height;
+ if (dim.Height == 0 && dim.Width == 0)
+ {
+ imageSize = (Size) xImage.getPropertyValue("SizePixel");
+ final int dpi = java.awt.Toolkit.getDefaultToolkit().getScreenResolution();
+ final double fac = 2540 / (double) dpi;
+ dim.Width = (int) (imageSize.Width * fac);
+ dim.Height = (int) (imageSize.Height * fac);
+ }
+ }
+ else if (xInfo.hasPropertyByName("SizePixel"))
+ {
+ final Size imageSize = (Size) xImage.getPropertyValue("SizePixel");
+ final int dpi = java.awt.Toolkit.getDefaultToolkit().getScreenResolution();
+ final double fac = 2540.0 / dpi;
+ dim.Width = (int) (imageSize.Width * fac);
+ dim.Height = (int) (imageSize.Height * fac);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new ReportExecutionException("Failed to query Image-Size", ex);
+ }
+ return dim;
+ }
+
+ public Size getImageSize(final byte[] image) throws ReportExecutionException
+ {
+ return getImageSize(new ByteArrayToXInputStreamAdapter(image));
+ }
+
+ private String getMimeType(final XInputStream image) throws ReportExecutionException
+ {
+ try
+ {
+ final PropertyValue[] value = new PropertyValue[]
+ {
+ new PropertyValue()
+ };
+ value[0].Name = "InputStream";
+ value[0].Value = image;
+
+ final XPropertySet xImage = UnoRuntime.queryInterface(XPropertySet.class,
+ m_xGraphicProvider.queryGraphic(value));
+
+ if (xImage != null)
+ {
+ final XPropertySetInfo xInfo = xImage.getPropertySetInfo();
+ if (xInfo.hasPropertyByName("MimeType"))
+ {
+ return (String) xImage.getPropertyValue("MimeType");
+ }
+ }
+ }
+ catch (UnknownPropertyException ex)
+ {
+ throw new ReportExecutionException(ex);
+ }
+ catch (WrappedTargetException ex)
+ {
+ throw new ReportExecutionException(ex);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException ex)
+ {
+ throw new ReportExecutionException(ex);
+ }
+ catch (IOException ex)
+ {
+ throw new ReportExecutionException(ex);
+ }
+ return null;
+ }
+
+ public String getMimeType(final byte[] image) throws ReportExecutionException
+ {
+ return getMimeType(new ByteArrayToXInputStreamAdapter(image));
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/StorageRepository.java b/reportbuilder/java/org/libreoffice/report/StorageRepository.java
new file mode 100644
index 000000000..a338ee5de
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/StorageRepository.java
@@ -0,0 +1,330 @@
+/*
+ * 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;
+
+import com.sun.star.beans.PropertyVetoException;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.container.NoSuchElementException;
+import com.sun.star.embed.ElementModes;
+import com.sun.star.embed.InvalidStorageException;
+import com.sun.star.embed.XStorage;
+import com.sun.star.embed.XTransactedObject;
+import com.sun.star.io.XStream;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lib.uno.adapter.XInputStreamToInputStreamAdapter;
+import com.sun.star.lib.uno.adapter.XOutputStreamToOutputStreamAdapter;
+import com.sun.star.uno.UnoRuntime;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.logging.Logger;
+
+/**
+ * A directory holds all the contents here.
+ *
+ *
+ */
+public class StorageRepository implements InputRepository, OutputRepository
+{
+
+ private static final Logger LOGGER = Logger.getLogger(StorageRepository.class.getName());
+ private static final String REPORT_PROCESSING_FAILED = "ReportProcessing failed: ";
+ private XStorage input;
+ private XStorage output;
+ private final String rootURL;
+
+ public StorageRepository(final XStorage input, final XStorage output, final String rootURL)
+ {
+ this.input = input;
+ this.output = output;
+ this.rootURL = rootURL;
+
+ }
+
+ private StorageRepository(final XStorage storage, final boolean isOutput, final String rootURL)
+ {
+ this.rootURL = rootURL;
+ if (isOutput)
+ {
+ this.output = storage;
+ }
+ else
+ {
+ this.input = storage;
+ }
+ }
+
+ public InputStream createInputStream(final String name) throws IOException
+ {
+ if (input == null)
+ {
+ throw new IOException("input is NULL");
+ }
+ try
+ {
+ final XStream xStream = UnoRuntime.queryInterface(XStream.class, input.openStreamElement(name, ElementModes.READ));
+ return new BufferedInputStream(new XInputStreamToInputStreamAdapter(xStream.getInputStream()), 102400);
+ }
+ catch (com.sun.star.uno.Exception ex1)
+ {
+ java.io.IOException ex2 = new java.io.IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ /**
+ * Creates an output stream for writing the data. If there is an entry with
+ * that name already contained in the repository, try to overwrite it.
+ *
+ * @throws IOException if opening the stream fails
+ */
+ public OutputStream createOutputStream(final String name, final String mimeType) throws IOException
+ {
+ if (output == null)
+ {
+ throw new IOException("output is NULL");
+ }
+ try
+ {
+ final XStream stream = output.openStreamElement(name, ElementModes.WRITE | ElementModes.TRUNCATE);
+ stream.getInputStream().closeInput();
+ if (mimeType != null)
+ {
+ final XPropertySet prop = UnoRuntime.queryInterface(XPropertySet.class, stream);
+ prop.setPropertyValue("MediaType", mimeType);
+ }
+ return new BufferedOutputStream(new XOutputStreamToOutputStreamAdapter(stream.getOutputStream()), 204800);
+ }
+ catch (com.sun.star.uno.Exception ex1)
+ {
+ java.io.IOException ex2 = new java.io.IOException();
+ ex2.initCause(ex1);
+ throw ex2;
+ }
+ }
+
+ public boolean exists(final String name)
+ {
+ try
+ {
+ return output.isStreamElement(name);
+ }
+ catch (InvalidStorageException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (NoSuchElementException e)
+ {
+ // We expect this exception, no need to log it.
+ }
+ return false;
+ }
+
+ public Object getId()
+ {
+ return "1";
+ }
+
+ public long getVersion(final String name)
+ {
+ return 1;
+ }
+
+ public boolean isReadable(final String name)
+ {
+ try
+ {
+ if (input != null)
+ {
+ return input.isStreamElement(name);
+ }
+ }
+ catch (InvalidStorageException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (NoSuchElementException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ return false;
+ }
+
+ public InputRepository openInputRepository(final String name) throws IOException
+ {
+ try
+ {
+ final String temp = shortenName(name);
+ if (!input.isStorageElement(temp))
+ {
+ throw new IOException();
+ }
+ final XStorage storage = UnoRuntime.queryInterface(XStorage.class, input.openStorageElement(temp, ElementModes.READ));
+ return new StorageRepository(storage, false, rootURL);
+ }
+ catch (NoSuchElementException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (WrappedTargetException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (InvalidStorageException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (com.sun.star.io.IOException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ throw new IOException();
+ }
+
+ private final String shortenName(final String name)
+ {
+ final String temp;
+ if (name.startsWith("./"))
+ {
+ temp = name.substring(2);
+ }
+ else
+ {
+ temp = name;
+ }
+ return temp;
+ }
+
+ public OutputRepository openOutputRepository(final String name, final String mimeType) throws IOException
+ {
+ try
+ {
+ final String temp = shortenName(name);
+ final XStorage storage = UnoRuntime.queryInterface(XStorage.class, output.openStorageElement(temp, ElementModes.WRITE));
+ if (mimeType != null)
+ {
+ final XPropertySet prop = UnoRuntime.queryInterface(XPropertySet.class, storage);
+ prop.setPropertyValue("MediaType", mimeType);
+ }
+ return new StorageRepository(storage, true, rootURL);
+ }
+ catch (UnknownPropertyException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (PropertyVetoException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (IllegalArgumentException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (WrappedTargetException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (InvalidStorageException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (com.sun.star.io.IOException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+
+ throw new IOException();
+ }
+
+ public void closeInputRepository()
+ {
+ if (input != null)
+ {
+ input.dispose();
+ }
+ }
+
+ public void closeOutputRepository()
+ {
+ if (output != null)
+ {
+ try
+ {
+ final XTransactedObject obj = UnoRuntime.queryInterface(XTransactedObject.class, output);
+ if (obj != null)
+ {
+ obj.commit();
+ }
+ }
+ catch (com.sun.star.io.IOException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (WrappedTargetException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ output.dispose();
+ }
+
+ }
+
+ public boolean existsStorage(final String name)
+ {
+ try
+ {
+ return output.isStorageElement(name);
+ }
+ catch (InvalidStorageException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (com.sun.star.lang.IllegalArgumentException ex)
+ {
+ LOGGER.severe(REPORT_PROCESSING_FAILED + ex);
+ }
+ catch (NoSuchElementException ex)
+ {
+ // We expect this exception, no need to log it.
+ }
+ return false;
+ }
+
+ public String getRootURL()
+ {
+ return rootURL;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/Author-Function.properties b/reportbuilder/java/org/libreoffice/report/function/metadata/Author-Function.properties
new file mode 100644
index 000000000..a05ce8dad
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/Author-Function.properties
@@ -0,0 +1,21 @@
+#
+# 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 .
+#
+# x-no-translate
+
+display-name=AUTHOR
+description=Returns the author of the report.
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/Author-Function_en_US.properties b/reportbuilder/java/org/libreoffice/report/function/metadata/Author-Function_en_US.properties
new file mode 100644
index 000000000..a05ce8dad
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/Author-Function_en_US.properties
@@ -0,0 +1,21 @@
+#
+# 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 .
+#
+# x-no-translate
+
+display-name=AUTHOR
+description=Returns the author of the report.
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/AuthorFunction.java b/reportbuilder/java/org/libreoffice/report/function/metadata/AuthorFunction.java
new file mode 100644
index 000000000..dcd30e5f0
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/AuthorFunction.java
@@ -0,0 +1,48 @@
+/*
+ * 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.function.metadata;
+
+import org.libreoffice.report.ReportEngineParameterNames;
+
+import org.pentaho.reporting.libraries.formula.EvaluationException;
+import org.pentaho.reporting.libraries.formula.FormulaContext;
+import org.pentaho.reporting.libraries.formula.LibFormulaErrorValue;
+import org.pentaho.reporting.libraries.formula.function.Function;
+import org.pentaho.reporting.libraries.formula.function.ParameterCallback;
+import org.pentaho.reporting.libraries.formula.lvalues.TypeValuePair;
+import org.pentaho.reporting.libraries.formula.typing.coretypes.TextType;
+
+public class AuthorFunction implements Function
+{
+
+ public String getCanonicalName()
+ {
+ return "AUTHOR";
+ }
+
+ public TypeValuePair evaluate(final FormulaContext context, final ParameterCallback parameters)
+ throws EvaluationException
+ {
+ if (parameters.getParameterCount() != 0)
+ {
+ throw new EvaluationException(LibFormulaErrorValue.ERROR_ARGUMENTS_VALUE);
+ }
+
+ return new TypeValuePair(TextType.TYPE, context.getConfiguration().getConfigProperty(ReportEngineParameterNames.AUTHOR));
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/AuthorFunctionDescription.java b/reportbuilder/java/org/libreoffice/report/function/metadata/AuthorFunctionDescription.java
new file mode 100644
index 000000000..b4cf6e22f
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/AuthorFunctionDescription.java
@@ -0,0 +1,57 @@
+/*
+ * 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.function.metadata;
+
+import org.pentaho.reporting.libraries.formula.function.AbstractFunctionDescription;
+import org.pentaho.reporting.libraries.formula.function.FunctionCategory;
+import org.pentaho.reporting.libraries.formula.typing.Type;
+import org.pentaho.reporting.libraries.formula.typing.coretypes.TextType;
+
+public class AuthorFunctionDescription extends AbstractFunctionDescription
+{
+
+ public AuthorFunctionDescription()
+ {
+ super("AUTHOR", "org.libreoffice.report.function.metadata.Author-Function");
+ }
+
+ public FunctionCategory getCategory()
+ {
+ return MetaDataFunctionCategory.CATEGORY;
+ }
+
+ public int getParameterCount()
+ {
+ return 0;
+ }
+
+ public Type getParameterType(final int position)
+ {
+ return null;
+ }
+
+ public Type getValueType()
+ {
+ return TextType.TYPE;
+ }
+
+ public boolean isParameterMandatory(final int position)
+ {
+ return false;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/MetaDataFunctionCategory.java b/reportbuilder/java/org/libreoffice/report/function/metadata/MetaDataFunctionCategory.java
new file mode 100644
index 000000000..3b6ac8a29
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/MetaDataFunctionCategory.java
@@ -0,0 +1,33 @@
+/*
+ * 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.function.metadata;
+
+import org.pentaho.reporting.libraries.formula.function.AbstractFunctionCategory;
+import org.pentaho.reporting.libraries.formula.function.FunctionCategory;
+
+public class MetaDataFunctionCategory extends AbstractFunctionCategory
+{
+
+ public static final FunctionCategory CATEGORY = new MetaDataFunctionCategory();
+
+ private MetaDataFunctionCategory()
+ {
+ super("org.libreoffice.report.function.metadata.category");
+ }
+}
+
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/Title-Function.properties b/reportbuilder/java/org/libreoffice/report/function/metadata/Title-Function.properties
new file mode 100644
index 000000000..3c0039f6c
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/Title-Function.properties
@@ -0,0 +1,21 @@
+#
+# 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 .
+#
+# x-no-translate
+
+display-name=TITLE
+description=Returns the title of the report.
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/Title-Function_en_US.properties b/reportbuilder/java/org/libreoffice/report/function/metadata/Title-Function_en_US.properties
new file mode 100644
index 000000000..3c0039f6c
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/Title-Function_en_US.properties
@@ -0,0 +1,21 @@
+#
+# 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 .
+#
+# x-no-translate
+
+display-name=TITLE
+description=Returns the title of the report.
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/TitleFunction.java b/reportbuilder/java/org/libreoffice/report/function/metadata/TitleFunction.java
new file mode 100644
index 000000000..c4cd953ba
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/TitleFunction.java
@@ -0,0 +1,48 @@
+/*
+ * 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.function.metadata;
+
+import org.libreoffice.report.ReportEngineParameterNames;
+
+import org.pentaho.reporting.libraries.formula.EvaluationException;
+import org.pentaho.reporting.libraries.formula.FormulaContext;
+import org.pentaho.reporting.libraries.formula.LibFormulaErrorValue;
+import org.pentaho.reporting.libraries.formula.function.Function;
+import org.pentaho.reporting.libraries.formula.function.ParameterCallback;
+import org.pentaho.reporting.libraries.formula.lvalues.TypeValuePair;
+import org.pentaho.reporting.libraries.formula.typing.coretypes.TextType;
+
+public class TitleFunction implements Function
+{
+
+ public String getCanonicalName()
+ {
+ return "TITLE";
+ }
+
+ public TypeValuePair evaluate(final FormulaContext context, final ParameterCallback parameters)
+ throws EvaluationException
+ {
+ if (parameters.getParameterCount() != 0)
+ {
+ throw new EvaluationException(LibFormulaErrorValue.ERROR_ARGUMENTS_VALUE);
+ }
+
+ return new TypeValuePair(TextType.TYPE, context.getConfiguration().getConfigProperty(ReportEngineParameterNames.TITLE));
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/TitleFunctionDescription.java b/reportbuilder/java/org/libreoffice/report/function/metadata/TitleFunctionDescription.java
new file mode 100644
index 000000000..30d3d337b
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/TitleFunctionDescription.java
@@ -0,0 +1,57 @@
+/*
+ * 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.function.metadata;
+
+import org.pentaho.reporting.libraries.formula.function.AbstractFunctionDescription;
+import org.pentaho.reporting.libraries.formula.function.FunctionCategory;
+import org.pentaho.reporting.libraries.formula.typing.Type;
+import org.pentaho.reporting.libraries.formula.typing.coretypes.TextType;
+
+public class TitleFunctionDescription extends AbstractFunctionDescription
+{
+
+ public TitleFunctionDescription()
+ {
+ super("TITLE", "org.libreoffice.report.function.metadata.Title-Function");
+ }
+
+ public FunctionCategory getCategory()
+ {
+ return MetaDataFunctionCategory.CATEGORY;
+ }
+
+ public int getParameterCount()
+ {
+ return 0;
+ }
+
+ public Type getParameterType(final int position)
+ {
+ return null;
+ }
+
+ public Type getValueType()
+ {
+ return TextType.TYPE;
+ }
+
+ public boolean isParameterMandatory(final int position)
+ {
+ return false;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/category.properties b/reportbuilder/java/org/libreoffice/report/function/metadata/category.properties
new file mode 100644
index 000000000..39f24f271
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/category.properties
@@ -0,0 +1,21 @@
+#
+# 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 .
+#
+# x-no-translate
+
+display-name=Document Information
+description=Contains functions to access document information.
diff --git a/reportbuilder/java/org/libreoffice/report/function/metadata/category_en_US.properties b/reportbuilder/java/org/libreoffice/report/function/metadata/category_en_US.properties
new file mode 100644
index 000000000..76ea0bb4d
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/function/metadata/category_en_US.properties
@@ -0,0 +1,21 @@
+#
+# 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 .
+#
+# x-no-translate
+
+display-name=MetaData
+description=Contains functions about meta data
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/DefaultNameGenerator.java b/reportbuilder/java/org/libreoffice/report/pentaho/DefaultNameGenerator.java
new file mode 100644
index 000000000..46f2a032a
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/DefaultNameGenerator.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+import org.libreoffice.report.OutputRepository;
+
+import java.io.IOException;
+
+
+public class DefaultNameGenerator
+{
+
+ private final OutputRepository outputRepository;
+
+ public DefaultNameGenerator(final OutputRepository outputRepository)
+ {
+ if (outputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ this.outputRepository = outputRepository;
+ }
+
+ public String generateName(final String namePrefix, final String mimeType)
+ throws IOException
+ {
+ return generateName(namePrefix, mimeType, true);
+ }
+
+ public String generateStorageName(final String namePrefix, final String mimeType)
+ throws IOException
+ {
+ return generateName(namePrefix, mimeType, false);
+ }
+
+ /**
+ * Generates a new, unique name for storing resources in the output repository. Assuming that proper synchronization
+ * has been applied, the generated name will be unique within that repository.
+ *
+ * @param namePrefix a user defined name for that resource.
+ * @param mimeType the mime type of the resource to be stored in the repository.
+ * @param isStream
+ * @return the generated, fully qualified name.
+ * @throws java.io.IOException
+ */
+ private String generateName(final String namePrefix, final String mimeType, final boolean isStream)
+ throws IOException
+ {
+ final String name;
+ if (namePrefix != null)
+ {
+ name = namePrefix;
+ }
+ else
+ {
+ name = "file";
+ }
+
+ StringBuffer firstFileName = new StringBuffer();
+ firstFileName.append(name);
+ final String suffix;
+ if (mimeType != null)
+ {
+ suffix = getSuffixForType(mimeType);
+ firstFileName.append('.');
+ firstFileName.append(suffix);
+ }
+ else
+ {
+ suffix = null;
+ }
+ String newName = firstFileName.toString();
+ boolean exists;
+ if (isStream)
+ {
+ exists = outputRepository.exists(newName);
+ }
+ else
+ {
+ exists = outputRepository.existsStorage(newName);
+ }
+ if (exists)
+ {
+ int counter = 0;
+ while (exists)
+ {
+ if (counter < 0) // wraparound should not happen...
+ {
+ throw new IOException();
+ }
+ firstFileName.delete(0, firstFileName.length());
+ firstFileName.append(name);
+ firstFileName.append(counter);
+ if (suffix != null)
+ {
+ firstFileName.append('.');
+ firstFileName.append(suffix);
+ }
+ newName = firstFileName.toString();
+ if (isStream)
+ {
+ exists = outputRepository.exists(newName);
+ }
+ else
+ {
+ exists = outputRepository.existsStorage(newName);
+ }
+ counter++;
+ }
+ }
+ return newName;
+ }
+
+ private String getSuffixForType(final String mimeType)
+ {
+ if ("image/png".equals(mimeType))
+ {
+ return "png";
+ }
+ if ("image/jpeg".equals(mimeType))
+ {
+ return "jpg";
+ }
+ if ("image/gif".equals(mimeType))
+ {
+ return "gif";
+ }
+
+ // todo ... use a flexible mapping ...
+ return "dat";
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/Manifest.mf b/reportbuilder/java/org/libreoffice/report/pentaho/Manifest.mf
new file mode 100644
index 000000000..2a56b2fbb
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/Manifest.mf
@@ -0,0 +1,7 @@
+RegistrationClassName: org.libreoffice.report.pentaho.SOReportJobFactory
+Class-Path: reportbuilderwizard.jar
+ flute-1.1.6.jar libserializer-1.1.6.jar libbase-1.1.6.jar
+ libfonts-1.1.6.jar libformula-1.1.7.jar liblayout.jar
+ libloader-1.1.6.jar librepository-1.1.6.jar libxml-1.1.7.jar
+ flow-engine.jar sac.jar
+UNO-Type-Path:
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/OfficeNamespaces.java b/reportbuilder/java/org/libreoffice/report/pentaho/OfficeNamespaces.java
new file mode 100644
index 000000000..6a7d14486
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/OfficeNamespaces.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+/**
+ * Creation-Date: Feb 22, 2007, 1:53:29 PM
+ *
+ */
+public class OfficeNamespaces
+{
+
+ public static final String OFFICE_NS = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
+ public static final String TABLE_NS = "urn:oasis:names:tc:opendocument:xmlns:table:1.0";
+ public static final String TEXT_NS = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
+ public static final String STYLE_NS = "urn:oasis:names:tc:opendocument:xmlns:style:1.0";
+ public static final String DRAWING_NS = "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0";
+ public static final String FO_NS = "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0";
+ public static final String XLINK_NS = "http://www.w3.org/1999/xlink";
+ public static final String PURL_NS = "http://purl.org/dc/elements/1.1/";
+ public static final String META_NS = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0";
+ public static final String DATASTYLE_NS = "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0";
+ public static final String SVG_NS = "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0";
+ public static final String CHART_NS = "urn:oasis:names:tc:opendocument:xmlns:chart:1.0";
+ public static final String CHARTOOO_NS = "http://openoffice.org/2010/chart";
+ public static final String DR3D_NS = "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0";
+ public static final String MATHML_NS = "http://www.w3.org/1998/Math/MathML";
+ public static final String FORM_NS = "urn:oasis:names:tc:opendocument:xmlns:form:1.0";
+ public static final String SCRIPT_NS = "urn:oasis:names:tc:opendocument:xmlns:script:1.0";
+ public static final String OO2004_NS = "http://openoffice.org/2004/office";
+ public static final String OOW2004_NS = "http://openoffice.org/2004/writer";
+ public static final String OOC2004_NS = "http://openoffice.org/2004/calc";
+ public static final String XML_EVENT_NS = "http://www.w3.org/2001/xml-events";
+ public static final String XFORMS_NS = "http://www.w3.org/2002/xforms";
+ public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema";
+ public static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
+ public static final String OOREPORT_NS = "http://openoffice.org/2005/report";
+ public static final String GRDDL_NS = "http://www.w3.org/2003/g/data-view#";
+ public static final String CONFIG = "urn:oasis:names:tc:opendocument:xmlns:config:1.0";
+ public static final String LOEXT_NS = "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0";
+
+
+ private OfficeNamespaces()
+ {
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/PentahoFormulaContext.java b/reportbuilder/java/org/libreoffice/report/pentaho/PentahoFormulaContext.java
new file mode 100644
index 000000000..ced17741c
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/PentahoFormulaContext.java
@@ -0,0 +1,84 @@
+/*
+ * 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;
+
+import org.pentaho.reporting.libraries.base.config.Configuration;
+import org.pentaho.reporting.libraries.formula.ContextEvaluationException;
+import org.pentaho.reporting.libraries.formula.FormulaContext;
+import org.pentaho.reporting.libraries.formula.LocalizationContext;
+import org.pentaho.reporting.libraries.formula.function.FunctionRegistry;
+import org.pentaho.reporting.libraries.formula.operators.OperatorFactory;
+import org.pentaho.reporting.libraries.formula.typing.Type;
+import org.pentaho.reporting.libraries.formula.typing.TypeRegistry;
+
+public class PentahoFormulaContext implements FormulaContext
+{
+
+ final private FormulaContext backend;
+ final private Configuration config;
+
+ public PentahoFormulaContext(final FormulaContext backend, final Configuration _config)
+ {
+ this.backend = backend;
+ config = _config;
+ }
+
+ public LocalizationContext getLocalizationContext()
+ {
+ return backend.getLocalizationContext();
+ }
+
+ public Configuration getConfiguration()
+ {
+ return config;
+ }
+
+ public FunctionRegistry getFunctionRegistry()
+ {
+ return backend.getFunctionRegistry();
+ }
+
+ public TypeRegistry getTypeRegistry()
+ {
+ return backend.getTypeRegistry();
+ }
+
+ public OperatorFactory getOperatorFactory()
+ {
+ return backend.getOperatorFactory();
+ }
+
+ public Type resolveReferenceType(final Object name) throws ContextEvaluationException
+ {
+ return backend.resolveReferenceType(name);
+ }
+
+ public Object resolveReference(final Object name) throws ContextEvaluationException
+ {
+ if (name == null)
+ {
+ throw new NullPointerException();
+ }
+ return backend.resolveReference(name);
+ }
+
+ public boolean isReferenceDirty(final Object name) throws ContextEvaluationException
+ {
+ return backend.isReferenceDirty(name);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportEngine.java b/reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportEngine.java
new file mode 100644
index 000000000..4f5aa81c4
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportEngine.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import org.libreoffice.report.JobDefinitionException;
+import org.libreoffice.report.ReportEngineMetaData;
+import org.libreoffice.report.ReportJob;
+import org.libreoffice.report.ReportJobDefinition;
+import org.libreoffice.report.util.DefaultReportJobDefinition;
+import org.jfree.report.JFreeReportBoot;
+
+public class PentahoReportEngine
+{
+
+ private final ReportEngineMetaData metaData;
+
+ public PentahoReportEngine()
+ {
+ JFreeReportBoot.getInstance().start();
+ this.metaData = new PentahoReportEngineMetaData();
+ }
+
+ public ReportJobDefinition createJobDefinition()
+ {
+ return new DefaultReportJobDefinition(metaData);
+ }
+
+ /**
+ * Open points: How to define scheduling?
+ *
+ * @return the report job definition for the job description.
+ */
+ public ReportJob createJob(final ReportJobDefinition definition)
+ throws JobDefinitionException
+ {
+ return new PentahoReportJob(definition);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportEngineMetaData.java b/reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportEngineMetaData.java
new file mode 100644
index 000000000..ef71cb3c1
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportEngineMetaData.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.ReportEngineMetaData;
+import org.libreoffice.report.ReportEngineParameterNames;
+import org.libreoffice.report.ReportJobFactory;
+
+
+public class PentahoReportEngineMetaData
+ implements ReportEngineMetaData
+{
+
+ public static final String OPENDOCUMENT_TEXT = "application/vnd.oasis.opendocument.text";
+ public static final String OPENDOCUMENT_SPREADSHEET = "application/vnd.oasis.opendocument.spreadsheet";
+ public static final String OPENDOCUMENT_CHART = "application/vnd.oasis.opendocument.chart";
+ public static final String DEBUG = "raw/text+xml";
+ private final Map<String,Class<?>> parameterTypes;
+
+ public PentahoReportEngineMetaData()
+ {
+ parameterTypes = new HashMap<String,Class<?>>();
+ parameterTypes.put(ReportEngineParameterNames.CONTENT_TYPE, String.class);
+ parameterTypes.put(ReportEngineParameterNames.INPUT_NAME, String.class);
+ parameterTypes.put(ReportEngineParameterNames.OUTPUT_NAME, String.class);
+ parameterTypes.put(ReportEngineParameterNames.INPUT_REPOSITORY, InputRepository.class);
+ parameterTypes.put(ReportEngineParameterNames.OUTPUT_REPOSITORY, OutputRepository.class);
+ parameterTypes.put(ReportEngineParameterNames.INPUT_DATASOURCE_FACTORY, DataSourceFactory.class);
+ parameterTypes.put(ReportEngineParameterNames.IMAGE_SERVICE, ImageService.class);
+ parameterTypes.put(ReportEngineParameterNames.INPUT_REPORTJOB_FACTORY, ReportJobFactory.class);
+ parameterTypes.put(ReportEngineParameterNames.INPUT_MASTER_COLUMNS, List.class);
+ parameterTypes.put(ReportEngineParameterNames.INPUT_MASTER_VALUES, List.class);
+ parameterTypes.put(ReportEngineParameterNames.INPUT_DETAIL_COLUMNS, List.class);
+ parameterTypes.put(ReportEngineParameterNames.AUTHOR, String.class);
+ parameterTypes.put(ReportEngineParameterNames.TITLE, String.class);
+ parameterTypes.put(ReportEngineParameterNames.MAXROWS, Integer.class);
+ }
+
+ public Class getParameterType(final String parameter)
+ {
+ return parameterTypes.get(parameter);
+ }
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportJob.java b/reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportJob.java
new file mode 100644
index 000000000..efb4261ce
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/PentahoReportJob.java
@@ -0,0 +1,381 @@
+/*
+ * 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;
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.JobDefinitionException;
+import org.libreoffice.report.JobProperties;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.ParameterMap;
+import org.libreoffice.report.ReportEngineParameterNames;
+import org.libreoffice.report.ReportExecutionException;
+import org.libreoffice.report.ReportJob;
+import org.libreoffice.report.ReportJobDefinition;
+import org.libreoffice.report.SDBCReportDataFactory;
+import org.libreoffice.report.pentaho.loader.InputRepositoryLoader;
+import org.libreoffice.report.pentaho.model.OfficeDetailSection;
+import org.libreoffice.report.pentaho.model.OfficeDocument;
+import org.libreoffice.report.pentaho.model.OfficeGroup;
+import org.libreoffice.report.pentaho.model.OfficeReport;
+import org.libreoffice.report.pentaho.output.chart.ChartRawReportProcessor;
+import org.libreoffice.report.pentaho.output.spreadsheet.SpreadsheetRawReportProcessor;
+import org.libreoffice.report.pentaho.output.text.TextRawReportProcessor;
+
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.jfree.report.expressions.Expression;
+import org.jfree.report.expressions.FormulaExpression;
+import org.jfree.report.flow.DefaultReportJob;
+import org.jfree.report.flow.ReportProcessor;
+import org.jfree.report.flow.raw.XmlPrintReportProcessor;
+import org.jfree.report.structure.Node;
+import org.jfree.report.structure.Section;
+import org.jfree.report.util.ReportParameters;
+
+import org.pentaho.reporting.libraries.formula.lvalues.ContextLookup;
+import org.pentaho.reporting.libraries.formula.lvalues.FormulaFunction;
+import org.pentaho.reporting.libraries.formula.lvalues.LValue;
+import org.pentaho.reporting.libraries.formula.lvalues.Term;
+import org.pentaho.reporting.libraries.formula.parser.FormulaParser;
+import org.pentaho.reporting.libraries.formula.parser.ParseException;
+import org.pentaho.reporting.libraries.resourceloader.Resource;
+import org.pentaho.reporting.libraries.resourceloader.ResourceException;
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+
+
+/**
+ * ToDo: Allow interrupting of jobs and report the report progress
+ */
+public class PentahoReportJob implements ReportJob
+{
+
+ private static final Logger LOGGER = Logger.getLogger(PentahoReportJob.class.getName());
+ private final DataSourceFactory dataSourceFactory;
+ private final OutputRepository outputRepository;
+ private final JobProperties jobProperties;
+ private OfficeDocument report;
+ private final ResourceManager resourceManager;
+ private final String outputName;
+ private final ImageService imageService;
+ private final InputRepository inputRepository;
+ private final List masterValues;
+ private final List detailColumns;
+
+ public PentahoReportJob(final ReportJobDefinition definition)
+ throws JobDefinitionException
+ {
+ if (definition == null)
+ {
+ throw new NullPointerException();
+ }
+
+ this.jobProperties = definition.getProcessingParameters().copy();
+
+ this.dataSourceFactory = (DataSourceFactory) jobProperties.getProperty(ReportEngineParameterNames.INPUT_DATASOURCE_FACTORY);
+ if (this.dataSourceFactory == null)
+ {
+ throw new JobDefinitionException("DataSourceFactory must not be null.");
+ }
+
+ this.outputRepository = (OutputRepository) jobProperties.getProperty(ReportEngineParameterNames.OUTPUT_REPOSITORY);
+ if (this.outputRepository == null)
+ {
+ throw new JobDefinitionException("OutputRepository must not be null.");
+ }
+
+ this.inputRepository =
+ (InputRepository) jobProperties.getProperty(ReportEngineParameterNames.INPUT_REPOSITORY);
+ if (inputRepository == null)
+ {
+ throw new JobDefinitionException("InputRepository must not be null.");
+ }
+
+ this.outputName = (String) jobProperties.getProperty(ReportEngineParameterNames.OUTPUT_NAME);
+ if (outputName == null)
+ {
+ throw new JobDefinitionException("OutputName must not be null");
+ }
+
+ this.imageService = (ImageService) jobProperties.getProperty(ReportEngineParameterNames.IMAGE_SERVICE);
+ if (imageService == null)
+ {
+ throw new JobDefinitionException("A valid image-service implementation must be given.");
+ }
+
+ this.masterValues = (ArrayList<?>) jobProperties.getProperty(ReportEngineParameterNames.INPUT_MASTER_VALUES);
+ this.detailColumns = (ArrayList<?>) jobProperties.getProperty(ReportEngineParameterNames.INPUT_DETAIL_COLUMNS);
+
+ this.resourceManager = new ResourceManager();
+ this.resourceManager.registerDefaults();
+ this.resourceManager.registerLoader(new InputRepositoryLoader(inputRepository));
+
+ try
+ {
+ this.report = parseReport(definition);
+ }
+ catch (ResourceException e)
+ {
+ throw new JobDefinitionException("Failed to parse the report.", e);
+ }
+ }
+
+ private OfficeDocument parseReport(final ReportJobDefinition definition)
+ throws ResourceException, JobDefinitionException
+ {
+ final String reportResource = (String) this.jobProperties.getProperty(ReportEngineParameterNames.INPUT_NAME);
+ if (reportResource == null)
+ {
+ throw new JobDefinitionException("Report definition name must be given");
+ }
+
+ final Resource res = resourceManager.createDirectly("sun:oo://" + reportResource, OfficeDocument.class);
+ final OfficeDocument tempReport = (OfficeDocument) res.getResource();
+ tempReport.setDataFactory(new StarReportDataFactory(dataSourceFactory));
+ tempReport.setJobProperties(definition.getProcessingParameters().copy());
+ final ReportParameters inputParameters = tempReport.getInputParameters();
+
+ final ParameterMap queryParameters = definition.getQueryParameters();
+ final String[] paramKeys = queryParameters.keys();
+ for (int i = 0; i < paramKeys.length; i++)
+ {
+ final String key = paramKeys[i];
+ inputParameters.put(key, queryParameters.get(key));
+ }
+
+ return tempReport;
+ }
+
+ private void collectGroupExpressions(final Node[] nodes, final List<Object[]> expressions, final FormulaParser parser, final Expression reportFunctions[])
+ {
+ for (int i = 0; i < nodes.length; i++)
+ {
+ final Node node = nodes[i];
+ if (node instanceof OfficeGroup)
+ {
+ final OfficeGroup group = (OfficeGroup) node;
+ final FormulaExpression exp = (FormulaExpression) group.getGroupingExpression();
+ if (exp == null)
+ {
+ continue;
+ }
+
+ try
+ {
+ final String expression = exp.getFormulaExpression();
+ if (expression == null)
+ {
+ continue;
+ }
+ final FormulaFunction function = (FormulaFunction) parser.parse(expression);
+ final LValue[] parameters = function.getChildValues();
+ if (parameters.length > 0)
+ {
+ String name = parameters[0].toString();
+ if (parameters[0] instanceof ContextLookup)
+ {
+ final ContextLookup context = (ContextLookup) parameters[0];
+ name = context.getName();
+ }
+ for (int j = 0; j < reportFunctions.length; j++)
+ {
+ if (reportFunctions[j] instanceof FormulaExpression)
+ {
+ final FormulaExpression reportExp = (FormulaExpression) reportFunctions[j];
+
+ if (reportExp.getName().equals(name))
+ {
+ LValue val = parser.parse(reportExp.getFormulaExpression());
+ while( !(val instanceof ContextLookup))
+ {
+ if (val instanceof Term)
+ {
+ val = ((Term)val).getHeadValue();
+ }
+ else if (val instanceof FormulaFunction)
+ {
+ final FormulaFunction reportFunction = (FormulaFunction) val;
+ val = reportFunction.getChildValues()[0];
+ }
+ }
+ final ContextLookup context = (ContextLookup) val;
+ name = context.getName();
+ break;
+ }
+ }
+ }
+
+ final Object[] pair = new Object[2];
+ pair[0] = name;
+ pair[1] = group.getAttribute(OfficeNamespaces.OOREPORT_NS, "sort-ascending");
+ expressions.add(pair);
+ }
+ }
+ catch (ParseException ex)
+ {
+ LOGGER.severe("ReportProcessing failed: " + ex);
+ }
+ }
+ else if (node instanceof OfficeDetailSection)
+ {
+ return;
+ }
+ if (node instanceof Section)
+ {
+ final Section section = (Section) node;
+ collectGroupExpressions(section.getNodeArray(), expressions, parser, reportFunctions);
+ }
+ }
+ }
+
+ private void collectSortExpressions(final Node[] nodes, final List<Object[]> expressions, final FormulaParser parser, final Expression reportFunctions[])
+ {
+ for (int i = 0; i < nodes.length; i++)
+ {
+ final Node node = nodes[i];
+ if (node instanceof OfficeGroup)
+ {
+ final OfficeGroup group = (OfficeGroup) node;
+ final String exp = group.getSortingExpression();
+ if (exp == null)
+ {
+ continue;
+ }
+
+ final Object[] pair = new Object[2];
+ pair[0] = exp;
+ pair[1] = group.getAttribute(OfficeNamespaces.OOREPORT_NS, "sort-ascending");
+ expressions.add(pair);
+ }
+ else if (node instanceof OfficeDetailSection)
+ {
+ return;
+ }
+ if (node instanceof Section)
+ {
+ final Section section = (Section) node;
+ collectSortExpressions(section.getNodeArray(), expressions, parser, reportFunctions);
+ }
+ }
+ }
+
+ private void setMetaDataProperties(DefaultReportJob job)
+ {
+ job.getConfiguration().setConfigProperty(ReportEngineParameterNames.AUTHOR, (String) jobProperties.getProperty(ReportEngineParameterNames.AUTHOR));
+ job.getConfiguration().setConfigProperty(ReportEngineParameterNames.TITLE, (String) jobProperties.getProperty(ReportEngineParameterNames.TITLE));
+ }
+
+ /**
+ * Although we might want to run the job as soon as it has been created, sometimes it is
+ * wiser to let the user add some listeners first. If we execute at once, the user
+ * either has to deal with threading code or won't receive any progress information in
+ * single threaded environments.
+ */
+ public void execute()
+ throws ReportExecutionException, IOException
+ {
+ final DefaultReportJob job = new DefaultReportJob(report);
+ setMetaDataProperties(job);
+ final String contentType = (String) jobProperties.getProperty(ReportEngineParameterNames.CONTENT_TYPE);
+ //noinspection OverlyBroadCatchBlock
+ try
+ {
+ final ReportParameters parameters = job.getParameters();
+
+ if (masterValues != null && detailColumns != null)
+ {
+ parameters.put(SDBCReportDataFactory.MASTER_VALUES, masterValues);
+ parameters.put(SDBCReportDataFactory.DETAIL_COLUMNS, detailColumns);
+ }
+
+ final Node[] nodes = report.getNodeArray();
+
+ final FormulaParser parser = new FormulaParser();
+ final OfficeReport officeReport = (OfficeReport) ((Section) nodes[0]).getNode(0);
+ final Section reportBody = (Section) officeReport.getBodySection();
+ final ArrayList<Object[]> sortExpressions = new ArrayList<Object[]>();
+ collectSortExpressions(reportBody.getNodeArray(), sortExpressions, parser, officeReport.getExpressions());
+ parameters.put(SDBCReportDataFactory.SORT_EXPRESSIONS, sortExpressions);
+ final ArrayList<Object[]> groupExpressions = new ArrayList<Object[]>();
+ collectGroupExpressions(reportBody.getNodeArray(), groupExpressions, parser, officeReport.getExpressions());
+ parameters.put(SDBCReportDataFactory.GROUP_EXPRESSIONS, groupExpressions);
+ final String command = (String) officeReport.getAttribute(OfficeNamespaces.OOREPORT_NS, "command");
+ final String commandType = (String) officeReport.getAttribute(OfficeNamespaces.OOREPORT_NS, SDBCReportDataFactory.COMMAND_TYPE);
+ final String escapeProcessing = (String) officeReport.getAttribute(OfficeNamespaces.OOREPORT_NS, SDBCReportDataFactory.ESCAPE_PROCESSING);
+ report.setQuery(command);
+ parameters.put(SDBCReportDataFactory.COMMAND_TYPE, commandType);
+ parameters.put(SDBCReportDataFactory.ESCAPE_PROCESSING, !("false".equals(escapeProcessing)));
+
+ final String filter = (String) officeReport.getAttribute(OfficeNamespaces.OOREPORT_NS, "filter");
+ parameters.put(SDBCReportDataFactory.UNO_FILTER, filter);
+
+ parameters.put(ReportEngineParameterNames.MAXROWS, report.getJobProperties().getProperty(ReportEngineParameterNames.MAXROWS));
+
+ final long startTime = System.currentTimeMillis();
+ final ReportProcessor rp = getProcessorForContentType(contentType);
+ rp.processReport(job);
+ job.close();
+ final long endTime = System.currentTimeMillis();
+ LOGGER.config("Report processing time: " + (endTime - startTime));
+ }
+ catch (final Exception e)
+ {
+ String message = e.getMessage();
+ if (message == null || message.length() == 0)
+ {
+ message = "Failed to process the report";
+ }
+ throw new ReportExecutionException(message, e);
+ }
+
+ }
+
+ private ReportProcessor getProcessorForContentType(final String mimeType)
+ throws ReportExecutionException
+ {
+ final ReportProcessor ret;
+
+ if (PentahoReportEngineMetaData.OPENDOCUMENT_SPREADSHEET.equals(mimeType))
+ {
+ ret = new SpreadsheetRawReportProcessor(inputRepository, outputRepository, outputName, imageService, dataSourceFactory);
+ }
+ else if (PentahoReportEngineMetaData.OPENDOCUMENT_TEXT.equals(mimeType))
+ {
+ ret = new TextRawReportProcessor(inputRepository, outputRepository, outputName, imageService, dataSourceFactory);
+ }
+ else if (PentahoReportEngineMetaData.OPENDOCUMENT_CHART.equals(mimeType))
+ {
+ ret = new ChartRawReportProcessor(inputRepository, outputRepository, outputName, imageService, dataSourceFactory);
+ }
+ else if (PentahoReportEngineMetaData.DEBUG.equals(mimeType))
+ {
+ ret = new XmlPrintReportProcessor(System.out, "ISO-8859-1");
+ }
+ else
+ {
+ throw new ReportExecutionException("Invalid mime-type");
+ }
+
+ return ret;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/SOFormulaOpCodeMapper.java b/reportbuilder/java/org/libreoffice/report/pentaho/SOFormulaOpCodeMapper.java
new file mode 100644
index 000000000..977c96e0a
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/SOFormulaOpCodeMapper.java
@@ -0,0 +1,143 @@
+/*
+ * 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;
+
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lib.uno.helper.WeakBase;
+import com.sun.star.sheet.FormulaLanguage;
+import com.sun.star.sheet.FormulaMapGroup;
+import com.sun.star.sheet.FormulaOpCodeMapEntry;
+import com.sun.star.sheet.FormulaToken;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+public final class SOFormulaOpCodeMapper extends WeakBase
+ implements com.sun.star.sheet.XFormulaOpCodeMapper, XServiceInfo
+{
+
+ private static final String __serviceName = "org.libreoffice.report.pentaho.SOFormulaOpCodeMapper";
+ private final SOFormulaParser parser;
+ // attributes
+ static final private int m_OpCodeExternal = 0;
+ static final private int m_OpCodeUnknown = 0;
+
+ public SOFormulaOpCodeMapper(SOFormulaParser parser)
+ {
+ this.parser = parser;
+ }
+
+ // com.sun.star.sheet.XFormulaOpCodeMapper:
+ public int getOpCodeExternal()
+ {
+ return m_OpCodeExternal;
+ }
+
+ public int getOpCodeUnknown()
+ {
+ return m_OpCodeUnknown;
+ }
+
+ public com.sun.star.sheet.FormulaToken[] getMappings(String[] Names, int Language) throws com.sun.star.lang.IllegalArgumentException
+ {
+ if (Language != FormulaLanguage.ODFF)
+ {
+ throw new IllegalArgumentException();
+ }
+ final ArrayList<FormulaToken> token = new ArrayList<FormulaToken>();
+ final Map parserNames = parser.getNames();
+ for (int i = 0; i < Names.length; i++)
+ {
+ if (parserNames.containsKey(Names[i]))
+ {
+ token.add(((FormulaOpCodeMapEntry) parserNames.get(Names[i])).Token);
+ }
+
+ }
+ return token.toArray(new FormulaToken[token.size()]);
+ }
+
+ public com.sun.star.sheet.FormulaOpCodeMapEntry[] getAvailableMappings(int Language, int Groups) throws com.sun.star.lang.IllegalArgumentException
+ {
+ if (Language != FormulaLanguage.ODFF)
+ {
+ throw new IllegalArgumentException();
+ }
+ final ArrayList<FormulaOpCodeMapEntry> token = new ArrayList<FormulaOpCodeMapEntry>();
+ if (Groups == FormulaMapGroup.SPECIAL)
+ {
+ return parser.getSpecialOpCodes().toArray(new FormulaOpCodeMapEntry[parser.getSpecialOpCodes().size()]);
+ }
+ else
+ {
+ if ((Groups & FormulaMapGroup.ARRAY_SEPARATORS) != 0)
+ {
+ token.addAll(parser.getGroup(SOFormulaParser.ARRAY_SEPARATORS).values());
+ }
+ if ((Groups & FormulaMapGroup.SEPARATORS) != 0)
+ {
+ token.addAll(parser.getGroup(SOFormulaParser.SEPARATORS).values());
+ }
+ if ((Groups & FormulaMapGroup.ARRAY_SEPARATORS) != 0)
+ {
+ token.addAll(parser.getGroup(SOFormulaParser.ARRAY_SEPARATORS).values());
+ }
+ if ((Groups & FormulaMapGroup.UNARY_OPERATORS) != 0)
+ {
+ token.addAll(parser.getGroup(SOFormulaParser.UNARY_OPERATORS).values());
+ }
+ if ((Groups & FormulaMapGroup.BINARY_OPERATORS) != 0)
+ {
+ token.addAll(parser.getGroup(SOFormulaParser.BINARY_OPERATORS).values());
+ }
+ if ((Groups & FormulaMapGroup.FUNCTIONS) != 0)
+ {
+ token.addAll(parser.getGroup(SOFormulaParser.FUNCTIONS).values());
+ }
+ }
+
+ return token.toArray(new FormulaOpCodeMapEntry[token.size()]);
+ }
+
+ public String getImplementationName()
+ {
+ return SOFormulaOpCodeMapper.class.getName();
+ }
+
+ public boolean supportsService(String sServiceName)
+ {
+ return sServiceName.equals(__serviceName);
+ }
+
+ public String[] getSupportedServiceNames()
+ {
+ return getServiceNames();
+ }
+
+ /**
+ * This method is a simple helper function to used in the static component initialisation functions as well as
+ * in getSupportedServiceNames.
+ */
+ private static String[] getServiceNames()
+ {
+ return new String[]
+ {
+ __serviceName
+ };
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/SOFormulaParser.java b/reportbuilder/java/org/libreoffice/report/pentaho/SOFormulaParser.java
new file mode 100644
index 000000000..24bf1a682
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/SOFormulaParser.java
@@ -0,0 +1,430 @@
+/*
+ * 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;
+
+
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lib.uno.helper.ComponentBase;
+import com.sun.star.lib.uno.helper.PropertySetMixin;
+import com.sun.star.sheet.FormulaLanguage;
+import com.sun.star.sheet.FormulaMapGroup;
+import com.sun.star.sheet.FormulaMapGroupSpecialOffset;
+import com.sun.star.sheet.FormulaOpCodeMapEntry;
+import com.sun.star.sheet.FormulaToken;
+import com.sun.star.sheet.XFormulaOpCodeMapper;
+import com.sun.star.uno.Any;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+import java.io.StringReader;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.pentaho.reporting.libraries.base.config.Configuration;
+import org.pentaho.reporting.libraries.formula.DefaultFormulaContext;
+import org.pentaho.reporting.libraries.formula.function.FunctionRegistry;
+import org.pentaho.reporting.libraries.formula.parser.FormulaParser;
+import org.pentaho.reporting.libraries.formula.parser.GeneratedFormulaParserConstants;
+import org.pentaho.reporting.libraries.formula.parser.GeneratedFormulaParserTokenManager;
+import org.pentaho.reporting.libraries.formula.parser.JavaCharStream;
+import org.pentaho.reporting.libraries.formula.parser.ParseException;
+import org.pentaho.reporting.libraries.formula.parser.Token;
+import org.pentaho.reporting.libraries.formula.parser.TokenMgrError;
+
+
+public final class SOFormulaParser extends ComponentBase
+ implements com.sun.star.report.meta.XFormulaParser, XServiceInfo
+{
+ /* Need this to get around generics array creation restriction */
+ private static class StringOpcodeMap extends HashMap<Integer,FormulaOpCodeMapEntry> {}
+
+ public static final int SEPARATORS = 0;
+ public static final int ARRAY_SEPARATORS = 1;
+ public static final int UNARY_OPERATORS = 2;
+ public static final int BINARY_OPERATORS = 3;
+ public static final int FUNCTIONS = 4;
+ private final PropertySetMixin m_prophlp;
+ private static final String __serviceName = "com.sun.star.report.meta.FormulaParser";
+ private static final String OPERATORS = "org.pentaho.reporting.libraries.formula.operators.";
+ // attributes
+ final private List<FormulaOpCodeMapEntry> m_OpCodeMap = new ArrayList<FormulaOpCodeMapEntry>();
+ private XFormulaOpCodeMapper formulaOpCodeMapper = null;
+ private final Map<Integer,FormulaOpCodeMapEntry> parserAllOpCodes = new HashMap<Integer,FormulaOpCodeMapEntry>();
+ private final Map<String,FormulaOpCodeMapEntry> parserNames = new HashMap<String,FormulaOpCodeMapEntry>();
+ private final StringOpcodeMap[] groupOpCodes = new StringOpcodeMap[5];
+ private final List<FormulaOpCodeMapEntry> specialOpCodes = new ArrayList<FormulaOpCodeMapEntry>();
+ private int ownTokenCounter = 1000;
+ private final FormulaOpCodeMapEntry opCodePush;
+ private final FormulaParser parser;
+
+ public SOFormulaParser(final XComponentContext context)
+ {
+
+ final ClassLoader cl = java.lang.Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
+
+ parser = new FormulaParser();
+ try
+ {
+ final XFormulaOpCodeMapper mapper = UnoRuntime.queryInterface(XFormulaOpCodeMapper.class, context.getServiceManager().createInstanceWithContext("simple.formula.FormulaOpCodeMapperObj", context));
+ FormulaOpCodeMapEntry[] opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.FUNCTIONS);
+ final DefaultFormulaContext defaultContext = new DefaultFormulaContext();
+ final FunctionRegistry functionRegistry = defaultContext.getFunctionRegistry();
+
+ String[] names = functionRegistry.getFunctionNames();
+ addOpCodes(names, opCodes, FUNCTIONS);
+ names = getOperators(defaultContext, OPERATORS);
+ opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.UNARY_OPERATORS);
+ addOpCodes(names, opCodes, UNARY_OPERATORS);
+ opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.BINARY_OPERATORS);
+ addOpCodes(names, opCodes, BINARY_OPERATORS);
+
+ names = GeneratedFormulaParserConstants.tokenImage.clone();
+ for (int i = 0; i < names.length; i++)
+ {
+ final String token = names[i];
+ if (token != null && token.length() > 0 && token.charAt(0) == '"')
+ {
+ names[i] = token.substring(1, token.length() - 1);
+ }
+ }
+ opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.SEPARATORS);
+ addOpCodes(names, opCodes, SEPARATORS, false);
+
+ opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.ARRAY_SEPARATORS);
+ addOpCodes(names, opCodes, ARRAY_SEPARATORS, false);
+
+ opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.SPECIAL);
+
+ for (int i = 0; i < opCodes.length; i++)
+ {
+ final FormulaOpCodeMapEntry opCode = opCodes[i];
+ parserAllOpCodes.put(opCode.Token.OpCode, opCode);
+ specialOpCodes.add(opCode);
+ }
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ opCodePush = specialOpCodes.get(FormulaMapGroupSpecialOffset.PUSH);
+ Thread.currentThread().setContextClassLoader(cl);
+ // use the last parameter of the PropertySetMixin constructor
+ // for your optional attributes if necessary. See the documentation
+ // of the PropertySetMixin helper for further information.
+ // Ensure that your attributes are initialized correctly!
+ m_prophlp = new PropertySetMixin(context, this,
+ new Type(com.sun.star.report.meta.XFormulaParser.class), null);
+ }
+
+ // com.sun.star.sheet.XFormulaParser:
+ public com.sun.star.sheet.FormulaToken[] parseFormula(String aFormula, com.sun.star.table.CellAddress aReferencePos)
+ {
+ final ArrayList<FormulaToken> tokens = new ArrayList<FormulaToken>();
+ if (!"=".equals(aFormula))
+ {
+ String formula;
+ if (aFormula.charAt(0) == '=')
+ {
+ formula = aFormula.substring(1);
+ }
+ else
+ {
+ formula = aFormula;
+ }
+ final ArrayList<String> images = new ArrayList<String>();
+ try
+ {
+ int brackets = 0;
+ final GeneratedFormulaParserTokenManager tokenParser = new GeneratedFormulaParserTokenManager(new JavaCharStream(new StringReader(formula), 1, 1));
+ Token token = tokenParser.getNextToken();
+ while (token.kind != GeneratedFormulaParserConstants.EOF)
+ {
+ final FormulaToken formulaToken;
+ images.add(token.image);
+ final String upper = token.image.toUpperCase();
+ if (parserNames.containsKey(upper))
+ {
+ if ("(".equals(token.image))
+ {
+ brackets++;
+ }
+ else if (")".equals(token.image))
+ {
+ --brackets;
+ }
+ final FormulaOpCodeMapEntry opCode = parserNames.get(upper);
+ formulaToken = opCode.Token;
+ }
+ else if (token.kind == GeneratedFormulaParserConstants.WHITESPACE)
+ {
+ final FormulaOpCodeMapEntry opCode = specialOpCodes.get(FormulaMapGroupSpecialOffset.SPACES);
+ formulaToken = opCode.Token;
+ }
+ else
+ {
+ formulaToken = new FormulaToken();
+ formulaToken.OpCode = opCodePush.Token.OpCode;
+ formulaToken.Data = new Any(Type.STRING, token.image);
+ }
+
+ tokens.add(formulaToken);
+ token = tokenParser.getNextToken();
+ }
+ if (brackets > 0)
+ {
+ final FormulaOpCodeMapEntry opCode = parserNames.get(")");
+ while (brackets-- != 0)
+ {
+ formula = formula.concat(")");
+ images.add(")");
+ tokens.add(opCode.Token);
+ }
+
+ }
+
+ parser.parse(formula);
+ }
+ catch (ParseException ex)
+ {
+ boolean found = false;
+ // error occurred so all token must be bad
+ for (int i = 0; i < tokens.size(); i++)
+ {
+ if (!found && ex.currentToken != null && images.get(i).equals(ex.currentToken.image))
+ {
+ found = true;
+ }
+ if (found)
+ {
+ final FormulaToken dest = new FormulaToken();
+ dest.OpCode = specialOpCodes.get(FormulaMapGroupSpecialOffset.BAD).Token.OpCode;
+ dest.Data = new Any(Type.STRING, images.get(i));
+ tokens.remove(i);
+ tokens.add(i, dest);
+ }
+ }
+ }
+ catch (java.lang.Exception e)
+ {
+ }
+ catch (TokenMgrError e)
+ {
+ }
+ }
+ return tokens.toArray(new FormulaToken[tokens.size()]);
+ }
+
+ public String printFormula(com.sun.star.sheet.FormulaToken[] aTokens, com.sun.star.table.CellAddress aReferencePos)
+ {
+ final StringBuffer ret = new StringBuffer();
+ for (int i = 0; i < aTokens.length; i++)
+ {
+ final FormulaToken formulaToken = aTokens[i];
+ if (formulaToken.OpCode == opCodePush.Token.OpCode && !formulaToken.Data.equals(Any.VOID))
+ {
+ ret.append(formulaToken.Data);
+ }
+ else if (parserAllOpCodes.containsKey(formulaToken.OpCode))
+ {
+ final FormulaOpCodeMapEntry opCode = parserAllOpCodes.get(formulaToken.OpCode);
+ if (opCode.Name.length() > 0)
+ {
+ ret.append(opCode.Name);
+ }
+ else if (!formulaToken.Data.equals(Any.VOID))
+ {
+ ret.append(formulaToken.Data);
+ }
+ }
+ }
+ return ret.toString();
+ }
+
+ // com.sun.star.beans.XPropertySet:
+ public com.sun.star.beans.XPropertySetInfo getPropertySetInfo()
+ {
+ return m_prophlp.getPropertySetInfo();
+ }
+
+ public void setPropertyValue(String aPropertyName, Object aValue) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.beans.PropertyVetoException, com.sun.star.lang.IllegalArgumentException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.setPropertyValue(aPropertyName, aValue);
+ }
+
+ public Object getPropertyValue(String aPropertyName) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ return m_prophlp.getPropertyValue(aPropertyName);
+ }
+
+ public void addPropertyChangeListener(String aPropertyName, com.sun.star.beans.XPropertyChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.addPropertyChangeListener(aPropertyName, xListener);
+ }
+
+ public void removePropertyChangeListener(String aPropertyName, com.sun.star.beans.XPropertyChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.removePropertyChangeListener(aPropertyName, xListener);
+ }
+
+ public void addVetoableChangeListener(String aPropertyName, com.sun.star.beans.XVetoableChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.addVetoableChangeListener(aPropertyName, xListener);
+ }
+
+ public void removeVetoableChangeListener(String aPropertyName, com.sun.star.beans.XVetoableChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.removeVetoableChangeListener(aPropertyName, xListener);
+ }
+
+ // com.sun.star.report.meta.XFormulaParser:
+ public com.sun.star.sheet.FormulaOpCodeMapEntry[] getOpCodeMap()
+ {
+ return m_OpCodeMap.toArray(new FormulaOpCodeMapEntry[m_OpCodeMap.size()]);
+ }
+
+ public void setOpCodeMap(com.sun.star.sheet.FormulaOpCodeMapEntry[] the_value)
+ {
+ }
+
+ public String getImplementationName()
+ {
+ return SOFormulaParser.class.getName();
+ }
+
+ public boolean supportsService(String sServiceName)
+ {
+ return sServiceName.equals(__serviceName);
+ }
+
+ public String[] getSupportedServiceNames()
+ {
+ return getServiceNames();
+ }
+
+ /**
+ * This method is a simple helper function to used in the static component initialisation functions as well as
+ * in getSupportedServiceNames.
+ */
+ public static String[] getServiceNames()
+ {
+ return new String[]
+ {
+ __serviceName
+ };
+ }
+
+ public XFormulaOpCodeMapper getFormulaOpCodeMapper()
+ {
+ if (formulaOpCodeMapper == null)
+ {
+ formulaOpCodeMapper = new SOFormulaOpCodeMapper(this);
+ }
+
+ return formulaOpCodeMapper;
+ }
+
+ private void addOpCodes(String[] names, FormulaOpCodeMapEntry[] opCodes, int group)
+ {
+ addOpCodes(names, opCodes, group, true);
+ }
+
+ private void addOpCodes(String[] names, FormulaOpCodeMapEntry[] opCodes, int group, boolean add)
+ {
+ groupOpCodes[group] = new StringOpcodeMap();
+ for (int j = 0; j < names.length; j++)
+ {
+ FormulaOpCodeMapEntry opCode = null;
+ int i = 0;
+ for (; i < opCodes.length; i++)
+ {
+ opCode = opCodes[i];
+ if (names[j].equals(opCode.Name))
+ {
+ break;
+ }
+ }
+ if (i >= opCodes.length)
+ {
+ if (!add)
+ {
+ continue;
+ }
+ final FormulaToken token = new FormulaToken(ownTokenCounter++, Any.VOID);
+ opCode = new FormulaOpCodeMapEntry(names[j], token);
+ }
+ parserNames.put(names[j], opCode);
+ parserAllOpCodes.put(opCode.Token.OpCode, opCode);
+ groupOpCodes[group].put(opCode.Token.OpCode, opCode);
+ }
+ }
+
+ public Map<String,FormulaOpCodeMapEntry> getNames()
+ {
+ return parserNames;
+ }
+
+ public Map<Integer,FormulaOpCodeMapEntry> getGroup(int group)
+ {
+ return groupOpCodes[group];
+ }
+
+ private String[] getOperators(DefaultFormulaContext defaultContext, final String _kind)
+ {
+ final ArrayList<String> ops = new ArrayList<String>();
+ final Configuration configuration = defaultContext.getConfiguration();
+ final Iterator iter = configuration.findPropertyKeys(_kind);
+ while (iter.hasNext())
+ {
+ final String configKey = (String) iter.next();
+ if (!configKey.endsWith(".class"))
+ {
+ continue;
+ }
+ final String operatorClass = configuration.getConfigProperty(configKey);
+ if (operatorClass == null)
+ {
+ continue;
+ }
+ if (operatorClass.length() == 0)
+ {
+ continue;
+ }
+ final String tokenKey = configKey.substring(0, configKey.length() - ".class".length()) + ".token";
+ final String token = configuration.getConfigProperty(tokenKey);
+ if (token == null)
+ {
+ continue;
+ }
+ ops.add(token.trim());
+ }
+ return ops.toArray(new String[ops.size()]);
+ }
+
+ public List<FormulaOpCodeMapEntry> getSpecialOpCodes()
+ {
+ return specialOpCodes;
+ }
+}
+
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/SOFunctionManager.java b/reportbuilder/java/org/libreoffice/report/pentaho/SOFunctionManager.java
new file mode 100644
index 000000000..af3bc94f0
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/SOFunctionManager.java
@@ -0,0 +1,157 @@
+/*
+ * 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;
+
+import com.sun.star.container.NoSuchElementException;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lib.uno.helper.ComponentBase;
+import com.sun.star.report.meta.XFunctionCategory;
+import com.sun.star.report.meta.XFunctionDescription;
+import com.sun.star.report.meta.XFunctionManager;
+import com.sun.star.uno.XComponentContext;
+
+import org.pentaho.reporting.libraries.formula.DefaultFormulaContext;
+import org.pentaho.reporting.libraries.formula.function.FunctionCategory;
+import org.pentaho.reporting.libraries.formula.function.FunctionDescription;
+import org.pentaho.reporting.libraries.formula.function.FunctionRegistry;
+
+public final class SOFunctionManager extends ComponentBase implements XFunctionManager, XServiceInfo
+{
+
+ private final XComponentContext m_xContext;
+ /**
+ * The service name, that must be used to get an instance of this service.
+ */
+ private static final String __serviceName =
+ "com.sun.star.report.meta.FunctionManager";
+ final private FunctionCategory[] categories;
+ final private FunctionRegistry functionRegistry;
+ final private DefaultFormulaContext defaultContext;
+
+ public SOFunctionManager(XComponentContext context)
+ {
+ m_xContext = context;
+ final ClassLoader cl = java.lang.Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
+ defaultContext = new DefaultFormulaContext();
+ functionRegistry = defaultContext.getFunctionRegistry();
+ categories = functionRegistry.getCategories();
+ Thread.currentThread().setContextClassLoader(cl);
+
+ }
+
+ /**
+ * This method returns an array of all supported service names.
+ *
+ * @return Array of supported service names.
+ */
+ public String[] getSupportedServiceNames()
+ {
+ return getServiceNames();
+ }
+
+ /**
+ * This method is a simple helper function to used in the static component initialisation functions as well as
+ * in getSupportedServiceNames.
+ */
+ public static String[] getServiceNames()
+ {
+ return new String[]
+ {
+ __serviceName
+ };
+ }
+
+ /**
+ * This method returns true, if the given service will be supported by the component.
+ *
+ * @param sServiceName Service name.
+ * @return True, if the given service name will be supported.
+ */
+ public boolean supportsService(final String sServiceName)
+ {
+ return sServiceName.equals(__serviceName);
+ }
+
+ /**
+ * Return the class name of the component.
+ *
+ * @return Class name of the component.
+ */
+ public String getImplementationName()
+ {
+ return SOFunctionManager.class.getName();
+ }
+
+ // com.sun.star.container.XElementAccess:
+ public com.sun.star.uno.Type getElementType()
+ {
+ return new com.sun.star.uno.Type(XFunctionCategory.class);
+ }
+
+ public boolean hasElements()
+ {
+ return categories.length != 0;
+ }
+
+ // com.sun.star.container.XIndexAccess:
+ public int getCount()
+ {
+ return categories.length;
+ }
+
+ public Object getByIndex(int Index) throws com.sun.star.lang.IndexOutOfBoundsException, com.sun.star.lang.WrappedTargetException
+ {
+ return getCategory(Index);
+ }
+
+ // com.sun.star.report.meta.XFunctionManager:
+ public com.sun.star.report.meta.XFunctionCategory getCategory(int position) throws com.sun.star.lang.IndexOutOfBoundsException, com.sun.star.lang.WrappedTargetException
+ {
+ if (position >= categories.length)
+ {
+ throw new com.sun.star.lang.IndexOutOfBoundsException();
+ }
+ return new StarFunctionCategory(defaultContext, m_xContext, functionRegistry, position, categories[position]);
+ }
+
+ public XFunctionDescription getFunctionByName(String arg0) throws NoSuchElementException
+ {
+ final FunctionDescription func = functionRegistry.getMetaData(arg0);
+ if (func == null)
+ {
+ throw new NoSuchElementException();
+ }
+ int i = 0;
+ for (; i < categories.length; i++)
+ {
+ if (categories[i] == func.getCategory())
+ {
+ break;
+ }
+ }
+ try
+ {
+ return new StarFunctionDescription(defaultContext, m_xContext, getCategory(i), func);
+ }
+ catch (Exception ex)
+ {
+ }
+ return null;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/SOReportJobFactory.java b/reportbuilder/java/org/libreoffice/report/pentaho/SOReportJobFactory.java
new file mode 100644
index 000000000..322c2ac1c
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/SOReportJobFactory.java
@@ -0,0 +1,453 @@
+/*
+ * 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;
+
+import com.sun.star.beans.NamedValue;
+import com.sun.star.beans.PropertyVetoException;
+import com.sun.star.beans.UnknownPropertyException;
+import com.sun.star.beans.XPropertyChangeListener;
+import com.sun.star.beans.XPropertySet;
+import com.sun.star.beans.XVetoableChangeListener;
+import com.sun.star.container.XChild;
+import com.sun.star.embed.XStorage;
+import com.sun.star.frame.XModel;
+import com.sun.star.lang.IllegalArgumentException;
+import com.sun.star.lang.WrappedTargetException;
+import com.sun.star.lang.XInitialization;
+import com.sun.star.lang.XServiceInfo;
+import com.sun.star.lang.XSingleComponentFactory;
+import com.sun.star.lib.uno.helper.Factory;
+import com.sun.star.lib.uno.helper.PropertySetMixin;
+import com.sun.star.lib.uno.helper.WeakBase;
+import com.sun.star.registry.InvalidRegistryException;
+import com.sun.star.registry.InvalidValueException;
+import com.sun.star.registry.XRegistryKey;
+import com.sun.star.registry.XSimpleRegistry;
+import com.sun.star.sdbc.SQLException;
+import org.jfree.report.ReportDataFactoryException;
+import org.libreoffice.report.DataSourceException;
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.JobProperties;
+import org.libreoffice.report.ReportEngineParameterNames;
+import org.libreoffice.report.ReportExecutionException;
+import org.libreoffice.report.ReportJob;
+import org.libreoffice.report.ReportJobDefinition;
+import org.libreoffice.report.ReportJobFactory;
+import org.libreoffice.report.SDBCReportDataFactory;
+import org.libreoffice.report.SOImageService;
+import org.libreoffice.report.StorageRepository;
+import com.sun.star.report.XReportDefinition;
+import com.sun.star.sdb.XDocumentDataSource;
+import com.sun.star.sdbc.XConnection;
+import com.sun.star.sdbc.XRowSet;
+import com.sun.star.task.XJob;
+import com.sun.star.uno.Exception;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.UnoRuntime;
+import com.sun.star.uno.XComponentContext;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import java.io.Writer;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * This class capsulates the class, that implements the minimal component, a factory for creating the service
+ * (<CODE>__getComponentFactory</CODE>) and a method, that writes the information into the given registry key
+ * (<CODE>__writeRegistryServiceInfo</CODE>).
+ */
+public class SOReportJobFactory
+{
+
+ private SOReportJobFactory()
+ {
+ }
+
+ public static class _SOReportJobFactory extends WeakBase implements XInitialization, XServiceInfo, XJob, XPropertySet, ReportJobFactory
+ {
+
+ private static final Logger LOGGER = Logger.getLogger(_SOReportJobFactory.class.getName());
+ /**
+ * The service name, that must be used to get an instance of this service.
+ */
+ private static final String __serviceName =
+ "org.libreoffice.report.pentaho.SOReportJobFactory";
+ private final PropertySetMixin m_prophlp;
+ /**
+ * The initial component contextr, that gives access to the service manager, supported singletons, ... It's
+ * often later used
+ */
+ private final XComponentContext m_cmpCtx;
+ private XConnection activeConnection;
+ private XReportDefinition report;
+
+ public _SOReportJobFactory(final XComponentContext xCompContext)
+ {
+ m_cmpCtx = xCompContext;
+ m_prophlp = new PropertySetMixin(m_cmpCtx, this,
+ new Type(XJob.class),
+ null); // no optionals
+ }
+
+ /**
+ * This method is a member of the interface for initializing an object directly after its creation.
+ *
+ * @param object This array of arbitrary objects will be passed to the component after its creation.
+ * @throws Exception Every exception will not be handled, but will be passed to the caller.
+ */
+ public void initialize(final Object[] object)
+ throws com.sun.star.uno.Exception
+ {
+ /* The component describes what arguments are expected and in which
+ * order! At this point you can read the objects and initialize
+ * your component using these objects.
+ */
+ }
+
+ /**
+ * This method returns an array of all supported service names.
+ *
+ * @return Array of supported service names.
+ */
+ public String[] getSupportedServiceNames()
+ {
+ return getServiceNames();
+ }
+
+ /**
+ * This method is a simple helper function to used in the static component initialisation functions as well as
+ * in getSupportedServiceNames.
+ */
+ private static String[] getServiceNames()
+ {
+ return new String[]
+ {
+ __serviceName
+ };
+ }
+
+ /**
+ * This method returns true, if the given service will be supported by the component.
+ *
+ * @param sServiceName Service name.
+ * @return True, if the given service name will be supported.
+ */
+ public boolean supportsService(final String sServiceName)
+ {
+ return sServiceName.equals(__serviceName);
+ }
+
+ /**
+ * Return the class name of the component.
+ *
+ * @return Class name of the component.
+ */
+ public String getImplementationName()
+ {
+ return SOReportJobFactory.class.getName();
+ }
+
+ private String getLocaleFromRegistry(final XSimpleRegistry simpleReg, final String path, final String value)
+ {
+ String currentLocale = null;
+ try
+ {
+ simpleReg.open(path, true, false);
+ final XRegistryKey xRegistryRootKey = simpleReg.getRootKey();
+ // read locale
+ final XRegistryKey locale = xRegistryRootKey.openKey(value);
+ if (locale != null)
+ {
+ final String newLocale = locale.getStringValue();
+ if (newLocale != null)
+ {
+ currentLocale = newLocale.replace('-', '_');
+ }
+ }
+ }
+ catch (InvalidValueException ex)
+ {
+ Logger.getLogger(SOReportJobFactory.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ catch (InvalidRegistryException ex)
+ {
+ Logger.getLogger(SOReportJobFactory.class.getName()).log(Level.SEVERE, null, ex);
+ }
+
+ return currentLocale;
+ }
+
+ // tdf#94446 if this is a SQLException in disguise, throw that
+ // original exception instead of the wrapper exception, so that
+ // dbaccess can apply its special handling for
+ // SQLException::ErrorCode of dbtools::ParameterInteractionCancelled
+ // in OLinkedDocumentsAccess::open if ParameterInteractionCancelled
+ // was the root cause
+ public void rethrow_sql_exception(Throwable exception)
+ throws com.sun.star.sdbc.SQLException
+ {
+ if (exception instanceof ReportDataFactoryException == false)
+ return;
+ exception = ((ReportDataFactoryException)exception).getCause();
+ if (exception instanceof DataSourceException == false)
+ return;
+ exception = ((DataSourceException)exception).getCause();
+ if (exception instanceof SQLException == false)
+ return;
+ throw (SQLException)exception;
+ }
+
+ public Object execute(final NamedValue[] namedValue)
+ throws com.sun.star.lang.IllegalArgumentException, com.sun.star.uno.Exception
+ {
+ final ClassLoader cl = java.lang.Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
+ try
+ {
+ final XSimpleRegistry simpleReg = UnoRuntime.queryInterface(XSimpleRegistry.class,
+ m_cmpCtx.getServiceManager().createInstanceWithContext("com.sun.star.configuration.ConfigurationRegistry", m_cmpCtx));
+
+ String currentLocale = getLocaleFromRegistry(simpleReg, "org.openoffice.Setup", "L10N/ooSetupSystemLocale");
+ if (currentLocale == null || "".equals(currentLocale))
+ {
+ currentLocale = getLocaleFromRegistry(simpleReg, "org.openoffice.Office.Linguistic", "General/DefaultLocale");
+ }
+ if (currentLocale != null && !"".equals(currentLocale))
+ {
+ System.setProperty("org.pentaho.reporting.libraries.formula.locale", currentLocale);
+ }
+ final ReportJob job = createReportJob(namedValue);
+ job.execute();
+
+ }
+ catch (java.lang.Exception e)
+ {
+ LOGGER.severe("ReportProcessing failed: " + e);
+ Writer result = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(result);
+ e.printStackTrace(printWriter);
+
+ // if this is a wrapped SQLException, rethrow that instead
+ rethrow_sql_exception(e.getCause());
+
+ throw new com.sun.star.lang.WrappedTargetException(e, e.toString() + '\n' + result.toString(), this, null);
+ }
+ catch (java.lang.IncompatibleClassChangeError e)
+ {
+ LOGGER.severe("Detected an IncompatibleClassChangeError");
+ Writer result = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(result);
+ e.printStackTrace(printWriter);
+ throw new com.sun.star.lang.WrappedTargetException(e, e.toString() + '\n' + result.toString(), this, null);
+ }
+ Thread.currentThread().setContextClassLoader(cl);
+
+ return null;
+ }
+
+ public ReportJob createReportJob(final NamedValue[] namedValue) throws IllegalArgumentException, ReportExecutionException, Exception
+ {
+ XStorage input = null;
+ XStorage output = null;
+ XRowSet rowSet = null;
+ String mimetype = null;
+ String author = null;
+ String title = null;
+ Integer maxRows = null;
+
+ for (int i = 0; i < namedValue.length; ++i)
+ {
+ final NamedValue aProps = namedValue[i];
+ if ("ActiveConnection".equalsIgnoreCase(aProps.Name))
+ {
+ activeConnection = UnoRuntime.queryInterface(XConnection.class, aProps.Value);
+ }
+ else if ("ReportDefinition".equalsIgnoreCase(aProps.Name))
+ {
+ report = UnoRuntime.queryInterface(XReportDefinition.class, aProps.Value);
+ }
+ else if ("InputStorage".equalsIgnoreCase(aProps.Name))
+ {
+ input = UnoRuntime.queryInterface(XStorage.class, aProps.Value);
+ }
+ else if ("OutputStorage".equalsIgnoreCase(aProps.Name))
+ {
+ output = UnoRuntime.queryInterface(XStorage.class, aProps.Value);
+ }
+ else if ("RowSet".equalsIgnoreCase(aProps.Name))
+ {
+ rowSet = UnoRuntime.queryInterface(XRowSet.class, aProps.Value);
+ }
+ else if ("mimetype".equalsIgnoreCase(aProps.Name))
+ {
+ mimetype = (String) aProps.Value;
+ }
+ else if ("MaxRows".equalsIgnoreCase(aProps.Name))
+ {
+ maxRows = (Integer) aProps.Value;
+ }
+ else if (ReportEngineParameterNames.AUTHOR.equalsIgnoreCase(aProps.Name))
+ {
+ author = (String) aProps.Value;
+ }
+ else if (ReportEngineParameterNames.TITLE.equalsIgnoreCase(aProps.Name))
+ {
+ title = (String) aProps.Value;
+ }
+ }
+
+ if (input == null || output == null)
+ {
+ throw new com.sun.star.lang.IllegalArgumentException();
+ }
+
+ if (rowSet == null)
+ {
+ if (report == null || activeConnection == null)
+ {
+ throw new com.sun.star.lang.IllegalArgumentException();
+ }
+ mimetype = report.getMimeType();
+ }
+ else
+ {
+ final XPropertySet set = UnoRuntime.queryInterface(XPropertySet.class, rowSet);
+ if (set == null)
+ {
+ throw new com.sun.star.lang.IllegalArgumentException();
+ }
+ activeConnection = UnoRuntime.queryInterface(XConnection.class, set.getPropertyValue("ActiveConnection"));
+ }
+ if (mimetype == null)
+ {
+ mimetype = PentahoReportEngineMetaData.OPENDOCUMENT_TEXT;
+ }
+
+ final XChild child = UnoRuntime.queryInterface(XChild.class, activeConnection);
+ final XDocumentDataSource docSource = UnoRuntime.queryInterface(XDocumentDataSource.class, child.getParent());
+ final XModel model = UnoRuntime.queryInterface(XModel.class, docSource.getDatabaseDocument());
+ final DataSourceFactory dataFactory = new SDBCReportDataFactory(m_cmpCtx, activeConnection);
+ final StorageRepository storageRepository = new StorageRepository(input, output, model.getURL());
+
+ final String inputName = "content.xml";
+ final String outputName = "content.xml";
+
+ final PentahoReportEngine engine = new PentahoReportEngine();
+ final ReportJobDefinition definition = engine.createJobDefinition();
+ final JobProperties procParms = definition.getProcessingParameters();
+ procParms.setProperty(ReportEngineParameterNames.INPUT_REPOSITORY, storageRepository);
+ procParms.setProperty(ReportEngineParameterNames.OUTPUT_REPOSITORY, storageRepository);
+ procParms.setProperty(ReportEngineParameterNames.INPUT_NAME, inputName);
+ procParms.setProperty(ReportEngineParameterNames.OUTPUT_NAME, outputName);
+ procParms.setProperty(ReportEngineParameterNames.CONTENT_TYPE, mimetype);
+ procParms.setProperty(ReportEngineParameterNames.INPUT_DATASOURCE_FACTORY, dataFactory);
+ procParms.setProperty(ReportEngineParameterNames.IMAGE_SERVICE, new SOImageService(m_cmpCtx));
+ procParms.setProperty(ReportEngineParameterNames.INPUT_REPORTJOB_FACTORY, this);
+ procParms.setProperty(ReportEngineParameterNames.MAXROWS, maxRows);
+ if (author != null)
+ {
+ procParms.setProperty(ReportEngineParameterNames.AUTHOR, author);
+ }
+ if (title != null)
+ {
+ procParms.setProperty(ReportEngineParameterNames.TITLE, title);
+ }
+
+ return engine.createJob(definition);
+ }
+
+ // com.sun.star.beans.XPropertySet:
+ public com.sun.star.beans.XPropertySetInfo getPropertySetInfo()
+ {
+ return m_prophlp.getPropertySetInfo();
+ }
+
+ public void setPropertyValue(final String aPropertyName, final Object aValue)
+ throws UnknownPropertyException, PropertyVetoException, com.sun.star.lang.IllegalArgumentException,
+ WrappedTargetException
+ {
+ m_prophlp.setPropertyValue(aPropertyName, aValue);
+ }
+
+ public Object getPropertyValue(final String aPropertyName)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ return m_prophlp.getPropertyValue(aPropertyName);
+ }
+
+ public void addPropertyChangeListener(final String aPropertyName, final XPropertyChangeListener xListener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ m_prophlp.addPropertyChangeListener(aPropertyName, xListener);
+ }
+
+ public void removePropertyChangeListener(final String aPropertyName, final XPropertyChangeListener xListener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ m_prophlp.removePropertyChangeListener(aPropertyName, xListener);
+ }
+
+ public void addVetoableChangeListener(final String aPropertyName, final XVetoableChangeListener xListener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ m_prophlp.addVetoableChangeListener(aPropertyName, xListener);
+ }
+
+ public void removeVetoableChangeListener(final String aPropertyName, final XVetoableChangeListener xListener)
+ throws UnknownPropertyException, WrappedTargetException
+ {
+ m_prophlp.removeVetoableChangeListener(aPropertyName, xListener);
+ }
+ }
+
+ /**
+ * Gives a factory for creating the service. This method is called by the <code>JavaLoader</code>.
+ *
+ * @param sImplName the name of the implementation for which a service is desired
+ * @return returns a <code>XSingleComponentFactory</code> for creating the component
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static XSingleComponentFactory __getComponentFactory(final String sImplName)
+ {
+ XSingleComponentFactory xFactory = null;
+
+ try
+ {
+ if (sImplName.equals(_SOReportJobFactory.class.getName()))
+ {
+ xFactory = Factory.createComponentFactory(_SOReportJobFactory.class, _SOReportJobFactory.getServiceNames());
+ }
+ else if (sImplName.equals(SOFunctionManager.class.getName()))
+ {
+ xFactory = Factory.createComponentFactory(SOFunctionManager.class, SOFunctionManager.getServiceNames());
+ }
+ else if (sImplName.equals(SOFormulaParser.class.getName()))
+ {
+ xFactory = Factory.createComponentFactory(SOFormulaParser.class, SOFormulaParser.getServiceNames());
+ }
+ }
+ catch (java.lang.IncompatibleClassChangeError e2)
+ {
+ }
+
+ return xFactory;
+ }
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/StarFunctionCategory.java b/reportbuilder/java/org/libreoffice/report/pentaho/StarFunctionCategory.java
new file mode 100644
index 000000000..83f26a0ea
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/StarFunctionCategory.java
@@ -0,0 +1,166 @@
+/*
+ * 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;
+
+import com.sun.star.lib.uno.helper.PropertySetMixin;
+import com.sun.star.lib.uno.helper.WeakBase;
+import com.sun.star.report.meta.XFunctionDescription;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.XComponentContext;
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+
+import org.pentaho.reporting.libraries.formula.DefaultFormulaContext;
+import org.pentaho.reporting.libraries.formula.function.FunctionCategory;
+import org.pentaho.reporting.libraries.formula.function.FunctionRegistry;
+
+public final class StarFunctionCategory extends WeakBase
+ implements com.sun.star.report.meta.XFunctionCategory
+{
+
+ private final XComponentContext m_xContext;
+ private final PropertySetMixin m_prophlp;
+ // attributes
+ private final int m_Number;
+ private final FunctionCategory category;
+ private final FunctionRegistry functionRegistry;
+ private final String functions[];
+ private final DefaultFormulaContext defaultContext;
+ private final Locale defaultLocale;
+
+ public StarFunctionCategory(DefaultFormulaContext defaultContext, final XComponentContext context, final FunctionRegistry functionRegistry, final int _number, final FunctionCategory category)
+ {
+ this.defaultContext = defaultContext;
+ m_xContext = context;
+ m_Number = _number;
+ this.category = category;
+ this.functionRegistry = functionRegistry;
+ Locale locale;
+ try
+ {
+ category.getDisplayName(defaultContext.getLocalizationContext().getLocale());
+ locale = defaultContext.getLocalizationContext().getLocale();
+ }
+ catch (MissingResourceException e)
+ {
+ locale = Locale.ENGLISH;
+ try
+ {
+ category.getDisplayName(locale);
+ }
+ catch (MissingResourceException e2)
+ {
+ }
+ }
+ this.defaultLocale = locale;
+
+ functions = functionRegistry.getFunctionNamesByCategory(category);
+ // use the last parameter of the PropertySetMixin constructor
+ // for your optional attributes if necessary. See the documentation
+ // of the PropertySetMixin helper for further information.
+ // Ensure that your attributes are initialized correctly!
+ m_prophlp = new PropertySetMixin(m_xContext, this,
+ new Type(com.sun.star.report.meta.XFunctionCategory.class), null);
+ }
+
+ // com.sun.star.beans.XPropertySet:
+ public com.sun.star.beans.XPropertySetInfo getPropertySetInfo()
+ {
+ return m_prophlp.getPropertySetInfo();
+ }
+
+ public void setPropertyValue(String aPropertyName, Object aValue) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.beans.PropertyVetoException, com.sun.star.lang.IllegalArgumentException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.setPropertyValue(aPropertyName, aValue);
+ }
+
+ public Object getPropertyValue(String aPropertyName) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ return m_prophlp.getPropertyValue(aPropertyName);
+ }
+
+ public void addPropertyChangeListener(String aPropertyName, com.sun.star.beans.XPropertyChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.addPropertyChangeListener(aPropertyName, xListener);
+ }
+
+ public void removePropertyChangeListener(String aPropertyName, com.sun.star.beans.XPropertyChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.removePropertyChangeListener(aPropertyName, xListener);
+ }
+
+ public void addVetoableChangeListener(String aPropertyName, com.sun.star.beans.XVetoableChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.addVetoableChangeListener(aPropertyName, xListener);
+ }
+
+ public void removeVetoableChangeListener(String aPropertyName, com.sun.star.beans.XVetoableChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.removeVetoableChangeListener(aPropertyName, xListener);
+ }
+
+ // com.sun.star.container.XElementAccess:
+ public com.sun.star.uno.Type getElementType()
+ {
+ return new com.sun.star.uno.Type(XFunctionDescription.class);
+ }
+
+ public boolean hasElements()
+ {
+ return functions.length != 0;
+ }
+
+ // com.sun.star.container.XIndexAccess:
+ public int getCount()
+ {
+ return functions.length;
+ }
+
+ public Object getByIndex(int Index) throws com.sun.star.lang.IndexOutOfBoundsException, com.sun.star.lang.WrappedTargetException
+ {
+ return getFunction(Index);
+ }
+
+ // com.sun.star.report.meta.XFunctionCategory:
+ public int getNumber()
+ {
+ return m_Number;
+ }
+
+ public String getName()
+ {
+ try
+ {
+ return category.getDisplayName(defaultLocale);
+ }
+ catch(Exception ex)
+ {
+ }
+ return "Missing category for number " + m_Number;
+ }
+
+ public com.sun.star.report.meta.XFunctionDescription getFunction(int position) throws com.sun.star.lang.IndexOutOfBoundsException, com.sun.star.lang.WrappedTargetException
+ {
+ if (position >= functions.length)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ return new StarFunctionDescription(defaultContext, m_xContext, this, functionRegistry.getMetaData(functions[position]));
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/StarFunctionDescription.java b/reportbuilder/java/org/libreoffice/report/pentaho/StarFunctionDescription.java
new file mode 100644
index 000000000..2eddaf307
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/StarFunctionDescription.java
@@ -0,0 +1,196 @@
+/*
+ * 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;
+
+import com.sun.star.lib.uno.helper.PropertySetMixin;
+import com.sun.star.lib.uno.helper.WeakBase;
+import com.sun.star.report.meta.XFunctionCategory;
+import com.sun.star.sheet.FunctionArgument;
+import com.sun.star.uno.Type;
+import com.sun.star.uno.XComponentContext;
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+
+import org.pentaho.reporting.libraries.formula.DefaultFormulaContext;
+import org.pentaho.reporting.libraries.formula.function.FunctionDescription;
+
+public final class StarFunctionDescription extends WeakBase
+ implements com.sun.star.report.meta.XFunctionDescription
+{
+
+ private final PropertySetMixin m_prophlp;
+ private final FunctionDescription functionDescription;
+ private final XFunctionCategory category;
+ private final Locale defaultLocale;
+
+ public StarFunctionDescription(final DefaultFormulaContext defaultContext, final XComponentContext context, final XFunctionCategory category, final FunctionDescription functionDescription)
+ {
+ this.category = category;
+ Locale locale;
+ try
+ {
+ functionDescription.getDisplayName(defaultContext.getLocalizationContext().getLocale());
+ locale = defaultContext.getLocalizationContext().getLocale();
+ }
+ catch (MissingResourceException e)
+ {
+ locale = Locale.ENGLISH;
+ }
+ this.defaultLocale = locale;
+
+ this.functionDescription = functionDescription;
+ // use the last parameter of the PropertySetMixin constructor
+ // for your optional attributes if necessary. See the documentation
+ // of the PropertySetMixin helper for further information.
+ // Ensure that your attributes are initialized correctly!
+ m_prophlp = new PropertySetMixin(context, this,
+ new Type(com.sun.star.report.meta.XFunctionDescription.class), null);
+ }
+
+ // com.sun.star.beans.XPropertySet:
+ public com.sun.star.beans.XPropertySetInfo getPropertySetInfo()
+ {
+ return m_prophlp.getPropertySetInfo();
+ }
+
+ public void setPropertyValue(String aPropertyName, Object aValue) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.beans.PropertyVetoException, com.sun.star.lang.IllegalArgumentException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.setPropertyValue(aPropertyName, aValue);
+ }
+
+ public Object getPropertyValue(String aPropertyName) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ return m_prophlp.getPropertyValue(aPropertyName);
+ }
+
+ public void addPropertyChangeListener(String aPropertyName, com.sun.star.beans.XPropertyChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.addPropertyChangeListener(aPropertyName, xListener);
+ }
+
+ public void removePropertyChangeListener(String aPropertyName, com.sun.star.beans.XPropertyChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.removePropertyChangeListener(aPropertyName, xListener);
+ }
+
+ public void addVetoableChangeListener(String aPropertyName, com.sun.star.beans.XVetoableChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.addVetoableChangeListener(aPropertyName, xListener);
+ }
+
+ public void removeVetoableChangeListener(String aPropertyName, com.sun.star.beans.XVetoableChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
+ {
+ m_prophlp.removeVetoableChangeListener(aPropertyName, xListener);
+ }
+
+ // com.sun.star.report.meta.XFunctionDescription:
+ public com.sun.star.report.meta.XFunctionCategory getCategory()
+ {
+ return category;
+ }
+
+ public String getName()
+ {
+ try
+ {
+ return functionDescription.getDisplayName(defaultLocale);
+ }
+ catch (Exception ex)
+ {
+ }
+ return "Missing function name for " + this.getClass().getName();
+ }
+
+ public String getDescription()
+ {
+ try
+ {
+ return functionDescription.getDescription(defaultLocale);
+ }
+ catch (Exception ex)
+ {
+ }
+ return "Missing function description for " + this.getClass().getName();
+ }
+
+ public String getSignature()
+ {
+ final int count = functionDescription.getParameterCount();
+ final StringBuffer signature = new StringBuffer(getName());
+ signature.append('(');
+ for (int i = 0; i < count; i++)
+ {
+ signature.append(functionDescription.getParameterDisplayName(i, defaultLocale));
+ if (i != (count - 1))
+ {
+ signature.append(';');
+ }
+ }
+ signature.append(')');
+ return signature.toString();
+ }
+
+ public com.sun.star.sheet.FunctionArgument[] getArguments()
+ {
+ int count = functionDescription.getParameterCount();
+ final boolean infinite = functionDescription.isInfiniteParameterCount();
+ if (infinite)
+ {
+ // Identical value as VAR_ARGS from formula/funcvarargs.h
+ count = 255;
+ }
+ final FunctionArgument[] args = new FunctionArgument[count];
+ for (int i = 0; i < args.length; i++)
+ {
+ final int pos = infinite ? 0 : i;
+ args[i] = new FunctionArgument();
+ args[i].Description = functionDescription.getParameterDescription(pos, defaultLocale);
+ args[i].Name = functionDescription.getParameterDisplayName(pos, defaultLocale);
+ args[i].IsOptional = !functionDescription.isParameterMandatory(pos);
+ }
+ return args;
+ }
+
+ public String createFormula(String[] arguments) throws com.sun.star.lang.DisposedException, com.sun.star.lang.IllegalArgumentException, com.sun.star.uno.Exception
+ {
+ final boolean infinite = functionDescription.isInfiniteParameterCount();
+ final int count = functionDescription.getParameterCount();
+ if (!infinite && arguments.length > count)
+ {
+ throw new com.sun.star.lang.IllegalArgumentException();
+ }
+
+ final StringBuffer formula = new StringBuffer(getName());
+ formula.append('(');
+ for (int i = 0; i < arguments.length; ++i)
+ {
+ if (arguments[i].length() == 0)
+ {
+ break;
+ }
+ formula.append(arguments[i]);
+ if (i < (arguments.length - 1) && arguments[i + 1].length() != 0)
+ {
+ formula.append(';');
+ }
+ }
+ formula.append(')');
+ return formula.toString();
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/StarReportData.java b/reportbuilder/java/org/libreoffice/report/pentaho/StarReportData.java
new file mode 100644
index 000000000..442703ea4
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/StarReportData.java
@@ -0,0 +1,155 @@
+/*
+ * 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;
+
+import org.libreoffice.report.DataSource;
+
+import org.jfree.report.DataSourceException;
+import org.jfree.report.ReportData;
+
+public class StarReportData implements ReportData
+{
+
+ private final DataSource dataSource;
+ private int currentRow;
+ private final int rowCount;
+
+ public StarReportData(final DataSource dataSource)
+ throws org.libreoffice.report.DataSourceException
+ {
+ if (dataSource == null)
+ {
+ throw new NullPointerException();
+ }
+ this.dataSource = dataSource;
+ this.currentRow = 0;
+ this.rowCount = dataSource.getRowCount();
+ }
+
+ public boolean setCursorPosition(final int row) throws DataSourceException
+ {
+ try
+ {
+ final boolean ret = dataSource.absolute(row);
+ if (ret)
+ {
+ currentRow = row;
+ }
+ return ret;
+ }
+ catch (org.libreoffice.report.DataSourceException e)
+ {
+ throw new DataSourceException("Failed to move cursor", e);
+ }
+ }
+
+ public void close()
+ throws DataSourceException
+ {
+ try
+ {
+ dataSource.close();
+ }
+ catch (org.libreoffice.report.DataSourceException e)
+ {
+ throw new DataSourceException("Failed to close datasource", e);
+ }
+ }
+
+ public int getCursorPosition()
+ throws DataSourceException
+ {
+ return currentRow;
+ }
+
+ /**
+ * This operation checks, whether a call to next will be likely to succeed. If
+ * there is a next data row, this should return true.
+ */
+ public boolean isAdvanceable() throws DataSourceException
+ {
+ return currentRow < rowCount;
+ }
+
+ public boolean next()
+ throws DataSourceException
+ {
+ try
+ {
+ if (dataSource.next())
+ {
+ currentRow += 1;
+ return true;
+ }
+ return false;
+ }
+ catch (org.libreoffice.report.DataSourceException e)
+ {
+ throw new DataSourceException("Failed to move cursor", e);
+ }
+ }
+
+ public Object get(final int column)
+ throws DataSourceException
+ {
+ if (!isReadable())
+ {
+ throw new DataSourceException("Failed to query column.");
+ }
+
+ try
+ {
+ return dataSource.getObject(column + 1);
+ }
+ catch (org.libreoffice.report.DataSourceException e)
+ {
+ throw new DataSourceException("Failed to query column.", e);
+ }
+ }
+
+ public int getColumnCount()
+ throws DataSourceException
+ {
+ try
+ {
+ return dataSource.getColumnCount();
+ }
+ catch (org.libreoffice.report.DataSourceException e)
+ {
+ throw new DataSourceException("Failed to query column count.", e);
+ }
+ }
+
+ public String getColumnName(final int column)
+ throws DataSourceException
+ {
+ try
+ {
+ return dataSource.getColumnName(column + 1);
+ }
+ catch (org.libreoffice.report.DataSourceException e)
+ {
+ throw new DataSourceException("Failed to query column name.", e);
+ }
+ }
+
+ public boolean isReadable() throws DataSourceException
+ {
+ return currentRow > 0 && rowCount > 0;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/StarReportDataFactory.java b/reportbuilder/java/org/libreoffice/report/pentaho/StarReportDataFactory.java
new file mode 100644
index 000000000..3fde6704a
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/StarReportDataFactory.java
@@ -0,0 +1,111 @@
+/*
+ * 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;
+
+import org.libreoffice.report.DataSourceException;
+import org.libreoffice.report.DataSourceFactory;
+
+import java.util.HashMap;
+
+import org.jfree.report.DataSet;
+import org.jfree.report.ReportData;
+import org.jfree.report.ReportDataFactory;
+import org.jfree.report.ReportDataFactoryException;
+
+
+public class StarReportDataFactory implements ReportDataFactory, Cloneable
+{
+
+ private final DataSourceFactory backend;
+
+ public StarReportDataFactory(DataSourceFactory backend)
+ {
+ this.backend = backend;
+ }
+
+ /**
+ * Queries a datasource. The string 'query' defines the name of the query. The
+ * Parameterset given here may contain more data than actually needed.
+ *
+ * <p>The dataset may change between two calls, do not assume anything!</p>
+ */
+ public ReportData queryData(final String query, final DataSet parameters)
+ throws ReportDataFactoryException
+ {
+ try
+ {
+ final HashMap<String, Object> map = new HashMap<String, Object>();
+ final int count = parameters.getColumnCount();
+ for (int i = 0; i < count; i++)
+ {
+ final Object o = parameters.get(i);
+ map.put(parameters.getColumnName(i), o);
+ }
+ return new StarReportData(backend.queryData(query, map));
+ }
+ catch (DataSourceException dse)
+ {
+ String message = dse.getMessage();
+ if (message.length() == 0)
+ {
+ message = "Failed to create report data wrapper";
+ }
+ throw new ReportDataFactoryException(message, dse);
+ }
+ catch (org.jfree.report.DataSourceException e)
+ {
+ String message = e.getMessage();
+ if (message.length() == 0)
+ {
+ message = "Failed to query data";
+ }
+ throw new ReportDataFactoryException(message, e);
+ }
+ }
+
+ public void open()
+ {
+ }
+
+ public void close()
+ {
+ }
+
+ /**
+ * Derives a freshly initialized report data factory, which is independent of
+ * the original data factory. Opening or Closing one data factory must not
+ * affect the other factories.
+ */
+ public ReportDataFactory derive()
+ {
+ try
+ {
+ return (ReportDataFactory) clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public Object clone() throws CloneNotSupportedException
+ {
+ return super.clone();
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/StarReportModule.java b/reportbuilder/java/org/libreoffice/report/pentaho/StarReportModule.java
new file mode 100644
index 000000000..7e26958a8
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/StarReportModule.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+import org.pentaho.reporting.libraries.base.boot.AbstractModule;
+import org.pentaho.reporting.libraries.base.boot.ModuleInitializeException;
+import org.pentaho.reporting.libraries.base.boot.SubSystem;
+
+@SuppressWarnings("ucd")
+public class StarReportModule extends AbstractModule
+{
+
+ public StarReportModule()
+ throws ModuleInitializeException
+ {
+ loadModuleInfo();
+ }
+
+ /**
+ * Initializes the module. Use this method to perform all initial setup operations. This
+ * method is called only once in a modules lifetime. If the initializing cannot be
+ * completed, throw a ModuleInitializeException to indicate the error,. The module will
+ * not be available to the system.
+ *
+ * @param subSystem the subSystem.
+ * @throws ModuleInitializeException
+ * if an error occurred while initializing the module.
+ */
+ public void initialize(final SubSystem subSystem)
+ throws ModuleInitializeException
+ {
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/configuration.properties b/reportbuilder/java/org/libreoffice/report/pentaho/configuration.properties
new file mode 100644
index 000000000..2453cf44e
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/configuration.properties
@@ -0,0 +1,147 @@
+#
+# 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 .
+#
+# x-no-translate
+
+
+##
+# Do not modify the following lines. They connect this module to the central
+# parser registry.
+org.pentaho.reporting.libraries.resourceloader.factory.modules.org.libreoffice.report.pentaho.model.OfficeDocument.star=org.libreoffice.report.pentaho.parser.StarXmlFactoryModule
+org.pentaho.reporting.libraries.resourceloader.factory.modules.org.libreoffice.report.pentaho.model.OfficeStylesCollection.star=org.libreoffice.report.pentaho.parser.StarStyleXmlFactoryModule
+org.pentaho.reporting.libraries.resourceloader.factory.modules.org.libreoffice.report.pentaho.styles.StyleMapper.star=org.libreoffice.report.pentaho.styles.StyleMapperXmlFactoryModule
+
+##
+# The known namespaces.
+#
+org.jfree.report.namespaces.star-rpt.Uri=http://openoffice.org/2005/report
+org.jfree.report.namespaces.star-rpt.Default-Style=res://org/libreoffice/report/pentaho/star-rpt.css
+org.jfree.report.namespaces.star-rpt.Prefix=rpt
+org.jfree.report.namespaces.star-rpt.ClassAttr=style-name
+
+org.jfree.report.namespaces.star-office.Uri=http://openoffice.org/2004/office
+org.jfree.report.namespaces.star-office.Default-Style=res://org/libreoffice/report/pentaho/star-office.css
+org.jfree.report.namespaces.star-office.Prefix=office
+org.jfree.report.namespaces.star-office.ClassAttr=style-name
+
+org.jfree.report.namespaces.oasis-style.Uri=urn:oasis:names:tc:opendocument:xmlns:style:1.0
+org.jfree.report.namespaces.oasis-style.Default-Style=res://org/libreoffice/report/pentaho/oasis-style.css
+org.jfree.report.namespaces.oasis-style.Prefix=style
+
+org.jfree.report.namespaces.oasis-table.Uri=urn:oasis:names:tc:opendocument:xmlns:table:1.0
+org.jfree.report.namespaces.oasis-table.Default-Style=res://org/libreoffice/report/pentaho/oasis-table.css
+org.jfree.report.namespaces.oasis-table.Prefix=table
+org.jfree.report.namespaces.oasis-table.ClassAttr=style-name
+
+org.jfree.report.namespaces.oasis-draw.Uri=urn:oasis:names:tc:opendocument:xmlns:drawing:1.0
+org.jfree.report.namespaces.oasis-draw.Default-Style=res://org/libreoffice/report/pentaho/oasis-draw.css
+org.jfree.report.namespaces.oasis-draw.Prefix=draw
+org.jfree.report.namespaces.oasis-draw.ClassAttr=style-name
+
+org.jfree.report.namespaces.oasis-chart.Uri=urn:oasis:names:tc:opendocument:xmlns:chart:1.0
+org.jfree.report.namespaces.oasis-chart.Default-Style=res://org/libreoffice/report/pentaho/oasis-chart.css
+org.jfree.report.namespaces.oasis-chart.Prefix=chart
+org.jfree.report.namespaces.oasis-chart.ClassAttr=style-name
+
+org.jfree.report.namespaces.oasis-text.Uri=urn:oasis:names:tc:opendocument:xmlns:text:1.0
+org.jfree.report.namespaces.oasis-text.Default-Style=res://org/libreoffice/report/pentaho/oasis-text.css
+org.jfree.report.namespaces.oasis-text.Prefix=text
+org.jfree.report.namespaces.oasis-text.ClassAttr=style-name
+
+org.jfree.report.namespaces.oasis-number.Uri=urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0
+org.jfree.report.namespaces.oasis-number.Default-Style=res://org/libreoffice/report/pentaho/oasis-number.css
+org.jfree.report.namespaces.oasis-number.Prefix=number
+org.jfree.report.namespaces.oasis-number.ClassAttr=style-name
+
+org.jfree.report.namespaces.oasis-form.Uri=urn:oasis:names:tc:opendocument:xmlns:form:1.0
+org.jfree.report.namespaces.oasis-form.Default-Style=res://org/libreoffice/report/pentaho/oasis-form.css
+org.jfree.report.namespaces.oasis-form.Prefix=form
+
+#
+# This defines a subset of the real XSL-FO standard.
+org.jfree.report.namespaces.oasis-compat-fo.Uri=urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0
+org.jfree.report.namespaces.oasis-compat-fo.Default-Style=res://org/libreoffice/report/pentaho/xsl-fo.css
+org.jfree.report.namespaces.oasis-compat-fo.Prefix=fo
+
+#
+# This defines a subset of the real XSL-FO standard.
+org.jfree.report.namespaces.oasis-compat-svg.Uri=urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0
+org.jfree.report.namespaces.oasis-compat-svg.Default-Style=res://org/libreoffice/report/pentaho/svg.css
+org.jfree.report.namespaces.oasis-compat-svg.Prefix=svg
+
+#
+# This defines a subset of the real XSL-FO standard.
+org.jfree.report.namespaces.oasis-compat-smil.Uri=urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0
+org.jfree.report.namespaces.oasis-compat-smil.Default-Style=res://org/libreoffice/report/pentaho/smil.css
+org.jfree.report.namespaces.oasis-compat-smil.Prefix=svg
+
+org.jfree.report.namespaces.xsl-fo.Uri=http://www.w3.org/1999/XSL/Format
+org.jfree.report.namespaces.xsl-fo.Default-Style=res://org/libreoffice/report/pentaho/xsl-fo.css
+org.jfree.report.namespaces.xsl-fo.Prefix=fo
+
+org.jfree.report.namespaces.svg.Uri=http://www.w3.org/2000/svg
+org.jfree.report.namespaces.svg.Default-Style=res://org/libreoffice/report/pentaho/svg.css
+org.jfree.report.namespaces.svg.Prefix=svg
+org.jfree.report.namespaces.svg.ClassAttr=class
+org.jfree.report.namespaces.svg.StyleAttr=style
+
+org.jfree.report.namespaces.xml-xlink.Uri=http://www.w3.org/1999/xlink
+#org.jfree.report.namespaces.xml-xlink.Default-Style=res://org/libreoffice/report/pentaho/xml-xlink.css
+org.jfree.report.namespaces.xml-xlink.Prefix=xlink
+
+#
+# Tag-definition for the XML-writer.
+# Prefix is 'org.libreoffice.report.pentaho.output.'
+#
+# Declare the namespaces (this is independent of the ones defined above ..)
+# <prefix>"namespace."<ns-prefix>=<ns-uri>
+org.libreoffice.report.pentaho.output.namespace.oasis-text=urn:oasis:names:tc:opendocument:xmlns:text:1.0
+org.libreoffice.report.pentaho.output.default.oasis-text=deny
+
+org.libreoffice.report.pentaho.output.namespace.oasis-config=urn:oasis:names:tc:opendocument:xmlns:config:1.0
+org.libreoffice.report.pentaho.output.default.oasis-config=allow
+
+#
+# Next define the tags for which we want to customize the indent-behaviour
+org.libreoffice.report.pentaho.output.tag.oasis-text.p=deny
+org.libreoffice.report.pentaho.output.tag.oasis-text.section=allow
+org.libreoffice.report.pentaho.output.tag.oasis-text.variable-decls=allow
+org.libreoffice.report.pentaho.output.tag.oasis-text.variable-decl=allow
+
+org.libreoffice.report.pentaho.output.tag.oasis-config.config-item=deny
+
+org.libreoffice.report.pentaho.output.namespace.oasis-data=urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0
+org.libreoffice.report.pentaho.output.default.oasis-data=allow
+org.libreoffice.report.pentaho.output.tag.oasis-data.text=deny
+org.libreoffice.report.pentaho.output.tag.oasis-data.currency-symbol=deny
+org.libreoffice.report.pentaho.output.tag.oasis-data.embedded-text=deny
+
+org.libreoffice.report.pentaho.output.namespace.oasis-draw=urn:oasis:names:tc:opendocument:xmlns:drawing:1.0
+org.libreoffice.report.pentaho.output.default.oasis-draw=deny
+
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.FixedTextElement=org.libreoffice.report.pentaho.layoutprocessor.FixedTextLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.FormattedTextElement=org.libreoffice.report.pentaho.layoutprocessor.FormattedTextLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.ObjectOleElement=org.libreoffice.report.pentaho.layoutprocessor.ObjectOleLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.ImageElement=org.libreoffice.report.pentaho.layoutprocessor.ImageElementLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.TableCellElement=org.libreoffice.report.pentaho.layoutprocessor.TableCellLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.OfficeReport=org.libreoffice.report.pentaho.layoutprocessor.OfficeReportLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.OfficeGroup=org.libreoffice.report.pentaho.layoutprocessor.OfficeGroupLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.OfficeGroupSection=org.libreoffice.report.pentaho.layoutprocessor.OfficeGroupSectionLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.VariablesDeclarationSection=org.libreoffice.report.pentaho.layoutprocessor.VariablesDeclarationLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.OfficeDetailSection=org.libreoffice.report.pentaho.layoutprocessor.OfficeDetailLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.OfficeTableSection=org.libreoffice.report.pentaho.layoutprocessor.OfficeTableLayoutController
+org.jfree.report.flow.structure.org.libreoffice.report.pentaho.model.OfficeGroupInstanceSection=org.libreoffice.report.pentaho.layoutprocessor.OfficeGroupInstanceSectionLayoutController
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/expressions/SumExpression.java b/reportbuilder/java/org/libreoffice/report/pentaho/expressions/SumExpression.java
new file mode 100644
index 000000000..531fe440e
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/expressions/SumExpression.java
@@ -0,0 +1,23 @@
+/*
+ * 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.expressions;
+
+public class SumExpression
+{
+
+}
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");
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/loader/InputRepositoryLoader.java b/reportbuilder/java/org/libreoffice/report/pentaho/loader/InputRepositoryLoader.java
new file mode 100644
index 000000000..b57930502
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/loader/InputRepositoryLoader.java
@@ -0,0 +1,162 @@
+/*
+ * 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.loader;
+
+import org.libreoffice.report.InputRepository;
+
+import java.net.URL;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.pentaho.reporting.libraries.resourceloader.ResourceData;
+import org.pentaho.reporting.libraries.resourceloader.ResourceException;
+import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
+import org.pentaho.reporting.libraries.resourceloader.ResourceKeyCreationException;
+import org.pentaho.reporting.libraries.resourceloader.ResourceLoader;
+import org.pentaho.reporting.libraries.resourceloader.ResourceLoadingException;
+import org.pentaho.reporting.libraries.resourceloader.loader.LoaderUtils;
+
+
+public class InputRepositoryLoader implements ResourceLoader
+{
+
+ private final InputRepository inputRepository;
+
+ public InputRepositoryLoader(final InputRepository inputRepository)
+ {
+ if (inputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ this.inputRepository = inputRepository;
+ }
+
+ /**
+ * Checks, whether this resource loader implementation was responsible for
+ * creating this key.
+ */
+ public boolean isSupportedKey(final ResourceKey key)
+ {
+ return InputRepositoryLoader.class.getName().equals(key.getSchema());
+ }
+
+ /**
+ * Creates a new resource key from the given object and the factory keys.
+ *
+ * @return the created key or null, if the format was not recognized.
+ * @throws ResourceKeyCreationException if creating the key failed.
+ */
+ public ResourceKey createKey(final Object value,
+ final Map factoryKeys)
+ throws ResourceKeyCreationException
+ {
+ if (value instanceof String)
+ {
+ final String strVal = (String) value;
+ if (strVal.startsWith("sun:oo://"))
+ {
+ return new ResourceKey(InputRepositoryLoader.class.getName(),
+ new InputResourceKey(inputRepository.getId(), strVal), factoryKeys);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Derives a new resource key from the given key. If neither a path nor new
+ * factory-keys are given, the parent key is returned.
+ *
+ * @param parent the parent
+ * @param path the derived path (can be null).
+ * @param factoryKeys the optional factory keys (can be null).
+ * @return the derived key.
+ * @throws ResourceKeyCreationException
+ * if the key cannot be derived for any reason.
+ */
+ @SuppressWarnings("unchecked")
+ public ResourceKey deriveKey(final ResourceKey parent,
+ final String path,
+ final Map factoryKeys)
+ throws ResourceKeyCreationException
+ {
+ if (!isSupportedKey(parent))
+ {
+ throw new ResourceKeyCreationException("Assertion: Unsupported parent key type");
+ }
+
+ final InputResourceKey parentKey = (InputResourceKey) parent.getIdentifier();
+ final String resource;
+ if (path.startsWith("sun:oo://"))
+ {
+ resource = path;
+ }
+ else if (path.charAt(0) == '/')
+ {
+ resource = "sun:oo:/" + path;
+ }
+ else
+ {
+ resource = LoaderUtils.mergePaths(parentKey.getPath(), path);
+ }
+ final Map map;
+ if (factoryKeys != null)
+ {
+ map = new HashMap();
+ map.putAll(parent.getFactoryParameters());
+ map.putAll(factoryKeys);
+ }
+ else
+ {
+ map = parent.getFactoryParameters();
+ }
+ return new ResourceKey(parent.getSchema(),
+ new InputResourceKey(parentKey.getInputRepositoryId(), resource), map);
+ }
+
+ public URL toURL(final ResourceKey key)
+ {
+ return null;
+ }
+
+ public ResourceData load(final ResourceKey key)
+ throws ResourceLoadingException
+ {
+ if (!isSupportedKey(key))
+ {
+ throw new ResourceLoadingException("None of my keys.");
+ }
+
+ return new InputRepositoryResourceData(key, inputRepository);
+ }
+
+ public boolean isSupportedDeserializer(String string)
+ {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String serialize(ResourceKey rk, ResourceKey rk1) throws ResourceException
+ {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public ResourceKey deserialize(ResourceKey rk, String string) throws ResourceKeyCreationException
+ {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/loader/InputRepositoryResourceData.java b/reportbuilder/java/org/libreoffice/report/pentaho/loader/InputRepositoryResourceData.java
new file mode 100644
index 000000000..dd2b48068
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/loader/InputRepositoryResourceData.java
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package org.libreoffice.report.pentaho.loader;
+
+import org.libreoffice.report.InputRepository;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
+import org.pentaho.reporting.libraries.resourceloader.ResourceLoadingException;
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+import org.pentaho.reporting.libraries.resourceloader.loader.AbstractResourceData;
+
+
+public class InputRepositoryResourceData extends AbstractResourceData
+{
+
+ private final InputRepository inputRepository;
+ private final ResourceKey key;
+ private final String resourceIdentifer;
+
+ public InputRepositoryResourceData(final ResourceKey key,
+ final InputRepository repository)
+ {
+ this.key = key;
+ this.inputRepository = repository;
+ final InputResourceKey rkey = (InputResourceKey) key.getIdentifier();
+ final String identifier = rkey.getPath();
+ this.resourceIdentifer = identifier.substring("sun:oo://".length());
+ }
+
+ public Object getAttribute(final String key)
+ {
+ // we don't support attributes here ..
+ return null;
+ }
+
+ public ResourceKey getKey()
+ {
+ return key;
+ }
+
+ public InputStream getResourceAsStream(final ResourceManager caller)
+ throws ResourceLoadingException
+ {
+ try
+ {
+ return inputRepository.createInputStream(resourceIdentifer);
+ }
+ catch (IOException e)
+ {
+ throw new ResourceLoadingException("Failed to create input stream for " + resourceIdentifer, e);
+ }
+ }
+
+ public long getVersion(final ResourceManager caller)
+ {
+ return inputRepository.getVersion(resourceIdentifer);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/loader/InputResourceKey.java b/reportbuilder/java/org/libreoffice/report/pentaho/loader/InputResourceKey.java
new file mode 100644
index 000000000..c0ddbe453
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/loader/InputResourceKey.java
@@ -0,0 +1,54 @@
+/*
+ * 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.loader;
+
+import java.io.Serializable;
+
+/**
+ * Creation-Date: Feb 22, 2007, 8:51:42 PM
+ *
+ */
+public class InputResourceKey implements Serializable
+{
+
+ private static final long serialVersionUID = 2819901838705793075L;
+ private final Object inputRepositoryId;
+ private final String path;
+
+ public InputResourceKey(final Object inputRepositoryId, final String path)
+ {
+ this.inputRepositoryId = inputRepositoryId;
+ this.path = path;
+ }
+
+ public Object getInputRepositoryId()
+ {
+ return inputRepositoryId;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "InputResourceKey{" + "inputRepositoryId=" + inputRepositoryId + ", path='" + path + '\'' + '}';
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/DataStyle.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/DataStyle.java
new file mode 100644
index 000000000..38b6aada4
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/DataStyle.java
@@ -0,0 +1,37 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.structure.Section;
+
+/**
+ * Represents an automatic or manual data style definition.
+ *
+ * @since 02.03.2007
+ */
+public class DataStyle extends Section
+{
+
+ public String getStyleName()
+ {
+ return (String) getAttribute(OfficeNamespaces.STYLE_NS, "name");
+ }
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/FixedTextElement.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/FixedTextElement.java
new file mode 100644
index 000000000..45145b7cf
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/FixedTextElement.java
@@ -0,0 +1,42 @@
+/*
+ * 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.model;
+
+import org.jfree.report.structure.Section;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 02.03.2007
+ */
+public class FixedTextElement extends ReportElement
+{
+
+ private final Section content;
+
+ public FixedTextElement()
+ {
+ content = new Section();
+ content.setVirtual(true);
+ }
+
+ public Section getContent()
+ {
+ return content;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/FontFaceDeclsSection.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/FontFaceDeclsSection.java
new file mode 100644
index 000000000..b4e4bd1d5
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/FontFaceDeclsSection.java
@@ -0,0 +1,64 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jfree.report.structure.Element;
+
+
+/**
+ * Todo: Document me!
+ *
+ * @since 13.03.2007
+ */
+public class FontFaceDeclsSection extends Element
+{
+
+ private final Map<String,FontFaceElement> fontFaces;
+
+ public FontFaceDeclsSection()
+ {
+ fontFaces = new HashMap<String,FontFaceElement>();
+ setType("font-face-decls");
+ setNamespace(OfficeNamespaces.OFFICE_NS);
+ }
+
+ public void addFontFace(final FontFaceElement style)
+ {
+ fontFaces.put(style.getStyleName(), style);
+ }
+
+ public FontFaceElement getFontFace(final String name)
+ {
+ return fontFaces.get(name);
+ }
+
+ public FontFaceElement[] getAllFontFaces()
+ {
+ return fontFaces.values().toArray(new FontFaceElement[fontFaces.size()]);
+ }
+
+ public boolean containsFont(final String fontName)
+ {
+ return fontFaces.containsKey(fontName);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/FontFaceElement.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/FontFaceElement.java
new file mode 100644
index 000000000..93d9399dd
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/FontFaceElement.java
@@ -0,0 +1,37 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.structure.Section;
+
+/**
+ * Represents an automatic or manual data style definition.
+ *
+ * @since 02.03.2007
+ */
+public class FontFaceElement extends Section
+{
+
+ public String getStyleName()
+ {
+ return (String) getAttribute(OfficeNamespaces.STYLE_NS, "name");
+ }
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/FormatCondition.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/FormatCondition.java
new file mode 100644
index 000000000..32ca96eef
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/FormatCondition.java
@@ -0,0 +1,57 @@
+/*
+ * 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.model;
+
+import org.jfree.report.expressions.FormulaExpression;
+
+/**
+ * The format condition defines, what style-format is applied to an element.
+ *
+ * @since 02.03.2007
+ */
+public class FormatCondition
+{
+
+ private final FormulaExpression formula;
+ private final String styleName;
+ private final boolean enabled;
+
+ public FormatCondition(final FormulaExpression formula,
+ final String styleName,
+ final boolean enabled)
+ {
+ this.formula = formula;
+ this.styleName = styleName;
+ this.enabled = enabled;
+ }
+
+ public FormulaExpression getFormula()
+ {
+ return formula;
+ }
+
+ public String getStyleName()
+ {
+ return styleName;
+ }
+
+ public boolean isEnabled()
+ {
+ return enabled;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/FormattedTextElement.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/FormattedTextElement.java
new file mode 100644
index 000000000..b6cb58ebc
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/FormattedTextElement.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.model;
+
+import org.jfree.report.expressions.FormulaExpression;
+
+/**
+ * A formatted text element takes a formula, evaluates it and formats the
+ * given element using some arbitrary style. (As this is totally undocumented,
+ * we leave this out for now. Either we'll insert a field there or we call
+ * a UNO-component to do the formatting.
+ *
+ * @since 02.03.2007
+ */
+public class FormattedTextElement extends ReportElement
+{
+
+ private FormulaExpression valueExpression;
+
+ public FormulaExpression getValueExpression()
+ {
+ return valueExpression;
+ }
+
+ public void setValueExpression(final FormulaExpression valueExpression)
+ {
+ this.valueExpression = valueExpression;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/ImageElement.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/ImageElement.java
new file mode 100644
index 000000000..fe29bd6f5
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/ImageElement.java
@@ -0,0 +1,68 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.expressions.FormulaExpression;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 02.03.2007
+ */
+public class ImageElement extends ReportElement
+{
+
+ private FormulaExpression formula;
+
+ public FormulaExpression getFormula()
+ {
+ return formula;
+ }
+
+ public void setFormula(final FormulaExpression formula)
+ {
+ this.formula = formula;
+ }
+
+ public String getScaleMode()
+ {
+ String val = (String) getAttribute(OfficeNamespaces.OOREPORT_NS, OfficeToken.SCALE);
+ if (OfficeToken.TRUE.equals(val))
+ {
+ val = OfficeToken.ANISOTROPIC;
+ }
+ else if (OfficeToken.FALSE.equals(val) || val == null)
+ {
+ val = OfficeToken.NONE;
+ }
+ return val;
+ }
+
+ public boolean isPreserveIRI()
+ {
+ return OfficeToken.TRUE.equals(getAttribute(OfficeNamespaces.OOREPORT_NS, OfficeToken.PRESERVE_IRI));
+ }
+
+ public String getImageData()
+ {
+ return (String) getAttribute(OfficeNamespaces.FORM_NS, OfficeToken.IMAGE_DATA);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/ObjectOleElement.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/ObjectOleElement.java
new file mode 100644
index 000000000..ddd74bd8b
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/ObjectOleElement.java
@@ -0,0 +1,75 @@
+/*
+ * 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.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ObjectOleElement extends ReportElement
+{
+
+ private String url;
+ private final List<String> masterfields;
+ private final List<String> detailfields;
+ private String classid;
+
+ public ObjectOleElement()
+ {
+ masterfields = new ArrayList<String>();
+ detailfields = new ArrayList<String>();
+ }
+
+ public String getClassid()
+ {
+ return classid;
+ }
+
+ public List<String> getDetailfields()
+ {
+ return detailfields;
+ }
+
+ public List<String> getMasterfields()
+ {
+ return masterfields;
+ }
+
+ public String getUrl()
+ {
+ return url;
+ }
+
+ public void setClassId(final String classid)
+ {
+ this.classid = classid;
+ }
+
+ public void setUrl(final String _url)
+ {
+ url = _url;
+ }
+
+ public void addMasterDetailFields(final String master, final String detail)
+ {
+ if (master != null)
+ {
+ masterfields.add(master);
+ detailfields.add(detail == null ? master : detail);
+ }
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeDetailSection.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeDetailSection.java
new file mode 100644
index 000000000..aaf8f7d95
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeDetailSection.java
@@ -0,0 +1,30 @@
+/*
+ * 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.model;
+
+import org.jfree.report.structure.DetailSection;
+
+/**
+ * A Marker-Class.
+ *
+ * @since 02.03.2007
+ */
+public class OfficeDetailSection extends DetailSection
+{
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeDocument.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeDocument.java
new file mode 100644
index 000000000..e7da21583
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeDocument.java
@@ -0,0 +1,59 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.JobProperties;
+
+import org.jfree.report.JFreeReport;
+
+/**
+ * An office document represents the root of the report processing. In
+ * OpenOffice reports, this is the only child of the report object.
+ *
+ * @since 02.03.2007
+ */
+public class OfficeDocument extends JFreeReport
+{
+
+ private OfficeStylesCollection stylesCollection;
+ private JobProperties jobProperties;
+
+ public JobProperties getJobProperties()
+ {
+ return jobProperties;
+ }
+
+ public void setJobProperties(final JobProperties jobProperties)
+ {
+ this.jobProperties = jobProperties;
+ }
+
+ public OfficeStylesCollection getStylesCollection()
+ {
+ return stylesCollection;
+ }
+
+ public void setStylesCollection(final OfficeStylesCollection stylesCollection)
+ {
+ if (stylesCollection == null)
+ {
+ throw new NullPointerException();
+ }
+ this.stylesCollection = stylesCollection;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroup.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroup.java
new file mode 100644
index 000000000..e632cc938
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroup.java
@@ -0,0 +1,80 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.JFreeReportInfo;
+import org.jfree.report.expressions.Expression;
+import org.jfree.report.structure.Section;
+
+/**
+ * An office group is a virtual section that contains the group header, footer
+ * and either a detail section or another group.
+ *
+ * @since 02.03.2007
+ */
+public class OfficeGroup extends Section
+{
+
+ public OfficeGroupSection getHeader()
+ {
+ final OfficeGroupInstanceSection instanceSection =
+ (OfficeGroupInstanceSection) findFirstChild(JFreeReportInfo.REPORT_NAMESPACE, "group-instance");
+ if (instanceSection == null)
+ {
+ return null;
+ }
+ return (OfficeGroupSection) instanceSection.findFirstChild(OfficeNamespaces.OOREPORT_NS, "group-header");
+
+ }
+
+ public OfficeGroupSection getFooter()
+ {
+ final OfficeGroupInstanceSection instanceSection =
+ (OfficeGroupInstanceSection) findFirstChild(JFreeReportInfo.REPORT_NAMESPACE, "group-instance");
+ if (instanceSection == null)
+ {
+ return null;
+ }
+ return (OfficeGroupSection) instanceSection.findFirstChild(OfficeNamespaces.OOREPORT_NS, "group-footer");
+
+ }
+
+ public Expression getGroupingExpression()
+ {
+ final OfficeGroupInstanceSection instanceSection =
+ (OfficeGroupInstanceSection) findFirstChild(JFreeReportInfo.REPORT_NAMESPACE, "group-instance");
+ if (instanceSection == null)
+ {
+ return null;
+ }
+ return instanceSection.getGroupingExpression();
+ }
+
+ public String getSortingExpression()
+ {
+ final OfficeGroupInstanceSection instanceSection =
+ (OfficeGroupInstanceSection) findFirstChild(JFreeReportInfo.REPORT_NAMESPACE, "group-instance");
+ if (instanceSection == null)
+ {
+ return null;
+ }
+ return instanceSection.getSortingExpression();
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroupInstanceSection.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroupInstanceSection.java
new file mode 100644
index 000000000..cf8728f65
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroupInstanceSection.java
@@ -0,0 +1,42 @@
+/*
+ * 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.model;
+
+import org.jfree.report.structure.Group;
+
+/**
+ * Creation-Date: 25.07.2007, 14:41:54
+ *
+ */
+public class OfficeGroupInstanceSection extends Group
+{
+
+ private String sortingExpression;
+
+ public void setSortingExpression(String s)
+ {
+ sortingExpression=s;
+ }
+
+ public String getSortingExpression()
+ {
+ return sortingExpression;
+ }
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroupSection.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroupSection.java
new file mode 100644
index 000000000..d49c96064
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeGroupSection.java
@@ -0,0 +1,40 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.structure.Section;
+
+/**
+ * A group header or footer. If such a section is marked as sticky, it will be
+ * repeated on each new page.
+ *
+ * @since 02.03.2007
+ */
+public class OfficeGroupSection extends Section
+{
+
+ public boolean isRepeatSection()
+ {
+ final Object repeatFlag =
+ getAttribute(OfficeNamespaces.OOREPORT_NS, "repeat-section");
+ return OfficeToken.TRUE.equals(repeatFlag);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeMasterPage.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeMasterPage.java
new file mode 100644
index 000000000..43216f6b9
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeMasterPage.java
@@ -0,0 +1,52 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.structure.Section;
+
+/**
+ * A master page. A master page can contain header and footer and is linked
+ * to a page-layout.
+ *
+ * @since 13.03.2007
+ */
+public class OfficeMasterPage extends Section
+{
+
+ public String getStyleName()
+ {
+ return (String) getAttribute(OfficeNamespaces.STYLE_NS, "name");
+ }
+
+ public void setStyleName(final String name)
+ {
+ setAttribute(OfficeNamespaces.STYLE_NS, "name", name);
+ }
+
+ public String getPageLayout()
+ {
+ return (String) getAttribute(OfficeNamespaces.STYLE_NS, "page-layout-name");
+ }
+
+ public void setPageLayout(final String name)
+ {
+ setAttribute(OfficeNamespaces.STYLE_NS, "page-layout-name", name);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeMasterStyles.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeMasterStyles.java
new file mode 100644
index 000000000..be42e9862
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeMasterStyles.java
@@ -0,0 +1,73 @@
+/*
+ * 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.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+
+/**
+ * The master-styles section can have either a master-page, handout-master
+ * or draw-layer-set. (The latter ones are ignored for the reporting purposes,
+ * they are PowerPoint related.)
+ *
+ * There is no documentation how the system selects a master-page if there is
+ * no master-page assigned to the paragraph. However, it seems as if the
+ * master-page called 'Standard' is used as initial default.
+ *
+ * @since 13.03.2007
+ */
+public class OfficeMasterStyles extends Element
+{
+
+ private final Map<String,OfficeMasterPage> masterPages;
+ private final Section otherNodes;
+
+ public OfficeMasterStyles()
+ {
+ masterPages = new HashMap<String,OfficeMasterPage>();
+ otherNodes = new Section();
+ }
+
+ public void addMasterPage(final OfficeMasterPage masterPage)
+ {
+ if (masterPage == null)
+ {
+ throw new NullPointerException();
+ }
+ this.masterPages.put(masterPage.getStyleName(), masterPage);
+ }
+
+ public OfficeMasterPage getMasterPage(final String name)
+ {
+ return masterPages.get(name);
+ }
+
+ public OfficeMasterPage[] getAllMasterPages()
+ {
+ return masterPages.values().toArray(new OfficeMasterPage[masterPages.size()]);
+ }
+
+ public Section getOtherNodes()
+ {
+ return otherNodes;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeReport.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeReport.java
new file mode 100644
index 000000000..e9ba60f6d
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeReport.java
@@ -0,0 +1,122 @@
+/*
+ * 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.model;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Node;
+
+/**
+ * A office report is an ordered section. It contains several root-level bands
+ * which need to be processed in a given order.
+ *
+ * A report can have named expression attached. These expressions will be
+ * computed at the global scope and will be available for all child elements.
+ *
+ * @since 02.03.2007
+ */
+public class OfficeReport extends Element
+{
+
+ private Node pageHeader;
+ private Node pageFooter;
+ private Node reportHeader;
+ private Node reportFooter;
+ private Node bodySection;
+ private Node preBodySection;
+ private Node postBodySection;
+
+ public Node getPostBodySection()
+ {
+ return postBodySection;
+ }
+
+ public void setPostBodySection(final Node postBodySection)
+ {
+ this.postBodySection = postBodySection;
+ }
+
+ public Node getPreBodySection()
+ {
+ return preBodySection;
+ }
+
+ public void setPreBodySection(final Node preBodySection)
+ {
+ this.preBodySection = preBodySection;
+ }
+
+ public Node getPageHeader()
+ {
+ return pageHeader;
+ }
+
+ public void setPageHeader(final Node pageHeader)
+ {
+ this.pageHeader = pageHeader;
+ }
+
+ public Node getPageFooter()
+ {
+ return pageFooter;
+ }
+
+ public void setPageFooter(final Node pageFooter)
+ {
+ this.pageFooter = pageFooter;
+ }
+
+ public Node getColumnHeader()
+ {
+ return null;
+ }
+
+ public Node getColumnFooter()
+ {
+ return null;
+ }
+
+ public Node getReportHeader()
+ {
+ return reportHeader;
+ }
+
+ public void setReportHeader(final Node reportHeader)
+ {
+ this.reportHeader = reportHeader;
+ }
+
+ public Node getReportFooter()
+ {
+ return reportFooter;
+ }
+
+ public void setReportFooter(final Node reportFooter)
+ {
+ this.reportFooter = reportFooter;
+ }
+
+ public Node getBodySection()
+ {
+ return bodySection;
+ }
+
+ public void setBodySection(final Node bodySection)
+ {
+ this.bodySection = bodySection;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStyle.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStyle.java
new file mode 100644
index 000000000..e5fdf1378
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStyle.java
@@ -0,0 +1,104 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+/**
+ * Represents an automatic or manual style definition.
+ *
+ * @since 02.03.2007
+ */
+public class OfficeStyle extends Section
+{
+
+ public OfficeStyle()
+ {
+ setNamespace(OfficeNamespaces.STYLE_NS);
+ setType("style");
+ }
+
+ public String getStyleName()
+ {
+ return (String) getAttribute(OfficeNamespaces.STYLE_NS, "name");
+ }
+
+ public void setStyleName(final String name)
+ {
+ setAttribute(OfficeNamespaces.STYLE_NS, "name", name);
+ }
+
+ /**
+ * A parent style name must be a common style (it cannot be an automatic
+ * style) and has to exist. If no parent style is given, an implementation
+ * specific default style is used.
+ */
+ public String getStyleParent()
+ {
+ return (String) getAttribute(OfficeNamespaces.STYLE_NS, "parent-style-name");
+ }
+
+ public void setStyleParent(final String parentName)
+ {
+ setAttribute(OfficeNamespaces.STYLE_NS, "parent-style-name", parentName);
+ }
+
+ public String getStyleFamily()
+ {
+ return (String) getAttribute(OfficeNamespaces.STYLE_NS, "family");
+ }
+
+ public void setStyleFamily(final String family)
+ {
+ setAttribute(OfficeNamespaces.STYLE_NS, "family", family);
+ }
+
+ public Element getParagraphProperties()
+ {
+ return findFirstChild(OfficeNamespaces.STYLE_NS, "paragraph-properties");
+ }
+
+ public Element getTextProperties()
+ {
+ return findFirstChild(OfficeNamespaces.STYLE_NS, "text-properties");
+ }
+
+ public Element getTableRowProperties()
+ {
+ return findFirstChild(OfficeNamespaces.STYLE_NS, "table-row-properties");
+ }
+
+ public Element getTableColumnProperties()
+ {
+ return findFirstChild(OfficeNamespaces.STYLE_NS, "table-column-properties");
+ }
+
+ public Element getTableCellProperties()
+ {
+ return findFirstChild(OfficeNamespaces.STYLE_NS, "table-cell-properties");
+ }
+
+ public Element getGraphicProperties()
+ {
+ return findFirstChild(OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStyles.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStyles.java
new file mode 100644
index 000000000..3844a0ba2
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStyles.java
@@ -0,0 +1,180 @@
+/*
+ * 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.model;
+
+import java.io.Serializable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jfree.report.structure.Element;
+
+
+/**
+ * Holds one style type, either an automatic, common or master style. This is a
+ * marker container that defines the nature of the styles contained within this
+ * container. (Yeah, it is awkward, but that's how the document model describes
+ * it.)
+ *
+ * The style family can be one of paragraph, text, section, table, table-column,
+ * table-row, table-cell, table-page, chart, default, drawing-page, graphic,
+ * presentation, control and ruby.
+ *
+ * @since 07.03.2007
+ */
+public class OfficeStyles extends Element
+{
+
+ private static class StyleKey implements Serializable
+ {
+
+ private static final long serialVersionUID = 4931878927362887477L;
+ private final String family;
+ private final String name;
+
+ private StyleKey(final String family, final String name)
+ {
+ if (family == null)
+ {
+ throw new NullPointerException();
+ }
+ this.family = family;
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(final Object obj)
+ {
+ if (this != obj)
+ {
+ if (obj == null || getClass() != obj.getClass())
+ {
+ return false;
+ }
+
+ final StyleKey styleKey = (StyleKey) obj;
+
+ if (!family.equals(styleKey.family) || (name != null ? !name.equals(styleKey.name) : styleKey.name != null))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = family.hashCode();
+ result = 31 * result + (name != null ? name.hashCode() : 0);
+ return result;
+ }
+ }
+ private final Map<String,PageLayout> pageStyles;
+ private final Map<String,DataStyle> dataStyles;
+ private final Map<StyleKey,OfficeStyle> styles;
+ private final List<Element> otherChildren;
+
+ public OfficeStyles()
+ {
+ this.styles = new HashMap<StyleKey,OfficeStyle>();
+ this.dataStyles = new HashMap<String,DataStyle>();
+ this.pageStyles = new HashMap<String,PageLayout>();
+ this.otherChildren = new ArrayList<Element>();
+ }
+
+ public OfficeStyle getStyle(final String family, final String name)
+ {
+ return styles.get(new StyleKey(family, name));
+ }
+
+ public void addStyle(final OfficeStyle style)
+ {
+ if (style == null)
+ {
+ throw new NullPointerException();
+ }
+ final String styleFamily = style.getStyleFamily();
+ if (styleFamily == null)
+ {
+ throw new NullPointerException();
+ }
+ if (style.getStyleName() == null)
+ {
+ throw new NullPointerException();
+ }
+ styles.put(new StyleKey(styleFamily, style.getStyleName()), style);
+ }
+
+ public void addPageStyle(final PageLayout style)
+ {
+ pageStyles.put(style.getStyleName(), style);
+ }
+
+ public PageLayout getPageStyle(final String name)
+ {
+ return pageStyles.get(name);
+ }
+
+ public void addDataStyle(final DataStyle style)
+ {
+ dataStyles.put(style.getStyleName(), style);
+ }
+
+ public DataStyle getDataStyle(final String name)
+ {
+ return dataStyles.get(name);
+ }
+
+ public void addOtherNode(final Element node)
+ {
+ otherChildren.add(node);
+ }
+
+ public DataStyle[] getAllDataStyles()
+ {
+ return dataStyles.values().toArray(new DataStyle[dataStyles.size()]);
+ }
+
+ public PageLayout[] getAllPageStyles()
+ {
+ return pageStyles.values().toArray(new PageLayout[pageStyles.size()]);
+ }
+
+ public OfficeStyle[] getAllStyles()
+ {
+ return styles.values().toArray(new OfficeStyle[styles.size()]);
+ }
+
+ public Element[] getOtherStyles()
+ {
+ return otherChildren.toArray(new Element[otherChildren.size()]);
+ }
+
+ public boolean containsStyle(final String family, final String name)
+ {
+ return styles.containsKey(new StyleKey(family, name));
+ }
+
+ public boolean containsDataStyle(final String styleName)
+ {
+ return dataStyles.containsKey(styleName);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStylesCollection.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStylesCollection.java
new file mode 100644
index 000000000..eee9ad553
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeStylesCollection.java
@@ -0,0 +1,113 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.structure.Element;
+
+/**
+ * Holds all style-definitions and provides some simplified lookup methods to
+ * grab them by their type and name.
+ *
+ * <p>For now, we are only interested in 'style:style' nodes. Each of these nodes
+ * has a style-name and a style-family. Each style declaration can have a parent
+ * style, from which properties are inherited.</p>
+ *
+ * <p>Style names are unique within the family, no matter whether the style is an
+ * automatic style, a common style or a master style.</p>
+ *
+ * <p>The contents of this element are the union of the 'styles.xml' file (if it
+ * exists), the font-declarations and auto-styles of the document-content.xml
+ * and the styles declared in the main document.</p>
+ *
+ * @since 06.03.2007
+ */
+public class OfficeStylesCollection extends Element
+{
+ // Font-face declarations are copied as is. We simply merge them by adding
+ // them all in one set. This may result in duplicate entries, but as the
+ // fileformat does not forbid that, it therefore must be ok.
+
+ private final FontFaceDeclsSection fontFaceDecls;
+ private final OfficeStyles automaticStyles;
+ private final OfficeStyles commonStyles;
+ private final OfficeMasterStyles masterStyles;
+
+ public OfficeStylesCollection()
+ {
+ fontFaceDecls = new FontFaceDeclsSection();
+
+ automaticStyles = new OfficeStyles();
+ automaticStyles.setType("automatic-styles");
+ automaticStyles.setNamespace(OfficeNamespaces.OFFICE_NS);
+
+ commonStyles = new OfficeStyles();
+ commonStyles.setType("styles");
+ commonStyles.setNamespace(OfficeNamespaces.OFFICE_NS);
+
+ masterStyles = new OfficeMasterStyles();
+ masterStyles.setType("master-styles");
+ masterStyles.setNamespace(OfficeNamespaces.OFFICE_NS);
+ }
+
+ public OfficeStyle getStyle(final String family, final String name)
+ {
+ final OfficeStyle commonStyle = commonStyles.getStyle(family, name);
+ if (commonStyle != null)
+ {
+ return commonStyle;
+ }
+ final OfficeStyle autoStyle = automaticStyles.getStyle(family, name);
+ if (autoStyle != null)
+ {
+ return autoStyle;
+ }
+
+ // And later: Autogenerate one of the default styles.
+ // However, at this moment, we don't have a clue about the default styles
+ // at all. Maybe we should add them to make this implementation more robust
+ // against invalid documents.
+ return null;
+ }
+
+ public boolean containsStyle(final String family, final String name)
+ {
+ return (getStyle(family, name) != null);
+ }
+
+ public OfficeStyles getAutomaticStyles()
+ {
+ return automaticStyles;
+ }
+
+ public OfficeStyles getCommonStyles()
+ {
+ return commonStyles;
+ }
+
+ public OfficeMasterStyles getMasterStyles()
+ {
+ return masterStyles;
+ }
+
+ public FontFaceDeclsSection getFontFaceDecls()
+ {
+ return fontFaceDecls;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeTableSection.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeTableSection.java
new file mode 100644
index 000000000..821fb3b89
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/OfficeTableSection.java
@@ -0,0 +1,29 @@
+/*
+ * 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.model;
+
+import org.jfree.report.structure.Section;
+
+/**
+ * Creation-Date: 24.04.2007, 15:55:17
+ *
+ */
+public class OfficeTableSection extends Section
+{
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/PageLayout.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/PageLayout.java
new file mode 100644
index 000000000..8ef007c7e
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/PageLayout.java
@@ -0,0 +1,58 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.structure.Section;
+
+/**
+ * A page layout describes the physical properties of a page. It is equal to
+ * an @page rule in CSS.
+ *
+ * @since 13.03.2007
+ */
+public class PageLayout extends Section
+{
+
+ public PageLayout()
+ {
+ setNamespace(OfficeNamespaces.STYLE_NS);
+ setType("page-layout");
+ }
+
+ public String getStyleName()
+ {
+ return (String) getAttribute(OfficeNamespaces.STYLE_NS, "name");
+ }
+
+ public void setStyleName(final String name)
+ {
+ setAttribute(OfficeNamespaces.STYLE_NS, "name", name);
+ }
+
+ public Section getHeaderStyle()
+ {
+ return (Section) findFirstChild(OfficeNamespaces.STYLE_NS, "header-style");
+ }
+
+ public Section getFooterStyle()
+ {
+ return (Section) findFirstChild(OfficeNamespaces.STYLE_NS, "footer-style");
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/PageSection.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/PageSection.java
new file mode 100644
index 000000000..732339705
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/PageSection.java
@@ -0,0 +1,46 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.layouting.util.AttributeMap;
+import org.jfree.report.structure.Section;
+
+/**
+ * This represents either a page header or page footer.
+ *
+ * @since 02.03.2007
+ */
+public class PageSection extends Section
+{
+
+ private static final String NOT_WITH_REPORT_HEADER_NOR_FOOTER = "not-with-report-header-nor-footer";
+
+ public static boolean isPrintWithReportHeader(final AttributeMap attrs)
+ {
+ final String pagePrintOption = (String) attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "page-print-option");
+ return !("not-with-report-header".equals(pagePrintOption) || NOT_WITH_REPORT_HEADER_NOR_FOOTER.equals(pagePrintOption));
+ }
+
+ public static boolean isPrintWithReportFooter(final AttributeMap attrs)
+ {
+ final String pagePrintOption = (String) attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "page-print-option");
+ return !("not-with-report-footer".equals(pagePrintOption) || NOT_WITH_REPORT_HEADER_NOR_FOOTER.equals(pagePrintOption));
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/RawText.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/RawText.java
new file mode 100644
index 000000000..bebbb8637
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/RawText.java
@@ -0,0 +1,36 @@
+/*
+ * 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.model;
+
+import org.jfree.report.structure.StaticText;
+
+/**
+ * A marker implementation. If encountered by the OfficeRawTarget, this text
+ * will be written without being normalized. Such text represents a page
+ * header or footer.
+ *
+ * @since 13.03.2007
+ */
+public class RawText extends StaticText
+{
+
+ public RawText(final String text)
+ {
+ super(text);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/ReportElement.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/ReportElement.java
new file mode 100644
index 000000000..59dabe01d
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/ReportElement.java
@@ -0,0 +1,100 @@
+/*
+ * 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.model;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+
+
+/**
+ * A report element is the base class for all content generating elements in a
+ * report.
+ *
+ * @since 02.03.2007
+ */
+public abstract class ReportElement extends Element
+{
+
+ private final List<FormatCondition> formatConditions;
+
+ protected ReportElement()
+ {
+ formatConditions = new ArrayList<FormatCondition>();
+ }
+
+ /**
+ * Checks the current group and prints this element only if the current row is
+ * the first row for that particular group.
+ *
+ * @return true, if the element should only be printed in the first row of the
+ * current group, false otherwise.
+ */
+ public boolean isPrintWhenGroupChange()
+ {
+ return OfficeToken.TRUE.equals(getAttribute(OfficeNamespaces.OOREPORT_NS, "print-when-group-change"));
+ }
+
+ public void setPrintWhenGroupChange(final boolean printWhenGroupChange)
+ {
+ setAttribute(OfficeNamespaces.OOREPORT_NS, "print-when-group-change",
+ String.valueOf(printWhenGroupChange));
+ }
+
+ /**
+ * Checks, whether the printed value has been changed since the last run. The
+ * element will only be printed, if there was at least one change.
+ *
+ * @return true, if repeated values should be printed, false if repeated
+ * values should be suppressed.
+ */
+ public boolean isPrintRepeatedValues()
+ {
+ return OfficeToken.TRUE.equals(getAttribute(OfficeNamespaces.OOREPORT_NS, "print-repeated-values"));
+ }
+
+ public void setPrintRepeatedValues(final boolean printRepeatedValues)
+ {
+ setAttribute(OfficeNamespaces.OOREPORT_NS, "print-repeated-values",
+ String.valueOf(printRepeatedValues));
+ }
+
+ public void addFormatCondition(final FormatCondition formatCondition)
+ {
+ if (formatCondition == null)
+ {
+ throw new NullPointerException();
+ }
+
+ this.formatConditions.add(formatCondition);
+ }
+
+ public FormatCondition[] getFormatConditions()
+ {
+ return this.formatConditions.toArray(new FormatCondition[this.formatConditions.size()]);
+ }
+
+ public int getFormatConditionCount()
+ {
+ return formatConditions.size();
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/TableCellElement.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/TableCellElement.java
new file mode 100644
index 000000000..4acc89f39
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/TableCellElement.java
@@ -0,0 +1,30 @@
+/*
+ * 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.model;
+
+import org.jfree.report.structure.Section;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 05.03.2007
+ */
+public class TableCellElement extends Section
+{
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/model/VariablesDeclarationSection.java b/reportbuilder/java/org/libreoffice/report/pentaho/model/VariablesDeclarationSection.java
new file mode 100644
index 000000000..c42917653
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/model/VariablesDeclarationSection.java
@@ -0,0 +1,42 @@
+/*
+ * 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.model;
+
+import org.jfree.report.JFreeReportInfo;
+import org.jfree.report.structure.Section;
+
+/**
+ * A paragraph that contains variables-declarations. This paragraph will be
+ * printed in the first cell of the first table (if there's one).
+ *
+ * The VariablesDeclarationSection is an auto-generated structure element that
+ * has no model-representation. The section itself is empty and simply acts
+ * as flag for the output-processor. The output processor itself is responsible
+ * to maintain the variables.
+ *
+ * @since 19.03.2007
+ */
+public class VariablesDeclarationSection extends Section
+{
+
+ public VariablesDeclarationSection()
+ {
+ setNamespace(JFreeReportInfo.REPORT_NAMESPACE);
+ setType("variables-section");
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/module.properties b/reportbuilder/java/org/libreoffice/report/pentaho/module.properties
new file mode 100644
index 000000000..be552962a
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/module.properties
@@ -0,0 +1,36 @@
+#
+# 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 .
+#
+# x-no-translate
+
+
+module-info:
+ name: factory-report-sun
+ producer: The JFreeReport project - www.jfree.org/jfreereport
+ description: XML-Parsers for OpenOffice.org report definitions. These definitions\
+ are basically similar to the old JFreeReport format, with some limited absolute\
+ positioning capabilities.
+ version.major: 0
+ version.minor: 90
+ version.patchlevel: 0
+
+depends:
+ module: org.jfree.report.modules.factories.report.base.ReportFactoryBaseModule
+ version.major: 0
+ version.minor: 92
+ version.patchlevel: 0
+
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/oasis-datastyle.css b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-datastyle.css
new file mode 100644
index 000000000..6c94b1e05
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-datastyle.css
@@ -0,0 +1,23 @@
+/*
+ * 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 .
+ */
+
+@namespace url("urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0");
+
+/**
+ * All default styles for data-styles elements.
+*/
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/oasis-draw.css b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-draw.css
new file mode 100644
index 000000000..341f44ec5
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-draw.css
@@ -0,0 +1,5 @@
+@namespace url("urn:oasis:names:tc:opendocument:xmlns:drawing:1.0");
+
+/**
+ * All default styles for draw elements.
+*/
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/oasis-form.css b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-form.css
new file mode 100644
index 000000000..7c8c43008
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-form.css
@@ -0,0 +1,5 @@
+@namespace url("urn:oasis:names:tc:opendocument:xmlns:form:1.0");
+
+/**
+ * All default styles for form elements.
+*/
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/oasis-style.css b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-style.css
new file mode 100644
index 000000000..bca51bd6b
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-style.css
@@ -0,0 +1,28 @@
+/*
+ * 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 .
+ */
+
+@namespace url("urn:oasis:names:tc:opendocument:xmlns:style:1.0");
+
+/**
+ * All default styles for style elements. (They should not be visible anyway,
+ * but better be complete than be sorry afterwards.)
+*/
+
+raw-styles {
+ display:none;
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/oasis-table.css b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-table.css
new file mode 100644
index 000000000..80145880a
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-table.css
@@ -0,0 +1,55 @@
+/*
+ * 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 .
+ */
+
+@namespace url("urn:oasis:names:tc:opendocument:xmlns:table:1.0");
+
+table {
+ display: table;
+}
+
+table-columns {
+ display: table-column-group;
+}
+
+table-column {
+ display: table-column;
+}
+
+table-row {
+ display: table-row;
+}
+
+table-cell {
+ display: table-cell;
+}
+
+table-cell[number-cols-spanned],
+table-cell[number-cols-spanned],
+table-columns[number-cols-spanned],
+table-column[number-cols-spanned] {
+ -x-liblayout-colspan: attr(number-cols-spanned);
+}
+
+table-cell[number-rows-spanned],
+table-cell[number-rows-spanned] {
+ -x-liblayout-rowspan: attr(number-rows-spanned);
+}
+
+
+
+
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/oasis-text.css b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-text.css
new file mode 100644
index 000000000..fb85c3d1f
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/oasis-text.css
@@ -0,0 +1,27 @@
+/*
+ * 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 .
+ */
+
+@namespace url("urn:oasis:names:tc:opendocument:xmlns:text:1.0");
+
+/**
+ * All default styles for form elements.
+*/
+
+p {
+ display: block;
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/ImageProducer.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/ImageProducer.java
new file mode 100644
index 000000000..69995d7aa
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/ImageProducer.java
@@ -0,0 +1,483 @@
+/*
+ * 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.output;
+
+import com.sun.star.awt.Size;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.ReportExecutionException;
+import org.libreoffice.report.pentaho.DefaultNameGenerator;
+
+import java.awt.Image;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import java.sql.Blob;
+import java.sql.SQLException;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.jfree.layouting.input.style.values.CSSNumericType;
+import org.jfree.layouting.input.style.values.CSSNumericValue;
+
+import org.pentaho.reporting.libraries.base.util.IOUtils;
+import org.pentaho.reporting.libraries.base.util.PngEncoder;
+import org.pentaho.reporting.libraries.base.util.WaitingImageObserver;
+
+
+/**
+ * This class manages the images embedded in a report.
+ *
+ * @since 31.03.2007
+ */
+public class ImageProducer
+{
+
+ private static final Logger LOGGER = Logger.getLogger(ImageProducer.class.getName());
+
+ public static class OfficeImage
+ {
+
+ private final CSSNumericValue width;
+ private final CSSNumericValue height;
+ private final String embeddableLink;
+
+ private OfficeImage(final String embeddableLink, final CSSNumericValue width, final CSSNumericValue height)
+ {
+ this.embeddableLink = embeddableLink;
+ this.width = width;
+ this.height = height;
+ }
+
+ public CSSNumericValue getWidth()
+ {
+ return width;
+ }
+
+ public CSSNumericValue getHeight()
+ {
+ return height;
+ }
+
+ public String getEmbeddableLink()
+ {
+ return embeddableLink;
+ }
+ }
+
+ private static class ByteDataImageKey
+ {
+
+ private final byte[] keyData;
+ private Integer hashCode;
+
+ protected ByteDataImageKey(final byte[] keyData)
+ {
+ if (keyData == null)
+ {
+ throw new NullPointerException();
+ }
+ this.keyData = keyData;
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this != o)
+ {
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final ByteDataImageKey key = (ByteDataImageKey) o;
+ if (!Arrays.equals(keyData, key.keyData))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ if (hashCode != null)
+ {
+ return hashCode;
+ }
+
+ final int length = Math.min(keyData.length, 512);
+ int hashValue = 0;
+ for (int i = 0; i < length; i++)
+ {
+ final byte b = keyData[i];
+ hashValue = b + hashValue * 23;
+ }
+ this.hashCode = hashValue;
+ return hashValue;
+ }
+ }
+ private final Map<Object,OfficeImage> imageCache;
+ private final InputRepository inputRepository;
+ private final OutputRepository outputRepository;
+ private final ImageService imageService;
+
+ public ImageProducer(final InputRepository inputRepository,
+ final OutputRepository outputRepository,
+ final ImageService imageService)
+ {
+ if (inputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (outputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (imageService == null)
+ {
+ throw new NullPointerException();
+ }
+
+ this.inputRepository = inputRepository;
+ this.outputRepository = outputRepository;
+ this.imageService = imageService;
+ this.imageCache = new HashMap<Object,OfficeImage>();
+ }
+
+ /**
+ * Image-Data can be one of the following types: String, URL, URI, byte-array, blob.
+ */
+ public OfficeImage produceImage(final Object imageData,
+ final boolean preserveIRI)
+ {
+
+ LOGGER.config("Want to produce image " + imageData);
+ if (imageData instanceof String)
+ {
+ return produceFromString((String) imageData, preserveIRI);
+ }
+
+ if (imageData instanceof URL)
+ {
+ return produceFromURL((URL) imageData, preserveIRI);
+ }
+
+ if (imageData instanceof Blob)
+ {
+ return produceFromBlob((Blob) imageData);
+ }
+
+ if (imageData instanceof byte[])
+ {
+ return produceFromByteArray((byte[]) imageData);
+ }
+
+ if (imageData instanceof Image)
+ {
+ return produceFromImage((Image) imageData);
+ }
+ // not usable ..
+ return null;
+ }
+
+ private OfficeImage produceFromImage(final Image image)
+ {
+ // quick caching ... use a weak list ...
+ final WaitingImageObserver obs = new WaitingImageObserver(image);
+ obs.waitImageLoaded();
+
+ final PngEncoder encoder = new PngEncoder(image, PngEncoder.ENCODE_ALPHA, PngEncoder.FILTER_NONE, 5);
+ final byte[] data = encoder.pngEncode();
+ return produceFromByteArray(data);
+ }
+
+ private OfficeImage produceFromBlob(final Blob blob)
+ {
+ try
+ {
+ final InputStream inputStream = blob.getBinaryStream();
+ final int length = (int) blob.length();
+
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream(length);
+ try
+ {
+ IOUtils.getInstance().copyStreams(inputStream, bout);
+ } finally
+ {
+ inputStream.close();
+ }
+ return produceFromByteArray(bout.toByteArray());
+ }
+ catch (IOException e)
+ {
+ LOGGER.warning("Failed to produce image from Blob: " + e);
+ }
+ catch (SQLException e)
+ {
+ LOGGER.warning("Failed to produce image from Blob: " + e);
+ }
+ return null;
+ }
+
+ private OfficeImage produceFromByteArray(final byte[] data)
+ {
+ final ByteDataImageKey imageKey = new ByteDataImageKey(data);
+ final OfficeImage o = imageCache.get(imageKey);
+ if (o != null)
+ {
+ return o;
+ }
+
+ try
+ {
+ final String mimeType = imageService.getMimeType(data);
+ final Size dims = imageService.getImageSize(data);
+
+ // copy the image into the local output-storage
+ // todo: Implement data-fingerprinting so that we can detect the mime-type
+ final OutputRepository storage = outputRepository.openOutputRepository("Pictures", null);
+ final DefaultNameGenerator nameGenerator = new DefaultNameGenerator(storage);
+ final String name = nameGenerator.generateName("image", mimeType);
+ final OutputStream outputStream = storage.createOutputStream(name, mimeType);
+ final ByteArrayInputStream bin = new ByteArrayInputStream(data);
+
+ try
+ {
+ IOUtils.getInstance().copyStreams(bin, outputStream);
+ } finally
+ {
+ outputStream.close();
+ storage.closeOutputRepository();
+ }
+
+ final CSSNumericValue widthVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.Width / 100.0);
+ final CSSNumericValue heightVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.Height / 100.0);
+ final OfficeImage officeImage = new OfficeImage("Pictures/" + name, widthVal, heightVal);
+ imageCache.put(imageKey, officeImage);
+ return officeImage;
+ }
+ catch (IOException e)
+ {
+ LOGGER.warning("Failed to load image from local input-repository: " + e);
+ }
+ catch (ReportExecutionException e)
+ {
+ LOGGER.warning("Failed to create image from local input-repository: " + e);
+ }
+ return null;
+ }
+
+ private OfficeImage produceFromString(final String source,
+ final boolean preserveIRI)
+ {
+
+ try
+ {
+ final URL url = new URL(source);
+ return produceFromURL(url, preserveIRI);
+ }
+ catch (MalformedURLException e)
+ {
+ // ignore .. but we had to try this ..
+ }
+
+ final OfficeImage o = imageCache.get(source);
+ if (o != null)
+ {
+ return o;
+ }
+
+ // Next, check whether this is a local path.
+ if (inputRepository.isReadable(source))
+ {
+ // cool, the file exists. Let's try to read it.
+ try
+ {
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
+ final InputStream inputStream = inputRepository.createInputStream(source);
+ try
+ {
+ IOUtils.getInstance().copyStreams(inputStream, bout);
+ } finally
+ {
+ inputStream.close();
+ }
+ final byte[] data = bout.toByteArray();
+ final Size dims = imageService.getImageSize(data);
+ final String mimeType = imageService.getMimeType(data);
+
+ final CSSNumericValue widthVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.Width / 100.0);
+ final CSSNumericValue heightVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.Height / 100.0);
+
+ final String filename = copyToOutputRepository(mimeType, data);
+ final OfficeImage officeImage = new OfficeImage(filename, widthVal, heightVal);
+ imageCache.put(source, officeImage);
+ return officeImage;
+ }
+ catch (IOException e)
+ {
+ LOGGER.warning("Failed to load image from local input-repository: " + e);
+ }
+ catch (ReportExecutionException e)
+ {
+ LOGGER.warning("Failed to create image from local input-repository: " + e);
+ }
+ }
+ else
+ {
+ try
+ {
+ URI rootURI = new URI(inputRepository.getRootURL());
+ final URI uri = rootURI.resolve(source);
+ return produceFromURL(uri.toURL(), preserveIRI);
+ }
+ catch (URISyntaxException ex)
+ {
+ }
+ catch (MalformedURLException e)
+ {
+ // ignore .. but we had to try this ..
+ }
+ }
+
+ // Return the image as broken image instead ..
+ final OfficeImage officeImage = new OfficeImage(source, null, null);
+ imageCache.put(source, officeImage);
+ return officeImage;
+ }
+
+ private OfficeImage produceFromURL(final URL url,
+ final boolean preserveIRI)
+ {
+ final String urlString = url.toString();
+ URI uri = null;
+ try
+ {
+ uri = new URI(urlString);
+ }
+ catch (URISyntaxException ex)
+ {
+ Logger.getLogger(ImageProducer.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ final OfficeImage o = imageCache.get(uri);
+ if (o != null)
+ {
+ return o;
+ }
+
+ try
+ {
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
+ final URLConnection urlConnection = url.openConnection();
+ final InputStream inputStream = new BufferedInputStream(urlConnection.getInputStream());
+ try
+ {
+ IOUtils.getInstance().copyStreams(inputStream, bout);
+ } finally
+ {
+ inputStream.close();
+ }
+ final byte[] data = bout.toByteArray();
+
+ final Size dims = imageService.getImageSize(data);
+ final String mimeType = imageService.getMimeType(data);
+ final CSSNumericValue widthVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.Width / 100.0);
+ final CSSNumericValue heightVal = CSSNumericValue.createValue(CSSNumericType.MM, dims.Height / 100.0);
+
+ if (preserveIRI)
+ {
+ final OfficeImage retval = new OfficeImage(urlString, widthVal, heightVal);
+ imageCache.put(uri, retval);
+ return retval;
+ }
+
+ final String name = copyToOutputRepository(mimeType, data);
+ final OfficeImage officeImage = new OfficeImage(name, widthVal, heightVal);
+ imageCache.put(uri, officeImage);
+ return officeImage;
+ }
+ catch (IOException e)
+ {
+ LOGGER.warning("Failed to load image from local input-repository: " + e);
+ }
+ catch (ReportExecutionException e)
+ {
+ LOGGER.warning("Failed to create image from local input-repository: " + e);
+ }
+
+ if (!preserveIRI)
+ {
+ final OfficeImage image = new OfficeImage(urlString, null, null);
+ imageCache.put(uri, image);
+ return image;
+ }
+
+ // OK, everything failed; the image is not - repeat it - not usable.
+ return null;
+ }
+
+ private String copyToOutputRepository(final String urlMimeType, final byte[] data)
+ throws IOException, ReportExecutionException
+ {
+ final String mimeType;
+ if (urlMimeType == null)
+ {
+ mimeType = imageService.getMimeType(data);
+ }
+ else
+ {
+ mimeType = urlMimeType;
+ }
+
+ // copy the image into the local output-storage
+ final OutputRepository storage = outputRepository.openOutputRepository("Pictures", null);
+ final DefaultNameGenerator nameGenerator = new DefaultNameGenerator(storage);
+ final String name = nameGenerator.generateName("image", mimeType);
+ final OutputStream outputStream = storage.createOutputStream(name, mimeType);
+ final ByteArrayInputStream bin = new ByteArrayInputStream(data);
+
+ try
+ {
+ IOUtils.getInstance().copyStreams(bin, outputStream);
+ } finally
+ {
+ outputStream.close();
+ storage.closeOutputRepository();
+ }
+ return "Pictures/" + name;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/OfficeDocumentReportTarget.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/OfficeDocumentReportTarget.java
new file mode 100644
index 000000000..b73b5781b
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/OfficeDocumentReportTarget.java
@@ -0,0 +1,1692 @@
+/*
+ * 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.output;
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.ReportEngineParameterNames;
+import org.libreoffice.report.SDBCReportDataFactory;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.layoutprocessor.ImageElementContext;
+import org.libreoffice.report.pentaho.model.OfficeDocument;
+import org.libreoffice.report.pentaho.model.OfficeStyle;
+import org.libreoffice.report.pentaho.model.OfficeStyles;
+import org.libreoffice.report.pentaho.model.OfficeStylesCollection;
+import org.libreoffice.report.pentaho.styles.LengthCalculator;
+import org.libreoffice.report.pentaho.styles.StyleMapper;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+
+import java.awt.Image;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.io.InputStream;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+import org.jfree.layouting.input.style.parser.CSSValueFactory;
+import org.jfree.layouting.input.style.parser.StyleSheetParserUtil;
+import org.jfree.layouting.input.style.values.CSSNumericType;
+import org.jfree.layouting.input.style.values.CSSNumericValue;
+import org.jfree.layouting.layouter.style.CSSValueResolverUtility;
+import org.jfree.layouting.namespace.NamespaceDefinition;
+import org.jfree.layouting.namespace.Namespaces;
+import org.jfree.layouting.util.AttributeMap;
+import org.jfree.layouting.util.LazyAttributeMap;
+import org.jfree.report.DataFlags;
+import org.jfree.report.DataSourceException;
+import org.jfree.report.JFreeReportBoot;
+import org.jfree.report.JFreeReportInfo;
+import org.jfree.report.ReportProcessingException;
+import org.jfree.report.flow.AbstractReportTarget;
+import org.jfree.report.flow.ReportJob;
+import org.jfree.report.flow.ReportStructureRoot;
+import org.jfree.report.flow.ReportTargetUtil;
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+import org.jfree.report.util.AttributeNameGenerator;
+import org.jfree.report.util.IntegerCache;
+import org.jfree.report.util.MemoryByteArrayOutputStream;
+
+import org.pentaho.reporting.libraries.base.util.FastStack;
+import org.pentaho.reporting.libraries.base.util.IOUtils;
+import org.pentaho.reporting.libraries.resourceloader.ResourceException;
+import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+import org.pentaho.reporting.libraries.xmlns.common.AttributeList;
+import org.pentaho.reporting.libraries.xmlns.writer.DefaultTagDescription;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriter;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriterSupport;
+
+import org.w3c.css.sac.LexicalUnit;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 08.03.2007
+ */
+public abstract class OfficeDocumentReportTarget extends AbstractReportTarget
+{
+
+ protected static final Logger LOGGER = Logger.getLogger(OfficeDocumentReportTarget.class.getName());
+ public static final String HORIZONTAL_POS = "horizontal-pos";
+ public static final String TAG_DEF_PREFIX = "org.libreoffice.report.pentaho.output.";
+ private static final int ROLE_NONE = 0;
+ public static final int ROLE_REPORT_HEADER = 1;
+ public static final int ROLE_REPORT_FOOTER = 2;
+ public static final int ROLE_GROUP_HEADER = 3;
+ public static final int ROLE_GROUP_FOOTER = 4;
+ public static final int ROLE_REPEATING_GROUP_HEADER = 5;
+ public static final int ROLE_REPEATING_GROUP_FOOTER = 6;
+ public static final int ROLE_PAGE_HEADER = 7;
+ public static final int ROLE_PAGE_FOOTER = 8;
+ public static final int ROLE_DETAIL = 9;
+ public static final int ROLE_VARIABLES = 10;
+ public static final int ROLE_TEMPLATE = 11;
+ public static final int ROLE_SPREADSHEET_PAGE_HEADER = 12;
+ public static final int ROLE_SPREADSHEET_PAGE_FOOTER = 13;
+ private static final int STATE_IN_DOCUMENT = 0;
+ private static final int STATE_IN_BODY = 1;
+ private static final int STATE_IN_CONTENT = 2;
+ private static final int STATE_IN_GROUP = 3;
+ private static final int STATE_IN_GROUP_BODY = 4;
+ private static final int STATE_IN_SECTION = 5;
+ private static final int STATE_IN_OTHER = 6;
+ private static final int STATE_IN_GROUP_INSTANCE = 7;
+ public static final String FAILED = "Failed";
+ public static final String VERTICAL_POS = "vertical-pos";
+ private static final String ZERO_CM = "0cm";
+ /** the version of the ODF specification to which generated documents
+ * shall conform. */
+ public static final String ODF_VERSION = "1.2";
+
+ protected static class BufferState
+ {
+
+ private final XmlWriter xmlWriter;
+ private final MemoryByteArrayOutputStream xmlBuffer;
+ private final OfficeStylesCollection stylesCollection;
+
+ private BufferState(final XmlWriter xmlWriter,
+ final MemoryByteArrayOutputStream xmlBuffer,
+ final OfficeStylesCollection stylesCollection)
+ {
+ this.stylesCollection = stylesCollection;
+ this.xmlWriter = xmlWriter;
+ this.xmlBuffer = xmlBuffer;
+ }
+
+ public OfficeStylesCollection getStylesCollection()
+ {
+ return stylesCollection;
+ }
+
+ public XmlWriter getXmlWriter()
+ {
+ return xmlWriter;
+ }
+
+ public String getXmlBuffer() throws ReportProcessingException
+ {
+ try
+ {
+ final byte[] zippedData = xmlBuffer.getRaw();
+ final InputStreamReader reader = new InputStreamReader(new InflaterInputStream(new ByteArrayInputStream(zippedData, 0, xmlBuffer.getLength())), "UTF-16");
+ final StringWriter writer = new StringWriter((zippedData.length / 2) + 1);
+ IOUtils.getInstance().copyWriter(reader, writer);
+ return writer.toString();
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException("Failed to copy buffer", e);
+ }
+ }
+
+ public Reader getXmlAsReader() throws ReportProcessingException
+ {
+ try
+ {
+ final byte[] zippedData = xmlBuffer.getRaw();
+ return new InputStreamReader(new InflaterInputStream(new ByteArrayInputStream(zippedData, 0, xmlBuffer.getLength())), "UTF-16");
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException("Failed to copy buffer", e);
+ }
+ }
+ }
+
+ public static class GroupContext
+ {
+
+ private final GroupContext parent;
+ private int iterationCount;
+ private boolean groupWithRepeatingSection;
+
+ private GroupContext(final GroupContext parent)
+ {
+ this.parent = parent;
+ }
+
+ public GroupContext getParent()
+ {
+ return parent;
+ }
+
+ public int getIterationCount()
+ {
+ return iterationCount;
+ }
+
+ private void setIterationCount(final int iterationCount)
+ {
+ this.iterationCount = iterationCount;
+ }
+
+ public boolean isGroupWithRepeatingSection()
+ {
+ return groupWithRepeatingSection;
+ }
+
+ private void setGroupWithRepeatingSection(final boolean groupWithRepeatingSection)
+ {
+ this.groupWithRepeatingSection = groupWithRepeatingSection;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "GroupContext{" + "parent=" + parent + ", iterationCount=" + iterationCount + ", groupWithRepeatingSection=" + groupWithRepeatingSection + '}';
+ }
+ }
+ private final FastStack states;
+ private int currentRole;
+ private final FastStack xmlWriters;
+ private XmlWriter rootXmlWriter;
+ /**
+ * This styles-collection contains all styles that were predefined in the report definition file. The common styles
+ * and the master-styles will be written unmodified, the automatic styles will be ignored.
+ */
+ private OfficeStylesCollection predefinedStylesCollection;
+ /**
+ * This styles-collection contains all master-styles that have been generated by the report definition process. It
+ * also contains all automatic styles that have been generated for the page-bands (and the pagebands as well).
+ */
+ private OfficeStylesCollection globalStylesCollection;
+ /**
+ * The content styles collection contains all automatic styles that have been generated for the normal-flow content.
+ */
+ private OfficeStylesCollection contentStylesCollection;
+ private final OutputRepository outputRepository;
+ private final InputRepository inputRepository;
+ private final AttributeNameGenerator tableNameGenerator;
+ private final AttributeNameGenerator frameNameGenerator;
+ private final AttributeNameGenerator autoStyleNameGenerator;
+ private final String target;
+ private static final int INITIAL_BUFFER_SIZE = 40960;
+ private StyleMapper styleMapper;
+ private StyleSheetParserUtil styleSheetParserUtil;
+ private final AttributeNameGenerator imageNames;
+ private final ImageProducer imageProducer;
+ private final OleProducer oleProducer;
+ private GroupContext groupContext;
+ private static final boolean DEBUG_ELEMENTS =
+ JFreeReportBoot.getInstance().getExtendedConfig().getBoolProperty("org.libreoffice.report.pentaho.output.DebugElements");
+
+ protected OfficeDocumentReportTarget(final ReportJob reportJob,
+ final ResourceManager resourceManager,
+ final ResourceKey baseResource,
+ final InputRepository inputRepository,
+ final OutputRepository outputRepository,
+ final String target,
+ final ImageService imageService,
+ final DataSourceFactory datasourcefactory)
+ throws ReportProcessingException
+ {
+ super(reportJob, resourceManager, baseResource);
+ if (imageService == null)
+ {
+ throw new NullPointerException("ImageService must not be null");
+ }
+ if (target == null)
+ {
+ throw new NullPointerException("Target-Name must not be null");
+ }
+
+ this.target = target;
+
+ this.tableNameGenerator = new AttributeNameGenerator();
+ this.frameNameGenerator = new AttributeNameGenerator();
+ this.autoStyleNameGenerator = new AttributeNameGenerator();
+ this.outputRepository = outputRepository;
+ this.inputRepository = inputRepository;
+ this.states = new FastStack();
+ this.xmlWriters = new FastStack();
+ this.imageNames = new AttributeNameGenerator();
+
+ this.imageProducer = new ImageProducer(inputRepository, outputRepository, imageService);
+ this.oleProducer = new OleProducer(inputRepository, outputRepository, imageService, datasourcefactory, (Integer) reportJob.getParameters().get(ReportEngineParameterNames.MAXROWS));
+
+ try
+ {
+ final ResourceManager realResourceManager = getResourceManager();
+ styleMapper = StyleMapper.loadInstance(realResourceManager);
+ }
+ catch (ResourceException e)
+ {
+ throw new ReportProcessingException("Failed to load style-mapper", e);
+ }
+ }
+
+ protected abstract String getTargetMimeType();
+
+ protected OutputRepository getOutputRepository()
+ {
+ return outputRepository;
+ }
+
+ private InputRepository getInputRepository()
+ {
+ return inputRepository;
+ }
+
+ /**
+ * Starts the output of a new office document. This method writes the generic 'office:document-content' tag along with
+ * all known namespace declarations.
+ *
+ * @param report the report object.
+ * @throws DataSourceException if there was an error accessing the datasource
+ * @throws ReportProcessingException if some other error occurred.
+ */
+ public void startReport(final ReportStructureRoot report)
+ throws DataSourceException, ReportProcessingException
+ {
+ imageNames.reset();
+ this.groupContext = new GroupContext(null);
+
+ final DefaultTagDescription tagDescription = createTagDescription();
+ try
+ {
+ final OutputStream outputStream = outputRepository.createOutputStream(target, "text/xml");
+ final Writer writer = new OutputStreamWriter(outputStream, "UTF-8");
+
+ this.rootXmlWriter = new XmlWriter(writer, tagDescription);
+ this.rootXmlWriter.setAlwaysAddNamespace(true);
+
+ final AttributeList rootAttributes = new AttributeList();
+ rootAttributes.addNamespaceDeclaration("office", OfficeNamespaces.OFFICE_NS);
+ rootAttributes.addNamespaceDeclaration("style", OfficeNamespaces.STYLE_NS);
+ rootAttributes.addNamespaceDeclaration("text", OfficeNamespaces.TEXT_NS);
+ rootAttributes.addNamespaceDeclaration("table", OfficeNamespaces.TABLE_NS);
+ rootAttributes.addNamespaceDeclaration("draw", OfficeNamespaces.DRAWING_NS);
+ rootAttributes.addNamespaceDeclaration("fo", OfficeNamespaces.FO_NS);
+ rootAttributes.addNamespaceDeclaration("xlink", OfficeNamespaces.XLINK_NS);
+ rootAttributes.addNamespaceDeclaration("dc", OfficeNamespaces.PURL_NS);
+ rootAttributes.addNamespaceDeclaration("meta", OfficeNamespaces.META_NS);
+ rootAttributes.addNamespaceDeclaration("number", OfficeNamespaces.DATASTYLE_NS);
+ rootAttributes.addNamespaceDeclaration("svg", OfficeNamespaces.SVG_NS);
+ rootAttributes.addNamespaceDeclaration("chart", OfficeNamespaces.CHART_NS);
+ rootAttributes.addNamespaceDeclaration("chartooo", OfficeNamespaces.CHARTOOO_NS);
+ rootAttributes.addNamespaceDeclaration("dr3d", OfficeNamespaces.DR3D_NS);
+ rootAttributes.addNamespaceDeclaration("math", OfficeNamespaces.MATHML_NS);
+ rootAttributes.addNamespaceDeclaration("form", OfficeNamespaces.FORM_NS);
+ rootAttributes.addNamespaceDeclaration("script", OfficeNamespaces.SCRIPT_NS);
+ rootAttributes.addNamespaceDeclaration("ooo", OfficeNamespaces.OO2004_NS);
+ rootAttributes.addNamespaceDeclaration("ooow", OfficeNamespaces.OOW2004_NS);
+ rootAttributes.addNamespaceDeclaration("oooc", OfficeNamespaces.OOC2004_NS);
+ rootAttributes.addNamespaceDeclaration("dom", OfficeNamespaces.XML_EVENT_NS);
+ rootAttributes.addNamespaceDeclaration("xforms", OfficeNamespaces.XFORMS_NS);
+ rootAttributes.addNamespaceDeclaration("xsd", OfficeNamespaces.XSD_NS);
+ rootAttributes.addNamespaceDeclaration("xsi", OfficeNamespaces.XSI_NS);
+ rootAttributes.addNamespaceDeclaration("grddl", OfficeNamespaces.GRDDL_NS);
+ rootAttributes.addNamespaceDeclaration("loext", OfficeNamespaces.LOEXT_NS);
+ rootAttributes.setAttribute(OfficeNamespaces.OFFICE_NS, "version",
+ ODF_VERSION);
+
+ this.rootXmlWriter.writeXmlDeclaration("UTF-8");
+ this.rootXmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "document-content", rootAttributes, XmlWriterSupport.OPEN);
+
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_DOCUMENT));
+
+ autoStyleNameGenerator.reset();
+ tableNameGenerator.reset();
+ frameNameGenerator.reset();
+
+ final OfficeDocument reportDoc = (OfficeDocument) report;
+ predefinedStylesCollection = reportDoc.getStylesCollection();
+
+ final OfficeStyles commonStyles = predefinedStylesCollection.getCommonStyles();
+ if (!commonStyles.containsStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS))
+ {
+ final OfficeStyle graphicsDefaultStyle = new OfficeStyle();
+ graphicsDefaultStyle.setStyleFamily(OfficeToken.GRAPHIC);
+ graphicsDefaultStyle.setStyleName(OfficeToken.GRAPHICS);
+ final Element graphicProperties = produceFirstChild(graphicsDefaultStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
+ graphicProperties.setAttribute(OfficeNamespaces.TEXT_NS, "anchor-type", OfficeToken.PARAGRAPH);
+ graphicProperties.setAttribute(OfficeNamespaces.SVG_NS, "x", ZERO_CM);
+ graphicProperties.setAttribute(OfficeNamespaces.SVG_NS, "y", ZERO_CM);
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "wrap", "dynamic");
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "number-wrapped-paragraphs", "no-limit");
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "wrap-contour", OfficeToken.FALSE);
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, VERTICAL_POS, "from-top"); // changed for chart
+
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "vertical-rel", OfficeToken.PARAGRAPH);
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, HORIZONTAL_POS, "from-left"); // changed for chart
+
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "horizontal-rel", OfficeToken.PARAGRAPH);
+ commonStyles.addStyle(graphicsDefaultStyle);
+ }
+
+ // Make sure that later generated styles do not overwrite existing styles.
+ fillStyleNameGenerator(predefinedStylesCollection);
+
+ contentStylesCollection = new OfficeStylesCollection();
+ globalStylesCollection = new OfficeStylesCollection();
+
+ startBuffering(contentStylesCollection, true);
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException(FAILED, e);
+ }
+ }
+
+ protected AttributeNameGenerator getAutoStyleNameGenerator()
+ {
+ return autoStyleNameGenerator;
+ }
+
+ private void fillStyleNameGenerator(final OfficeStylesCollection stylesCollection)
+ {
+ final OfficeStyles commonStyles = stylesCollection.getCommonStyles();
+ final OfficeStyle[] allCommonStyles = commonStyles.getAllStyles();
+ for (int i = 0; i < allCommonStyles.length; i++)
+ {
+ final OfficeStyle style = allCommonStyles[i];
+ autoStyleNameGenerator.generateName(style.getStyleName());
+ }
+
+ final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles();
+ final OfficeStyle[] allAutoStyles = autoStyles.getAllStyles();
+ for (int i = 0; i < allAutoStyles.length; i++)
+ {
+ final OfficeStyle style = allAutoStyles[i];
+ autoStyleNameGenerator.generateName(style.getStyleName());
+ }
+ }
+
+ public OfficeStylesCollection getPredefinedStylesCollection()
+ {
+ return predefinedStylesCollection;
+ }
+
+ public OfficeStylesCollection getGlobalStylesCollection()
+ {
+ return globalStylesCollection;
+ }
+
+ public OfficeStylesCollection getContentStylesCollection()
+ {
+ return contentStylesCollection;
+ }
+
+ /**
+ * Returns the XML-Writer tag description. This description defines whether an element can have character data inside.
+ * Such element will disable the indention, as in that case the additional whitespaces might alter the meaning of the
+ * element's contents.
+ *
+ * @return the tag description library.
+ */
+ protected DefaultTagDescription createTagDescription()
+ {
+ final DefaultTagDescription tagDescription = new DefaultTagDescription();
+ tagDescription.configure(JFreeReportBoot.getInstance().getGlobalConfig(),
+ OfficeDocumentReportTarget.TAG_DEF_PREFIX);
+ return tagDescription;
+ }
+
+ /**
+ * Returns the current processing state.
+ *
+ * @return the processing state.
+ */
+ private int getCurrentState()
+ {
+ if (states.isEmpty())
+ {
+ throw new IllegalStateException();
+ }
+ final Integer o = (Integer) states.peek();
+ return o;
+ }
+
+ /**
+ * Starts the processing of an element and updates the processing state. This will select an appropriate handler method
+ * for the call and will call one of the start* methods.
+ *
+ * @param roAttrs the attribute map for the current element
+ */
+ public final void startElement(final AttributeMap roAttrs)
+ throws DataSourceException, ReportProcessingException
+ {
+ final AttributeMap attrs = new LazyAttributeMap(roAttrs);
+ // todo
+ if (DEBUG_ELEMENTS)
+ {
+ LOGGER.config("Starting " + getCurrentState() + '/' + states.size() + ' ' + ReportTargetUtil.getNamespaceFromAttribute(attrs) + " -> " + ReportTargetUtil.getElemenTypeFromAttribute(attrs));
+ }
+ try
+ {
+ switch (getCurrentState())
+ {
+ case OfficeDocumentReportTarget.STATE_IN_DOCUMENT:
+ {
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OFFICE_NS, "body", attrs))
+ {
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_BODY));
+ startBody();
+ }
+ else
+ {
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER));
+ if (!isFilteredNamespace(ReportTargetUtil.getNamespaceFromAttribute(attrs)))
+ {
+ startOther(attrs);
+ }
+ }
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_BODY:
+ {
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OFFICE_NS, "report", attrs))
+ {
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_CONTENT));
+ startContent(attrs);
+ }
+ else
+ {
+ throw new IllegalStateException("The 'office:body' element must have exactly one child of type 'report'");
+ }
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_CONTENT:
+ {
+ // Either an ordinary section or a group ..
+ // A group.
+ if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "report-body", attrs))
+ {
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP_BODY));
+ }
+ else
+ {
+ // Either a template-section, page-header, page-footer, report-header, report-footer
+ // or variables-section
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
+ if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "template", attrs))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_TEMPLATE;
+ }
+ else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "page-header", attrs))
+ {
+ if ("spreadsheet-section".equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "role")))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_HEADER;
+ }
+ else
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_PAGE_HEADER;
+ }
+ }
+ else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "page-footer", attrs))
+ {
+ if ("spreadsheet-section".equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "role")))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_FOOTER;
+ }
+ else
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_PAGE_FOOTER;
+ }
+ }
+ else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "report-header", attrs))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_REPORT_HEADER;
+ }
+ else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "report-footer", attrs))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_REPORT_FOOTER;
+ }
+ else if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "variables-section", attrs))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES;
+ }
+ else
+ {
+ throw new IllegalStateException("Expected either 'template', 'report-body', " + "'report-header', 'report-footer', 'variables-section', 'page-header' or 'page-footer'");
+ }
+ startReportSection(attrs, currentRole);
+ }
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_GROUP_BODY:
+ {
+ // We now expect either another group or a detail band.
+
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group", attrs))
+ {
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP));
+ groupContext = new GroupContext(groupContext);
+ startGroup(attrs);
+ }
+ else
+ {
+ // Either a variables-section, or a detail-band
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "detail", attrs))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_DETAIL;
+ }
+ else if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "variables-section", attrs))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES;
+ }
+ else
+ {
+ throw new IllegalStateException("Expected either 'group', 'detail' or 'variables-section'");
+ }
+ startReportSection(attrs, currentRole);
+ }
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_GROUP:
+ {
+ // A group can carry a repeating group header/footer or a group-instance section.
+ if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "group-instance", attrs))
+ {
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE));
+ startGroupInstance(attrs);
+ }
+ else
+ {
+ // repeating group header/footer, but *no* variables section
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-header", attrs) && OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "repeated-section")))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER;
+ }
+ else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-footer", attrs) && OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "repeated-section")))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER;
+ }
+ else
+ {
+ throw new IllegalStateException("Expected either 'group-instance', " + "'repeating group-header' or 'repeating group-footer'");
+ }
+ startReportSection(attrs, currentRole);
+ }
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE:
+ {
+ if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "group-body", attrs))
+ {
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_GROUP_BODY));
+ }
+ else
+ {
+ // Either a group-header or group-footer or variables-section
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_SECTION));
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-header", attrs))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_GROUP_HEADER;
+ }
+ else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.OOREPORT_NS, "group-footer", attrs))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_GROUP_FOOTER;
+ }
+ else if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, "variables-section", attrs))
+ {
+ currentRole = OfficeDocumentReportTarget.ROLE_VARIABLES;
+ }
+ else
+ {
+ throw new IllegalStateException("Expected either 'group-body', 'group-header', 'group-footer' or 'variables-section'");
+ }
+ startReportSection(attrs, currentRole);
+ }
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_SECTION:
+ case OfficeDocumentReportTarget.STATE_IN_OTHER:
+ {
+ states.push(IntegerCache.getInteger(OfficeDocumentReportTarget.STATE_IN_OTHER));
+ startOther(attrs);
+ break;
+ }
+ default:
+ throw new IllegalStateException("Failure: " + getCurrentState());
+ }
+ }
+ catch (IOException ioe)
+ {
+ LOGGER.severe("ReportProcessing failed: " + ioe);
+ throw new ReportProcessingException("Failed to write content", ioe);
+ }
+ }
+
+ protected GroupContext getGroupContext()
+ {
+ return groupContext;
+ }
+
+ protected void performStyleProcessing(final AttributeMap attrs)
+ throws ReportProcessingException
+ {
+ final OfficeStylesCollection stylesCollection = getStylesCollection();
+ final OfficeStylesCollection predefCollection = getPredefinedStylesCollection();
+ final OfficeStylesCollection globalStylesCollection = getGlobalStylesCollection();
+
+ final String elementNamespace =
+ ReportTargetUtil.getNamespaceFromAttribute(attrs);
+ final String elementName =
+ ReportTargetUtil.getElemenTypeFromAttribute(attrs);
+
+ final String[] namespaces = attrs.getNameSpaces();
+ for (int i = 0; i < namespaces.length; i++)
+ {
+ final String attrNamespace = namespaces[i];
+ if (isFilteredNamespace(attrNamespace))
+ {
+ continue;
+ }
+
+ final Map attributes = attrs.getAttributes(attrNamespace);
+ final Iterator iterator = attributes.entrySet().iterator();
+ while (iterator.hasNext())
+ {
+ final Map.Entry entry = (Map.Entry) iterator.next();
+ final String attrName = (String) entry.getKey();
+ final String attrValue = String.valueOf(entry.getValue());
+
+ final String styleFamily = styleMapper.getStyleFamilyFor(elementNamespace, elementName, attrNamespace, attrName);
+ if (styleFamily == null)
+ {
+ // None of the known style attributes.
+ continue;
+ }
+
+ if (styleMapper.isListOfStyles(elementNamespace, elementName, attrNamespace, attrName))
+ {
+ // ignored for now.
+ LOGGER.warning("List of styles is not yet implemented.");
+ continue;
+ }
+
+ // Copy styles is only called once per style.
+ StyleUtilities.copyStyle(styleFamily, attrValue, stylesCollection, globalStylesCollection, predefCollection);
+ }
+ }
+ }
+
+ private void startBody()
+ throws IOException
+ {
+ getXmlWriter().writeTag(OfficeNamespaces.OFFICE_NS, "body", XmlWriterSupport.OPEN);
+ }
+
+ private final boolean allowBuffering(final int role)
+ {
+ return (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER || role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER || role == OfficeDocumentReportTarget.ROLE_TEMPLATE);
+ }
+
+ protected void startReportSection(final AttributeMap attrs, final int role)
+ throws ReportProcessingException
+ {
+ if (allowBuffering(role))
+ {
+ startBuffering(new OfficeStylesCollection(), true);
+ }
+ }
+
+ protected abstract void startContent(final AttributeMap attrs)
+ throws IOException, DataSourceException, ReportProcessingException;
+
+ protected void startGroup(final AttributeMap attrs)
+ {
+ final Object repeatingHeaderOrFooter = attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "repeating-header-or-footer");
+ if (OfficeToken.TRUE.equals(repeatingHeaderOrFooter))
+ {
+ getGroupContext().setGroupWithRepeatingSection(true);
+ }
+
+ final Object iterationCount = attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "iteration-count");
+ if (iterationCount instanceof Number)
+ {
+ final Number itNumber = (Number) iterationCount;
+ getGroupContext().setIterationCount(itNumber.intValue());
+ }
+ }
+
+ protected void startGroupInstance(final AttributeMap attrs)
+ {
+ }
+
+ protected abstract void startOther(final AttributeMap attrs)
+ throws IOException, DataSourceException, ReportProcessingException;
+
+ public void processText(final String text)
+ throws DataSourceException, ReportProcessingException
+ {
+ try
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+ final BufferedReader br = new BufferedReader(new StringReader(text));
+ String line = br.readLine();
+ while (line != null)
+ {
+ xmlWriter.writeTextNormalized(line, false);
+ line = br.readLine();
+ if (line != null)
+ {
+ xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, "line-break", XmlWriterSupport.CLOSE);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException(FAILED, e);
+ }
+ }
+
+ protected boolean isFilteredNamespace(final String namespace)
+ {
+ if (Namespaces.LIBLAYOUT_NAMESPACE.equals(namespace))
+ {
+ return true;
+ }
+ if (JFreeReportInfo.REPORT_NAMESPACE.equals(namespace))
+ {
+ return true;
+ }
+ if (JFreeReportInfo.REPORT_NAMESPACE.equals(namespace))
+ {
+ return true;
+ }
+ if (JFreeReportInfo.COMPATIBILITY_NAMESPACE.equals(namespace))
+ {
+ return true;
+ }
+ if (OfficeNamespaces.OOREPORT_NS.equals(namespace))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ public void processContent(final DataFlags value)
+ throws DataSourceException, ReportProcessingException
+ {
+ final Object rawvalue = value.getValue();
+ if (rawvalue == null)
+ {
+ return;
+ }
+
+ // special handler for image (possibly also for URL ..)
+ if (rawvalue instanceof Image)
+ {
+ // do nothing yet. We should define something for that later ..
+ return;
+ }
+
+ final XmlWriter xmlWriter = getXmlWriter();
+ final String text = String.valueOf(rawvalue);
+ try
+ {
+ final BufferedReader br = new BufferedReader(new StringReader(text));
+ String line = br.readLine();
+ while (line != null)
+ {
+ xmlWriter.writeTextNormalized(line, false);
+ line = br.readLine();
+ if (line != null)
+ {
+ xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, "line-break", XmlWriterSupport.CLOSE);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException(FAILED, e);
+ }
+ }
+
+ public final void endElement(final AttributeMap roAttrs)
+ throws DataSourceException, ReportProcessingException
+ {
+ final AttributeMap attrs = new LazyAttributeMap(roAttrs);
+ try
+ {
+
+ switch (getCurrentState())
+ {
+ case OfficeDocumentReportTarget.STATE_IN_OTHER:
+ {
+ endOther(attrs);
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_SECTION:
+ {
+ endReportSection(attrs, currentRole);
+ currentRole = OfficeDocumentReportTarget.ROLE_NONE;
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_GROUP:
+ {
+ endGroup(attrs);
+ groupContext = groupContext.getParent();
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_GROUP_INSTANCE:
+ {
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_GROUP_BODY:
+ {
+ endGroupBody(attrs);
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_CONTENT:
+ {
+ endContent(attrs);
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_BODY:
+ {
+ endBody();
+ break;
+ }
+ case OfficeDocumentReportTarget.STATE_IN_DOCUMENT:
+ {
+ throw new IllegalStateException("This cannot be.");
+ }
+ default:
+ {
+ throw new IllegalStateException("Invalid state encountered.");
+ }
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw new ReportProcessingException("IO Error while writing content",
+ ioe);
+ } finally
+ {
+ states.pop();
+
+ if (DEBUG_ELEMENTS)
+ {
+ LOGGER.config("Finished " + getCurrentState() + "/" + states.size() + " " + ReportTargetUtil.getNamespaceFromAttribute(attrs) + ":" + ReportTargetUtil.getElemenTypeFromAttribute(attrs));
+ }
+
+ }
+ }
+
+ protected void endGroupBody(final AttributeMap attrs)
+ throws IOException
+ {
+ }
+
+ public int getCurrentRole()
+ {
+ return currentRole;
+ }
+
+ protected abstract void endOther(final AttributeMap attrs)
+ throws IOException, DataSourceException, ReportProcessingException;
+
+ protected void endReportSection(final AttributeMap attrs,
+ final int role)
+ throws IOException, ReportProcessingException
+ {
+ if (allowBuffering(role))
+ {
+ finishBuffering();
+ }
+ }
+
+ protected void endGroup(final AttributeMap attrs)
+ throws ReportProcessingException
+ {
+ }
+
+ protected abstract void endContent(final AttributeMap attrs)
+ throws IOException, DataSourceException, ReportProcessingException;
+
+ private void endBody()
+ throws IOException
+ {
+ getXmlWriter().writeCloseTag();
+ }
+
+ public void copyMeta()
+ {
+ // now copy the meta.xml
+ if (getInputRepository().isReadable("meta.xml"))
+ {
+ InputStream inputStream = null;
+ try
+ {
+ inputStream = getInputRepository().createInputStream("meta.xml");
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+ Document document = dBuilder.parse(new InputSource(inputStream));
+
+ Node node = document.getFirstChild().getFirstChild().getFirstChild().getFirstChild();
+ String creator = node.getNodeValue();
+ node.setNodeValue(creator + "/report_builder");
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+
+ final OutputStream outputMetaStream = getOutputRepository().createOutputStream("meta.xml", "text/xml");
+ StreamResult result = new StreamResult(outputMetaStream);
+ DOMSource source = new DOMSource(document);
+ transformer.transform(source, result);
+
+ outputMetaStream.flush();
+ outputMetaStream.close();
+ }
+ catch (java.lang.Exception ex)
+ {
+ } finally
+ {
+ if (inputStream != null)
+ {
+ try
+ {
+ inputStream.close();
+ }
+ catch (IOException ex)
+ {
+ Logger.getLogger(OfficeDocumentReportTarget.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+ }
+ }
+ }
+
+ public void endReport(final ReportStructureRoot report)
+ throws DataSourceException, ReportProcessingException
+ {
+ if (xmlWriters.size() != 1)
+ {
+ throw new IllegalStateException("Invalid writer-stack state");
+ }
+
+ try
+ {
+ final StylesWriter inlineStylesWriter = new StylesWriter(rootXmlWriter);
+ inlineStylesWriter.writeContentStyles(contentStylesCollection);
+
+ final BufferState state = finishBuffering();
+ this.rootXmlWriter.writeStream(state.getXmlAsReader());
+
+ final OutputStream stylesOutStream =
+ outputRepository.createOutputStream("styles.xml", "text/xml");
+ final OutputStreamWriter osw =
+ new OutputStreamWriter(stylesOutStream, "UTF-8");
+ final StylesWriter stylesWriter = new StylesWriter(osw);
+ stylesWriter.writeGlobalStyles(globalStylesCollection);
+ stylesWriter.close();
+
+ this.rootXmlWriter.writeCloseTag();
+ this.rootXmlWriter.close();
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException(FAILED, e);
+ }
+ }
+
+ public XmlWriter getXmlWriter()
+ {
+ final BufferState bufferState = (BufferState) xmlWriters.peek();
+ return bufferState.getXmlWriter();
+ }
+
+ public OfficeStylesCollection getStylesCollection()
+ {
+ final BufferState bufferState = (BufferState) xmlWriters.peek();
+ return bufferState.getStylesCollection();
+ }
+
+ public void startBuffering(final OfficeStylesCollection stylesCollection,
+ final boolean indent) throws ReportProcessingException
+ {
+ final XmlWriter currentWriter;
+ if (xmlWriters.isEmpty())
+ {
+ currentWriter = rootXmlWriter;
+ }
+ else
+ {
+ final BufferState bufferState = (BufferState) xmlWriters.peek();
+ currentWriter = bufferState.getXmlWriter();
+ }
+
+ try
+ {
+ final MemoryByteArrayOutputStream out =
+ new MemoryByteArrayOutputStream(INITIAL_BUFFER_SIZE, 256 * INITIAL_BUFFER_SIZE);
+ final DeflaterOutputStream deflateOut = new DeflaterOutputStream(out);
+ final OutputStreamWriter xmlBuffer = new OutputStreamWriter(deflateOut, "UTF-16");
+ final XmlWriter contentXmlWriter = new XmlWriter(xmlBuffer, createTagDescription());
+ contentXmlWriter.copyNamespaces(currentWriter);
+ if (indent)
+ {
+ contentXmlWriter.setAdditionalIndent(currentWriter.getCurrentIndentLevel());
+ contentXmlWriter.setWriteFinalLinebreak(true);
+ }
+ else
+ {
+ contentXmlWriter.setWriteFinalLinebreak(false);
+ }
+ contentXmlWriter.setAlwaysAddNamespace(true);
+ xmlWriters.push(new BufferState(contentXmlWriter, out, stylesCollection));
+ }
+ catch (IOException ioe)
+ {
+ throw new ReportProcessingException("Unable to create the buffer", ioe);
+ }
+ }
+
+ public BufferState finishBuffering()
+ {
+ final BufferState state = (BufferState) xmlWriters.pop();
+ try
+ {
+ state.getXmlWriter().close();
+ }
+ catch (IOException e)
+ {
+ LOGGER.severe("ReportProcessing failed: " + e);
+ }
+ return state;
+ }
+
+ public void commit()
+ throws ReportProcessingException
+ {
+ // do not call flush before the report is fully finished. Every flush
+ // causes the Office-Backend to fully ZIP all contents (it acts like a
+ // 'Save' call from the UI) and that's expensive like hell
+ }
+
+ public NamespaceDefinition getNamespaceByUri(final String uri)
+ {
+ return null;
+ }
+
+ protected AttributeList buildAttributeList(final AttributeMap attrs)
+ {
+ final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
+ final AttributeList attrList = new AttributeList();
+ final String[] namespaces = attrs.getNameSpaces();
+ for (int i = 0; i < namespaces.length; i++)
+ {
+ final String attrNamespace = namespaces[i];
+ if (isFilteredNamespace(attrNamespace))
+ {
+ continue;
+ }
+
+ final Map localAttributes = attrs.getAttributes(attrNamespace);
+ final Iterator entries = localAttributes.entrySet().iterator();
+ while (entries.hasNext())
+ {
+ final Map.Entry entry = (Map.Entry) entries.next();
+ final String key = String.valueOf(entry.getKey());
+ if (OfficeNamespaces.TABLE_NS.equals(attrNamespace) && "name".equals(key))
+ {
+ final String tableName = String.valueOf(entry.getValue());
+ final String saneName = sanitizeName(tableName);
+ attrList.setAttribute(attrNamespace, key,
+ tableNameGenerator.generateName(saneName));
+ }
+ else if (OfficeNamespaces.DRAWING_NS.equals(attrNamespace) && "name".equals(key) && !"equation".equals(elementType))
+ {
+ final String objectName = String.valueOf(entry.getValue());
+ attrList.setAttribute(attrNamespace, key,
+ frameNameGenerator.generateName(objectName));
+ }
+ else
+ {
+ attrList.setAttribute(attrNamespace, key, String.valueOf(entry.getValue()));
+ }
+ }
+ }
+ return attrList;
+ }
+
+ private String sanitizeName(final String name)
+ {
+ // A table name cannot contain spaces and should only contain
+ // ascii-characters.
+ if (name == null)
+ {
+ return "";
+ }
+ final char[] chars = name.toCharArray();
+ final StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < chars.length; i++)
+ {
+ final char aChar = chars[i];
+ if (Character.isWhitespace(aChar))
+ {
+ buffer.append('_');
+ }
+ else
+ {
+ buffer.append(aChar);
+ }
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Returns the length in point. This method is f**king slow, it eats half of the processing time. I surely should
+ * replace it with something more efficient later.
+ *
+ * @param text
+ * @return
+ */
+ protected CSSNumericValue parseLength(final String text)
+ {
+ if (styleSheetParserUtil == null)
+ {
+ styleSheetParserUtil = StyleSheetParserUtil.getInstance();
+ }
+
+ final LexicalUnit cssValue = styleSheetParserUtil.parseLexicalStyleValue(
+ text);
+ if (cssValue == null) {
+ CSSNumericValue zeroLength = CSSNumericValue.createValue(CSSNumericType.CM, 0);
+ return zeroLength;
+ }
+ return CSSValueFactory.createLengthValue(cssValue);
+ }
+
+ protected boolean isRepeatingSection()
+ {
+ return (currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER || currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER || currentRole == OfficeDocumentReportTarget.ROLE_PAGE_FOOTER || currentRole == OfficeDocumentReportTarget.ROLE_PAGE_HEADER || currentRole == OfficeDocumentReportTarget.ROLE_VARIABLES);
+
+ }
+
+ protected OfficeStyle deriveStyle(final String styleFamily, final String styleName)
+ throws ReportProcessingException
+ {
+ // autogenerate a style. The style has already been added to the current
+ // auto-collection.
+ final OfficeStyle style = StyleUtilities.deriveStyle(styleFamily, styleName,
+ getStylesCollection(), getGlobalStylesCollection(),
+ getPredefinedStylesCollection(), getAutoStyleNameGenerator());
+ return style;
+ }
+
+ protected void startImageProcessing(final AttributeMap attrs)
+ throws ReportProcessingException
+ {
+ final Object imageData = attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.IMAGE_DATA);
+ final boolean preserveIRI = OfficeToken.TRUE.equals(attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.PRESERVE_IRI));
+
+ // for the first shot, do nothing fancy ..
+ final ImageProducer.OfficeImage image = imageProducer.produceImage(imageData, preserveIRI);
+ if (image != null)
+ {
+ final ImageElementContext imageContext = (ImageElementContext) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "image-context");
+
+ // When scaling, we have to create an image-style.
+ final CSSNumericValue width = image.getWidth(); // always in 100th of a mm
+
+ final CSSNumericValue height = image.getHeight(); // always in 100th of a mm
+
+ LOGGER.config("Image " + imageData + " Width: " + width + ", Height: " + height);
+ if (width == null || height == null)
+ {
+ return;
+ }
+
+ CSSNumericValue imageAreaWidthVal;
+ CSSNumericValue imageAreaHeightVal;
+ CSSNumericValue posX = CSSNumericValue.createValue(CSSNumericType.CM, 0.0);
+ CSSNumericValue posY = CSSNumericValue.createValue(CSSNumericType.CM, 0.0);
+
+ String styleName = null;
+ if (imageContext != null)
+ {
+ imageAreaWidthVal = computeImageWidth(imageContext);
+ imageAreaHeightVal = computeImageHeight(imageContext);
+
+ if (imageAreaWidthVal == null || imageAreaHeightVal == null)
+ {
+ LOGGER.config("Image data returned from context is invalid. Maybe this is not an image?");
+ return;
+ }
+ else
+ {
+ // compute the clip-area ..
+ final CSSNumericValue normalizedImageWidth =
+ CSSValueResolverUtility.convertLength(width, imageAreaWidthVal.getType());
+ final CSSNumericValue normalizedImageHeight =
+ CSSValueResolverUtility.convertLength(height, imageAreaHeightVal.getType());
+
+ final String scale = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.SCALE);
+ if (OfficeToken.NONE.equals(scale) && normalizedImageWidth.getValue() > 0 && normalizedImageHeight.getValue() > 0)
+ {
+ final double clipWidth = normalizedImageWidth.getValue() - imageAreaWidthVal.getValue();
+ final double clipHeight = normalizedImageHeight.getValue() - imageAreaHeightVal.getValue();
+ if (clipWidth > 0 && clipHeight > 0)
+ {
+ final OfficeStyle imageStyle = deriveStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS);
+ final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
+ final StringBuffer buffer = new StringBuffer();
+ buffer.append("rect(");
+ buffer.append(clipHeight / 2);
+ buffer.append(imageAreaHeightVal.getType().getType());
+ buffer.append(' ');
+ buffer.append(clipWidth / 2);
+ buffer.append(imageAreaWidthVal.getType().getType());
+ buffer.append(' ');
+ buffer.append(clipHeight / 2);
+ buffer.append(imageAreaHeightVal.getType().getType());
+ buffer.append(' ');
+ buffer.append(clipWidth / 2);
+ buffer.append(imageAreaWidthVal.getType().getType());
+ buffer.append(')');
+ graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());
+
+ styleName = imageStyle.getStyleName();
+ getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
+ }
+ else if (clipWidth > 0)
+ {
+ final OfficeStyle imageStyle = deriveStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS);
+ final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
+ final StringBuffer buffer = new StringBuffer();
+ buffer.append("rect(0cm ");
+ buffer.append(clipWidth / 2);
+ buffer.append(imageAreaWidthVal.getType().getType());
+ buffer.append(" 0cm ");
+ buffer.append(clipWidth / 2);
+ buffer.append(imageAreaWidthVal.getType().getType());
+ buffer.append(')');
+ graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());
+
+ styleName = imageStyle.getStyleName();
+ getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
+ imageAreaHeightVal = normalizedImageHeight;
+ }
+ else if (clipHeight > 0)
+ {
+ final OfficeStyle imageStyle = deriveStyle(OfficeToken.GRAPHIC, OfficeToken.GRAPHICS);
+ final Element graphProperties = produceFirstChild(imageStyle, OfficeNamespaces.STYLE_NS, OfficeToken.GRAPHIC_PROPERTIES);
+ final StringBuffer buffer = new StringBuffer();
+ buffer.append("rect(");
+ buffer.append(clipHeight / 2);
+ buffer.append(imageAreaHeightVal.getType().getType());
+ buffer.append(" 0cm ");
+ buffer.append(clipHeight / 2);
+ buffer.append(imageAreaHeightVal.getType().getType());
+ buffer.append(" 0cm)");
+ graphProperties.setAttribute(OfficeNamespaces.FO_NS, "clip", buffer.toString());
+
+ styleName = imageStyle.getStyleName();
+ getStylesCollection().getAutomaticStyles().addStyle(imageStyle);
+ imageAreaWidthVal = normalizedImageWidth;
+ }
+ else
+ {
+ imageAreaWidthVal = normalizedImageWidth;
+ imageAreaHeightVal = normalizedImageHeight;
+ }
+ }
+ else if (OfficeToken.ISOTROPIC.equals(scale))
+ {
+ final double[] ret = calcPaintSize(imageAreaWidthVal, imageAreaHeightVal, normalizedImageWidth, normalizedImageHeight);
+
+ posX = CSSNumericValue.createValue(imageAreaWidthVal.getType(), (imageAreaWidthVal.getValue() - ret[0]) * 0.5);
+ posY = CSSNumericValue.createValue(imageAreaHeightVal.getType(), (imageAreaHeightVal.getValue() - ret[1]) * 0.5);
+
+ imageAreaWidthVal = CSSNumericValue.createValue(imageAreaWidthVal.getType(), ret[0]);
+ imageAreaHeightVal = CSSNumericValue.createValue(imageAreaHeightVal.getType(), ret[1]);
+ }
+ }
+ // If we do scale, then we simply use the given image-area-size as valid image size and don't
+ // care about the image itself ..
+ }
+ else
+ {
+ LOGGER.config("There is no image-context, so we have to rely on the image's natural bounds. " + "This may go awfully wrong.");
+ imageAreaWidthVal = image.getWidth();
+ imageAreaHeightVal = image.getHeight();
+ }
+
+ final AttributeList frameList = new AttributeList();
+ frameList.setAttribute(OfficeNamespaces.DRAWING_NS, "name", imageNames.generateName("Image"));
+ if (styleName != null)
+ {
+ frameList.setAttribute(OfficeNamespaces.DRAWING_NS, OfficeToken.STYLE_NAME, styleName);
+ }
+ frameList.setAttribute(OfficeNamespaces.TEXT_NS, "anchor-type", OfficeToken.PARAGRAPH);
+ frameList.setAttribute(OfficeNamespaces.SVG_NS, "z-index", "0");
+ frameList.setAttribute(OfficeNamespaces.SVG_NS, "x", posX.getValue() + posX.getType().getType());
+ frameList.setAttribute(OfficeNamespaces.SVG_NS, "y", posY.getValue() + posY.getType().getType());
+
+
+ LOGGER.config("Image " + imageData + " A-Width: " + imageAreaWidthVal + ", A-Height: " + imageAreaHeightVal);
+
+ if (imageAreaWidthVal != null)
+ {
+ frameList.setAttribute(OfficeNamespaces.SVG_NS,
+ "width", imageAreaWidthVal.getValue() + imageAreaWidthVal.getType().getType());
+ }
+
+ if (imageAreaHeightVal != null)
+ {
+ frameList.setAttribute(OfficeNamespaces.SVG_NS,
+ "height", imageAreaHeightVal.getValue() + imageAreaHeightVal.getType().getType());
+ }
+
+
+ final AttributeList imageList = new AttributeList();
+ imageList.setAttribute(OfficeNamespaces.XLINK_NS, "href", image.getEmbeddableLink());
+ imageList.setAttribute(OfficeNamespaces.XLINK_NS, "type", "simple");
+ imageList.setAttribute(OfficeNamespaces.XLINK_NS, "show", "embed");
+ imageList.setAttribute(OfficeNamespaces.XLINK_NS, "actuate", "onLoad");
+
+
+ try
+ {
+ getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, "frame", frameList, XmlWriterSupport.OPEN);
+ getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, OfficeToken.IMAGE, imageList, XmlWriterSupport.CLOSE);
+ getXmlWriter().writeCloseTag();
+ }
+ catch (IOException ioe)
+ {
+ throw new ReportProcessingException(FAILED, ioe);
+ }
+ }
+ }
+
+ private CSSNumericValue computeImageWidth(final ImageElementContext imageElementContext)
+ {
+ final LengthCalculator calculator = new LengthCalculator();
+ final String[] strings = imageElementContext.getColStyles();
+ for (int i = 0; i < strings.length; i++)
+ {
+ final String styleName = strings[i];
+ final CSSNumericValue value = computeColumnWidth(styleName);
+ if (value != null)
+ {
+ calculator.add(value);
+ }
+ }
+ return calculator.getResult();
+ }
+
+ private CSSNumericValue computeImageHeight(final ImageElementContext imageElementContext)
+ {
+ final LengthCalculator calculator = new LengthCalculator();
+ final String[] strings = imageElementContext.getRowStyles();
+ for (int i = 0; i < strings.length; i++)
+ {
+ final String styleName = strings[i];
+ final CSSNumericValue value = computeRowHeight(styleName);
+ if (value != null)
+ {
+ calculator.add(value);
+ }
+ }
+ return calculator.getResult();
+ }
+
+ protected CSSNumericValue computeRowHeight(final String rowStyle)
+ {
+ final OfficeStylesCollection contentStyles = getContentStylesCollection();
+ final OfficeStyle style = contentStyles.getStyle(OfficeToken.TABLE_ROW, rowStyle);
+ if (style != null)
+ {
+ final Element element = style.getTableRowProperties();
+ if (element != null)
+ {
+ final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
+ if (height != null)
+ {
+ return parseLength(height);
+ }
+ }
+
+ final String styleParent = style.getStyleParent();
+ if (styleParent != null)
+ {
+ return computeRowHeight(styleParent);
+ }
+ }
+
+ final OfficeStylesCollection globalStyles = getGlobalStylesCollection();
+ final OfficeStyle globalStyle = globalStyles.getStyle(OfficeToken.TABLE_ROW, rowStyle);
+ if (globalStyle != null)
+ {
+ final Element element = globalStyle.getTableRowProperties();
+ if (element != null)
+ {
+ final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
+ if (height != null)
+ {
+ return parseLength(height);
+ }
+ }
+ final String styleParent = globalStyle.getStyleParent();
+ if (styleParent != null)
+ {
+ return computeRowHeight(styleParent);
+ }
+ }
+
+ final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
+ final OfficeStyle predefStyle = predefStyles.getStyle(OfficeToken.TABLE_ROW, rowStyle);
+ if (predefStyle != null)
+ {
+ final Element element = predefStyle.getTableRowProperties();
+ if (element != null)
+ {
+ final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "row-height");
+ if (height != null)
+ {
+ return parseLength(height);
+ }
+ }
+ final String styleParent = predefStyle.getStyleParent();
+ if (styleParent != null)
+ {
+ return computeRowHeight(styleParent);
+ }
+ }
+ // not found.
+ return null;
+ }
+
+ private CSSNumericValue computeColumnWidth(final String colStyle)
+ {
+ final OfficeStylesCollection contentStyles = getContentStylesCollection();
+ final OfficeStyle style = contentStyles.getStyle(OfficeToken.TABLE_COLUMN, colStyle);
+ if (style != null)
+ {
+ final Element element = style.getTableColumnProperties();
+ if (element != null)
+ {
+ final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
+ if (height != null)
+ {
+ return parseLength(height);
+ }
+ }
+
+ final String styleParent = style.getStyleParent();
+ if (styleParent != null)
+ {
+ return computeRowHeight(styleParent);
+ }
+ }
+
+ final OfficeStylesCollection globalStyles = getGlobalStylesCollection();
+ final OfficeStyle globalStyle = globalStyles.getStyle(OfficeToken.TABLE_COLUMN, colStyle);
+ if (globalStyle != null)
+ {
+ final Element element = globalStyle.getTableColumnProperties();
+ if (element != null)
+ {
+ final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
+ if (height != null)
+ {
+ return parseLength(height);
+ }
+ }
+ final String styleParent = globalStyle.getStyleParent();
+ if (styleParent != null)
+ {
+ return computeRowHeight(styleParent);
+ }
+ }
+
+ final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
+ final OfficeStyle predefStyle = predefStyles.getStyle(OfficeToken.TABLE_COLUMN, colStyle);
+ if (predefStyle != null)
+ {
+ final Element element = predefStyle.getTableColumnProperties();
+ if (element != null)
+ {
+ final String height = (String) element.getAttribute(OfficeNamespaces.STYLE_NS, "column-width");
+ if (height != null)
+ {
+ return parseLength(height);
+ }
+ }
+ final String styleParent = predefStyle.getStyleParent();
+ if (styleParent != null)
+ {
+ return computeRowHeight(styleParent);
+ }
+ }
+ // not found.
+ return null;
+ }
+
+ protected Element produceFirstChild(final Section style,
+ final String nameSpace,
+ final String type)
+ {
+ Element paragraphProps = style.findFirstChild(nameSpace, type);
+ if (paragraphProps == null)
+ {
+ paragraphProps = new Section();
+ paragraphProps.setNamespace(nameSpace);
+ paragraphProps.setType(type);
+ style.addNode(paragraphProps);
+ }
+ return paragraphProps;
+ }
+
+ protected void startChartProcessing(final AttributeMap attrs)
+ throws ReportProcessingException
+ {
+ final String classId = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "class-id");
+ final String chartUrl = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "href");
+ final ArrayList<?> masterColumns = (ArrayList<?>) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_COLUMNS);
+ final ArrayList<?> masterValues = (ArrayList<?>) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.MASTER_VALUES);
+ final ArrayList<?> detailColumns = (ArrayList<?>) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, SDBCReportDataFactory.DETAIL_COLUMNS);
+ final String href = oleProducer.produceOle(chartUrl, masterColumns, masterValues, detailColumns);
+
+ final AttributeList oleList = new AttributeList();
+ oleList.setAttribute(OfficeNamespaces.DRAWING_NS, "class-id", classId);
+ oleList.setAttribute(OfficeNamespaces.XLINK_NS, "href", "./" + href);
+ oleList.setAttribute(OfficeNamespaces.XLINK_NS, "type", "simple");
+ oleList.setAttribute(OfficeNamespaces.XLINK_NS, "show", "embed");
+ oleList.setAttribute(OfficeNamespaces.XLINK_NS, "actuate", "onLoad");
+
+ try
+ {
+ getXmlWriter().writeTag(OfficeNamespaces.DRAWING_NS, OfficeToken.OBJECT_OLE, oleList, XmlWriterSupport.CLOSE);
+ }
+ catch (IOException ioe)
+ {
+ throw new ReportProcessingException(FAILED, ioe);
+ }
+ }
+
+ private static double[] calcPaintSize(final CSSNumericValue areaWidth, final CSSNumericValue areaHeight,
+ final CSSNumericValue imageWidth, final CSSNumericValue imageHeight)
+ {
+
+ final double ratioX = areaWidth.getValue() / imageWidth.getValue();
+ final double ratioY = areaHeight.getValue() / imageHeight.getValue();
+ final double ratioMin = Math.min(ratioX, ratioY);
+
+ double[] ret = new double[2];
+ ret[0] = imageWidth.getValue() * ratioMin;
+ ret[1] = imageHeight.getValue() * ratioMin;
+ return ret;
+ }
+
+ protected void writeNullDate() throws IOException
+ {
+ // write NULL DATE
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, "calculation-settings", null, XmlWriterSupport.OPEN);
+ final AttributeMap nullDateAttributes = new AttributeMap();
+ nullDateAttributes.setAttribute(OfficeNamespaces.TABLE_NS, "date-value", "1899-12-30");
+ xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, "null-date", buildAttributeList(nullDateAttributes), XmlWriterSupport.CLOSE);
+ xmlWriter.writeCloseTag();
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/OleProducer.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/OleProducer.java
new file mode 100644
index 000000000..27f3c25a4
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/OleProducer.java
@@ -0,0 +1,124 @@
+/*
+ * 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.output;
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.JobProperties;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.ReportEngineParameterNames;
+import org.libreoffice.report.ReportExecutionException;
+import org.libreoffice.report.ReportJobDefinition;
+import org.libreoffice.report.pentaho.DefaultNameGenerator;
+import org.libreoffice.report.pentaho.PentahoReportEngine;
+import org.libreoffice.report.pentaho.PentahoReportEngineMetaData;
+
+import java.io.IOException;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+public class OleProducer
+{
+
+ private static final Logger LOGGER = Logger.getLogger(OleProducer.class.getName());
+ private final InputRepository inputRepository;
+ private final OutputRepository outputRepository;
+ private final DefaultNameGenerator nameGenerator;
+ private final DataSourceFactory dataSourceFactory;
+ private final ImageService imageService;
+ private final Integer maxRows;
+
+ public OleProducer(final InputRepository inputRepository,
+ final OutputRepository outputRepository, final ImageService imageService, final DataSourceFactory dataSourceFactory, final Integer maxRows)
+ {
+ if (inputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (outputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+
+ this.inputRepository = inputRepository;
+ this.outputRepository = outputRepository;
+ this.nameGenerator = new DefaultNameGenerator(outputRepository);
+ this.dataSourceFactory = dataSourceFactory;
+ this.imageService = imageService;
+ this.maxRows = maxRows;
+ }
+
+ String produceOle(final String source, final List masterColumns, final List masterValues, final List detailColumns)
+ {
+ InputRepository subInputRepository = null;
+ OutputRepository subOutputRepository = null;
+ String output = "";
+ try
+ {
+ subInputRepository = inputRepository.openInputRepository(source);
+ output = nameGenerator.generateStorageName("Object", null);
+ subOutputRepository = outputRepository.openOutputRepository(output, PentahoReportEngineMetaData.OPENDOCUMENT_CHART);
+ try
+ {
+
+ final PentahoReportEngine engine = new PentahoReportEngine();
+ final ReportJobDefinition definition = engine.createJobDefinition();
+ final JobProperties procParms = definition.getProcessingParameters();
+
+ procParms.setProperty(ReportEngineParameterNames.INPUT_REPOSITORY, subInputRepository);
+ procParms.setProperty(ReportEngineParameterNames.OUTPUT_REPOSITORY, subOutputRepository);
+ procParms.setProperty(ReportEngineParameterNames.INPUT_NAME, "content.xml");
+ procParms.setProperty(ReportEngineParameterNames.OUTPUT_NAME, "content.xml");
+ procParms.setProperty(ReportEngineParameterNames.CONTENT_TYPE, PentahoReportEngineMetaData.OPENDOCUMENT_CHART);
+ procParms.setProperty(ReportEngineParameterNames.INPUT_DATASOURCE_FACTORY, dataSourceFactory);
+ procParms.setProperty(ReportEngineParameterNames.INPUT_MASTER_COLUMNS, masterColumns);
+ procParms.setProperty(ReportEngineParameterNames.INPUT_MASTER_VALUES, masterValues);
+ procParms.setProperty(ReportEngineParameterNames.INPUT_DETAIL_COLUMNS, detailColumns);
+ procParms.setProperty(ReportEngineParameterNames.IMAGE_SERVICE, imageService);
+ procParms.setProperty(ReportEngineParameterNames.MAXROWS, maxRows);
+
+ engine.createJob(definition).execute();
+ }
+ catch (ReportExecutionException ex)
+ {
+ LOGGER.severe("ReportProcessing failed: " + ex);
+ }
+ catch (IOException ex)
+ {
+ LOGGER.severe("ReportProcessing failed: " + ex);
+ }
+ }
+ catch (IOException ex)
+ {
+ LOGGER.severe("ReportProcessing failed: " + ex);
+ } finally
+ {
+ if (subInputRepository != null)
+ {
+ subInputRepository.closeInputRepository();
+ }
+ if (subOutputRepository != null)
+ {
+ subOutputRepository.closeOutputRepository();
+ }
+ }
+ return output;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/StyleUtilities.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/StyleUtilities.java
new file mode 100644
index 000000000..98af0c3fa
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/StyleUtilities.java
@@ -0,0 +1,590 @@
+/*
+ * 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.output;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.DataStyle;
+import org.libreoffice.report.pentaho.model.FontFaceDeclsSection;
+import org.libreoffice.report.pentaho.model.FontFaceElement;
+import org.libreoffice.report.pentaho.model.OfficeStyle;
+import org.libreoffice.report.pentaho.model.OfficeStyles;
+import org.libreoffice.report.pentaho.model.OfficeStylesCollection;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.jfree.report.ReportProcessingException;
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+import org.jfree.report.util.AttributeNameGenerator;
+
+
+/**
+ * Todo: Document me!
+ *
+ * @since 13.03.2007
+ */
+public class StyleUtilities
+{
+
+ private static final Logger LOGGER = Logger.getLogger(StyleUtilities.class.getName());
+ private static final String STYLE = "style";
+
+ private StyleUtilities()
+ {
+ }
+
+ /**
+ * Copies the specified style (keyed by its family and name) into the current styles collection. This copies the
+ * style and all inherited styles into the target collection. Inherited common styles will be always be added to the
+ * common collection (which will be written into the 'styles.xml' later).
+ *
+ * <p>This method does nothing if the specified style already exists in the styles collection.</p>
+ *
+ * @param styleFamily the family of the style to copy
+ * @param styleName the unique name of the style.
+ * @param stylesCollection the current styles collection
+ * @param commonCollection the global styles collection
+ * @param predefCollection the predefined styles from where to copy the styles.
+ * @throws ReportProcessingException if the style copying failed.
+ */
+ public static void copyStyle(final String styleFamily,
+ final String styleName,
+ final OfficeStylesCollection stylesCollection,
+ final OfficeStylesCollection commonCollection,
+ final OfficeStylesCollection predefCollection)
+ throws ReportProcessingException
+ {
+ copyStyle(styleFamily, styleName, stylesCollection,
+ commonCollection, predefCollection, new HashSet<String>());
+ }
+
+ /**
+ * Copies the specified style (keyed by its family and name) into the current styles collection. This copies the
+ * style and all inherited styles into the target collection. Inherited common styles will be always be added to the
+ * common collection (which will be written into the 'styles.xml' later).
+ *
+ * <p>This method does nothing if the specified style already exists in the styles collection.</p>
+ *
+ * @param styleFamily the family of the style to copy
+ * @param styleName the unique name of the style.
+ * @param stylesCollection the current styles collection
+ * @param commonCollection the global styles collection
+ * @param predefCollection the predefined styles from where to copy the styles.
+ * @param inheritanceTracker a collection of all styles that have been touched. This is used to prevent infinite
+ * loops and duplicates.
+ * @throws ReportProcessingException if the style copying failed.
+ */
+ private static void copyStyle(final String styleFamily,
+ final String styleName,
+ final OfficeStylesCollection stylesCollection,
+ final OfficeStylesCollection commonCollection,
+ final OfficeStylesCollection predefCollection,
+ final Set<String> inheritanceTracker)
+ throws ReportProcessingException
+ {
+ if (inheritanceTracker.contains(styleName))
+ {
+ return;
+ }
+ inheritanceTracker.add(styleName);
+
+ if (stylesCollection.containsStyle(styleFamily, styleName) || commonCollection.getCommonStyles().containsStyle(styleFamily, styleName))
+ {
+ // fine, there's already a copy of the stylesheet.
+ return;
+ }
+
+ final OfficeStyle predefCommonStyle =
+ predefCollection.getCommonStyles().getStyle(styleFamily, styleName);
+ if (predefCommonStyle != null)
+ {
+ // so we have a style from the predefined collection.
+ // copy it an add it to the current stylescollection
+ final OfficeStyles commonStyles = commonCollection.getCommonStyles();
+
+ copyStyleInternal(predefCommonStyle, commonStyles, stylesCollection,
+ commonCollection, predefCollection, styleFamily, inheritanceTracker);
+ return;
+ }
+
+ final OfficeStyle predefAutoStyle =
+ predefCollection.getAutomaticStyles().getStyle(styleFamily, styleName);
+ if (predefAutoStyle != null)
+ {
+ // so we have a style from the predefined collection.
+ // copy it an add it to the current stylescollection
+ final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles();
+ copyStyleInternal(predefAutoStyle, autoStyles, stylesCollection,
+ commonCollection, predefCollection, styleFamily, inheritanceTracker);
+ return;
+ }
+
+ // There is no automatic style either. Now this means that someone
+ // messed up the fileformat. Lets create a new empty style for this.
+ final OfficeStyle autostyle = new OfficeStyle();
+ autostyle.setNamespace(OfficeNamespaces.STYLE_NS);
+ autostyle.setType(STYLE);
+ autostyle.setStyleFamily(styleFamily);
+ autostyle.setStyleName(styleName);
+
+ final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles();
+ autoStyles.addStyle(autostyle);
+ }
+
+ private static OfficeStyle copyStyleInternal(
+ final OfficeStyle predefCommonStyle,
+ final OfficeStyles styles,
+ final OfficeStylesCollection stylesCollection,
+ final OfficeStylesCollection commonCollection,
+ final OfficeStylesCollection predefCollection,
+ final String styleFamily,
+ final Set<String> inheritanceTracker)
+ throws ReportProcessingException
+ {
+ try
+ {
+ final OfficeStyle preStyle = (OfficeStyle) predefCommonStyle.clone();
+ styles.addStyle(preStyle);
+ performFontFaceProcessing(preStyle, stylesCollection, predefCollection);
+ performDataStyleProcessing(preStyle, stylesCollection, predefCollection);
+
+ // Lookup the parent style ..
+ final String styleParent = preStyle.getStyleParent();
+ final OfficeStyle inherited =
+ stylesCollection.getStyle(styleFamily, styleParent);
+ if (inherited != null)
+ {
+ // OK, recurse (and hope that we don't run into an infinite loop) ..
+ copyStyle(styleFamily, styleParent, stylesCollection,
+ commonCollection, predefCollection, inheritanceTracker);
+ }
+ else if (styleParent != null)
+ {
+ LOGGER.warning("Inconsistent styles: " + styleFamily + ":" + styleParent + " does not exist.");
+ }
+ return preStyle;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new ReportProcessingException("Failed to derive a stylesheet", e);
+ }
+ }
+
+ private static void performFontFaceProcessing(final OfficeStyle style,
+ final OfficeStylesCollection stylesCollection,
+ final OfficeStylesCollection predefCollection)
+ throws ReportProcessingException
+ {
+ final Element textProperties = style.getTextProperties();
+ if (textProperties == null)
+ {
+ return;
+ }
+
+ try
+ {
+ final FontFaceDeclsSection currentFonts = stylesCollection.getFontFaceDecls();
+ final FontFaceDeclsSection predefFonts = predefCollection.getFontFaceDecls();
+
+ final String fontName = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS, "font-name");
+ if (fontName != null && !currentFonts.containsFont(fontName))
+ {
+ final FontFaceElement element = predefFonts.getFontFace(fontName);
+ if (element != null)
+ {
+ currentFonts.addFontFace((FontFaceElement) element.clone());
+ }
+ }
+
+ final String fontNameAsian = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS,
+ "font-name-asian");
+ if (fontNameAsian != null && !currentFonts.containsFont(fontNameAsian))
+ {
+ final FontFaceElement element = predefFonts.getFontFace(
+ fontNameAsian);
+ if (element != null)
+ {
+ currentFonts.addFontFace((FontFaceElement) element.clone());
+ }
+ }
+
+ final String fontNameComplex = (String) textProperties.getAttribute(OfficeNamespaces.STYLE_NS,
+ "font-name-complex");
+ if (fontNameComplex != null && !currentFonts.containsFont(fontNameComplex))
+ {
+ final FontFaceElement element = predefFonts.getFontFace(
+ fontNameComplex);
+ if (element != null)
+ {
+ currentFonts.addFontFace((FontFaceElement) element.clone());
+ }
+ }
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new ReportProcessingException("Failed to clone font-face element", e);
+ }
+ }
+
+ private static void performDataStyleProcessing(final OfficeStyle style,
+ final OfficeStylesCollection stylesCollection,
+ final OfficeStylesCollection predefCollection)
+ throws ReportProcessingException
+ {
+ final Section derivedStyle = performDataStyleProcessing(style, stylesCollection, predefCollection, "data-style-name");
+ if (derivedStyle != null)
+ {
+ try
+ {
+ final Section styleMap = (Section) derivedStyle.findFirstChild(OfficeNamespaces.STYLE_NS, "map");
+ if (styleMap != null)
+ {
+ performDataStyleProcessing(styleMap, stylesCollection, predefCollection, "apply-style-name");
+ }
+ }
+ catch (Exception e)
+ {
+ }
+ }
+ }
+
+ private static Section performDataStyleProcessing(final Section style,
+ final OfficeStylesCollection stylesCollection,
+ final OfficeStylesCollection predefCollection,
+ final String attributeName)
+ throws ReportProcessingException
+ {
+ final Object attribute = style.getAttribute(OfficeNamespaces.STYLE_NS, attributeName);
+ final DataStyle derivedStyle;
+ if (attribute != null)
+ {
+ final String styleName = String.valueOf(attribute);
+ if (!stylesCollection.getAutomaticStyles().containsDataStyle(styleName) && !stylesCollection.getCommonStyles().containsDataStyle(styleName))
+ {
+ try
+ {
+ final OfficeStyles automaticStyles = predefCollection.getAutomaticStyles();
+ final DataStyle autoDataStyle = automaticStyles.getDataStyle(styleName);
+ if (autoDataStyle != null)
+ {
+ derivedStyle = (DataStyle) autoDataStyle.clone();
+ stylesCollection.getAutomaticStyles().addDataStyle(derivedStyle);
+ }
+ else
+ {
+ final OfficeStyles commonStyles = predefCollection.getCommonStyles();
+ final DataStyle commonDataStyle = commonStyles.getDataStyle(styleName);
+ if (commonDataStyle != null)
+ {
+ derivedStyle = (DataStyle) commonDataStyle.clone();
+ stylesCollection.getCommonStyles().addDataStyle(derivedStyle);
+ }
+ else
+ {
+ LOGGER.warning("Dangling data style: " + styleName);
+ derivedStyle = null;
+ }
+ }
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new ReportProcessingException("Failed to copy style. This should not have happened.", e);
+ }
+ }
+ else
+ {
+ derivedStyle = null;
+ }
+ }
+ else
+ {
+ derivedStyle = null;
+ }
+ return derivedStyle;
+ }
+
+ /**
+ * Derives the named style. If the style is a common style, a new automatic style is generated and inserted into the
+ * given stylesCollection. If the named style is an automatic style, the style is copied and inserted as new automatic
+ * style.
+ *
+ * <p>After the style has been created, the style's inheritance hierarchy will be copied as well.</p>
+ *
+ * <p>If there is no style with the given name and family, a new empty automatic style will be created.</p>
+ *
+ * @param styleFamily the family of the style to copy
+ * @param styleName the unique name of the style.
+ * @param stylesCollection the current styles collection
+ * @param commonCollection the global styles collection
+ * @param predefCollection the predefined styles from where to copy the styles.
+ * @param generator the style-name-generator of the current report-target
+ * @return the derived style instance.
+ * @throws ReportProcessingException if the style copying failed.
+ */
+ public static OfficeStyle deriveStyle(final String styleFamily,
+ final String styleName,
+ final OfficeStylesCollection stylesCollection,
+ final OfficeStylesCollection commonCollection,
+ final OfficeStylesCollection predefCollection,
+ final AttributeNameGenerator generator)
+ throws ReportProcessingException
+ {
+ if (styleFamily == null)
+ {
+ throw new NullPointerException("StyleFamily must not be null");
+ }
+ if (styleName != null)
+ {
+
+ final OfficeStyle currentAuto =
+ stylesCollection.getAutomaticStyles().getStyle(styleFamily,
+ styleName);
+ if (currentAuto != null)
+ {
+ // handle an automatic style ..
+ final OfficeStyle derivedStyle =
+ deriveAutomaticStyle(currentAuto, styleFamily, styleName,
+ generator, commonCollection, predefCollection);
+ stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
+ return derivedStyle;
+ }
+
+ final OfficeStyle currentCommon =
+ stylesCollection.getCommonStyles().getStyle(styleFamily, styleName);
+ if (currentCommon != null)
+ {
+ // handle a common style ..
+ final OfficeStyle derivedStyle =
+ deriveCommonStyle(currentCommon, styleFamily, styleName,
+ generator, commonCollection, predefCollection);
+ stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
+ return derivedStyle;
+ }
+
+ final OfficeStyle commonCommon =
+ commonCollection.getCommonStyles().getStyle(styleFamily, styleName);
+ if (commonCommon != null)
+ {
+ // handle a common style ..
+ final OfficeStyle derivedStyle =
+ deriveCommonStyle(commonCommon, styleFamily, styleName,
+ generator, commonCollection, predefCollection);
+ stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
+ return derivedStyle;
+ }
+
+ final OfficeStyle predefAuto =
+ predefCollection.getAutomaticStyles().getStyle(styleFamily,
+ styleName);
+ if (predefAuto != null)
+ {
+ // handle an automatic style ..
+ final OfficeStyle derivedStyle =
+ deriveAutomaticStyle(predefAuto, styleFamily, styleName,
+ generator, commonCollection, predefCollection);
+ stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
+ return derivedStyle;
+ }
+
+ final OfficeStyle predefCommon =
+ predefCollection.getCommonStyles().getStyle(styleFamily, styleName);
+ if (predefCommon != null)
+ {
+ // handle a common style ..
+ final OfficeStyle derivedStyle =
+ deriveCommonStyle(predefCommon, styleFamily, styleName,
+ generator, commonCollection, predefCollection);
+ stylesCollection.getAutomaticStyles().addStyle(derivedStyle);
+ return derivedStyle;
+ }
+ }
+
+ // No such style. Create a new one ..
+ final OfficeStyle autostyle = new OfficeStyle();
+ autostyle.setNamespace(OfficeNamespaces.STYLE_NS);
+ autostyle.setType(STYLE);
+ autostyle.setStyleFamily(styleFamily);
+ if (styleName != null)
+ {
+ autostyle.setStyleName(styleName);
+ }
+ else
+ {
+ autostyle.setStyleName(generator.generateName("derived_anonymous"));
+ }
+
+ final OfficeStyles autoStyles = stylesCollection.getAutomaticStyles();
+ autoStyles.addStyle(autostyle);
+ return autostyle;
+ }
+
+ private static OfficeStyle deriveCommonStyle(final OfficeStyle commonStyle,
+ final String styleFamily,
+ final String styleName,
+ final AttributeNameGenerator nameGenerator,
+ final OfficeStylesCollection commonCollection,
+ final OfficeStylesCollection predefCollection)
+ throws ReportProcessingException
+ {
+ final OfficeStyle autostyle = new OfficeStyle();
+ autostyle.setNamespace(OfficeNamespaces.STYLE_NS);
+ autostyle.setType(STYLE);
+ autostyle.setStyleFamily(styleFamily);
+ autostyle.setStyleName(nameGenerator.generateName("derived_" + styleName));
+ autostyle.setStyleParent(styleName);
+
+ // now copy the common style ..
+ final OfficeStyles commonStyles = commonCollection.getCommonStyles();
+ if (!commonStyles.containsStyle(styleFamily, styleName))
+ {
+ copyStyleInternal(commonStyle, commonStyles,
+ commonCollection, commonCollection, predefCollection,
+ styleFamily, new HashSet<String>());
+ }
+ return autostyle;
+ }
+
+ private static OfficeStyle deriveAutomaticStyle(final OfficeStyle commonStyle,
+ final String styleFamily,
+ final String styleName,
+ final AttributeNameGenerator nameGenerator,
+ final OfficeStylesCollection commonCollection,
+ final OfficeStylesCollection predefCollection)
+ throws ReportProcessingException
+ {
+ try
+ {
+ final OfficeStyle autostyle = (OfficeStyle) commonStyle.clone();
+ autostyle.setNamespace(OfficeNamespaces.STYLE_NS);
+ autostyle.setType(STYLE);
+ autostyle.setStyleFamily(styleFamily);
+ autostyle.setStyleName(nameGenerator.generateName("derived_auto_" + styleName));
+
+
+ final String parent = autostyle.getStyleParent();
+ if (parent != null)
+ {
+ copyStyle(styleFamily, parent, commonCollection, commonCollection,
+ predefCollection);
+ }
+ return autostyle;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new ReportProcessingException(
+ "Deriving the style failed. Clone error: ", e);
+ }
+ }
+
+ public static String queryStyle(final OfficeStylesCollection predefCollection,
+ final String styleFamily,
+ final String styleName,
+ final String sectionName,
+ final String propertyNamespace,
+ final String propertyName)
+ {
+ return queryStyle(predefCollection, styleFamily,
+ styleName, sectionName, propertyNamespace, propertyName, new HashSet<String>());
+ }
+
+ public static OfficeStyle queryStyleByProperties(final OfficeStylesCollection predefCollection,
+ final String styleFamily,
+ final String sectionName,
+ final ArrayList<?> propertyNamespace,
+ final ArrayList<?> propertyName,
+ final ArrayList<?> propertyValues)
+ {
+ if (propertyNamespace.size() != propertyName.size())
+ {
+ return null;
+ }
+ final OfficeStyle[] styles = predefCollection.getAutomaticStyles().getAllStyles();
+ for (int i = 0; i < styles.length; i++)
+ {
+ final OfficeStyle officeStyle = styles[i];
+ if (officeStyle.getStyleFamily().equals(styleFamily))
+ {
+ final Element section = officeStyle.findFirstChild(OfficeNamespaces.STYLE_NS, sectionName);
+ if (section != null)
+ {
+ int j = 0;
+ for (; j < propertyNamespace.size(); j++)
+ {
+ final String ns = (String) propertyNamespace.get(j);
+ final String prop = (String) propertyName.get(j);
+ final Object obj = section.getAttribute(ns, prop);
+ final Object value = propertyValues.get(j);
+ if (obj == null || value == null)
+ {
+ continue;
+ }
+ if (!propertyValues.get(j).equals(obj))
+ {
+ break;
+ }
+ }
+ if (j == propertyName.size())
+ {
+ return officeStyle;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static String queryStyle(final OfficeStylesCollection predefCollection,
+ final String styleFamily,
+ final String styleName,
+ final String sectionName,
+ final String propertyNamespace,
+ final String propertyName,
+ final Set<String> seenStyles)
+ {
+ if (seenStyles.contains(styleName))
+ {
+ return null;
+ }
+ seenStyles.add(styleName);
+
+ final OfficeStyle style = predefCollection.getStyle(styleFamily, styleName);
+ if (style == null)
+ {
+ return null; // no such style
+
+ }
+ final Element section = style.findFirstChild(OfficeNamespaces.STYLE_NS, sectionName);
+ if (section != null)
+ {
+ final Object attribute = section.getAttribute(propertyNamespace, propertyName);
+ if (attribute != null)
+ {
+ return String.valueOf(attribute);
+ }
+ }
+ final String parent = style.getStyleParent();
+ if (parent == null)
+ {
+ return null;
+ }
+ return queryStyle(predefCollection, styleFamily, parent, sectionName, propertyNamespace, propertyName, seenStyles);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/StylesWriter.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/StylesWriter.java
new file mode 100644
index 000000000..4797d2ad4
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/StylesWriter.java
@@ -0,0 +1,379 @@
+/*
+ * 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.output;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.DataStyle;
+import org.libreoffice.report.pentaho.model.FontFaceDeclsSection;
+import org.libreoffice.report.pentaho.model.FontFaceElement;
+import org.libreoffice.report.pentaho.model.OfficeMasterPage;
+import org.libreoffice.report.pentaho.model.OfficeMasterStyles;
+import org.libreoffice.report.pentaho.model.OfficeStyle;
+import org.libreoffice.report.pentaho.model.OfficeStyles;
+import org.libreoffice.report.pentaho.model.OfficeStylesCollection;
+import org.libreoffice.report.pentaho.model.PageLayout;
+import org.libreoffice.report.pentaho.model.RawText;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.jfree.layouting.namespace.Namespaces;
+import org.jfree.layouting.util.AttributeMap;
+import org.jfree.report.JFreeReportBoot;
+import org.jfree.report.JFreeReportInfo;
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Node;
+import org.jfree.report.structure.Section;
+import org.jfree.report.structure.StaticText;
+
+import org.pentaho.reporting.libraries.xmlns.common.AttributeList;
+import org.pentaho.reporting.libraries.xmlns.writer.DefaultTagDescription;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriter;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriterSupport;
+
+
+/**
+ * This class writes the style collection into a 'styles.xml' document.
+ *
+ * @since 09.03.2007
+ */
+public class StylesWriter
+{
+
+ private final XmlWriter xmlWriter;
+ private final boolean writeOpeningTag;
+
+ public StylesWriter(final Writer writer)
+ {
+ final DefaultTagDescription tagDescription = new DefaultTagDescription();
+ tagDescription.configure(JFreeReportBoot.getInstance().getGlobalConfig(),
+ OfficeDocumentReportTarget.TAG_DEF_PREFIX);
+
+ this.xmlWriter = new XmlWriter(writer, tagDescription);
+ this.xmlWriter.setAlwaysAddNamespace(true);
+ this.writeOpeningTag = true;
+ }
+
+ public StylesWriter(final XmlWriter xmlWriter)
+ {
+ this.xmlWriter = xmlWriter;
+ this.writeOpeningTag = false;
+ }
+
+ public void writeContentStyles(
+ final OfficeStylesCollection globals)
+ throws IOException
+ {
+ writeFontFaces(new OfficeStylesCollection[]
+ {
+ globals
+ });
+ writeAutomaticStylesSection(new OfficeStylesCollection[]
+ {
+ globals
+ });
+ }
+
+ public void writeGlobalStyles(
+ final OfficeStylesCollection globals)
+ throws IOException
+ {
+ if (writeOpeningTag)
+ {
+ performWriteRootTag();
+ }
+
+ writeFontFaces(new OfficeStylesCollection[]
+ {
+ globals
+ });
+ writeCommonStylesSection(new OfficeStylesCollection[]
+ {
+ globals
+ });
+ writeAutomaticStylesSection(new OfficeStylesCollection[]
+ {
+ globals
+ });
+ writeMasterStylesSection(new OfficeStylesCollection[]
+ {
+ globals
+ });
+
+ if (writeOpeningTag)
+ {
+ xmlWriter.writeCloseTag();
+ }
+ }
+
+ private void writeMasterStylesSection(final OfficeStylesCollection[] osc)
+ throws IOException
+ {
+ xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "master-styles", XmlWriterSupport.OPEN);
+ for (int sci = 0; sci < osc.length; sci++)
+ {
+ final OfficeStylesCollection collection = osc[sci];
+ final OfficeMasterStyles officeStyles = collection.getMasterStyles();
+ final OfficeMasterPage[] officeMasterPages = officeStyles.getAllMasterPages();
+ for (int i = 0; i < officeMasterPages.length; i++)
+ {
+ final OfficeMasterPage masterPage = officeMasterPages[i];
+ writeSection(masterPage);
+ }
+
+ writeSectionChildren(officeStyles.getOtherNodes().getNodeArray());
+ }
+
+ xmlWriter.writeCloseTag();
+ }
+
+ private void writeCommonStylesSection(final OfficeStylesCollection[] osc)
+ throws IOException
+ {
+ xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "styles", XmlWriterSupport.OPEN);
+
+ for (int sci = 0; sci < osc.length; sci++)
+ {
+ final OfficeStylesCollection collection = osc[sci];
+ final OfficeStyles officeStyles = collection.getCommonStyles();
+ writeStyles(officeStyles);
+ }
+
+ xmlWriter.writeCloseTag();
+ }
+
+ private void writeAutomaticStylesSection(final OfficeStylesCollection[] osc)
+ throws IOException
+ {
+ xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "automatic-styles", XmlWriterSupport.OPEN);
+ for (int sci = 0; sci < osc.length; sci++)
+ {
+ final OfficeStylesCollection collection = osc[sci];
+ final OfficeStyles officeStyles = collection.getAutomaticStyles();
+ writeStyles(officeStyles);
+ }
+
+ xmlWriter.writeCloseTag();
+ }
+
+ private void writeFontFaces(final OfficeStylesCollection[] osc)
+ throws IOException
+ {
+ xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "font-face-decls", XmlWriterSupport.OPEN);
+
+ final TreeMap<String,FontFaceElement> fontFaces = new TreeMap<String,FontFaceElement>();
+ for (int sci = 0; sci < osc.length; sci++)
+ {
+ final OfficeStylesCollection collection = osc[sci];
+ final FontFaceDeclsSection fontFaceDecls = collection.getFontFaceDecls();
+ final FontFaceElement[] fontFaceElements = fontFaceDecls.getAllFontFaces();
+ for (int i = 0; i < fontFaceElements.length; i++)
+ {
+ final FontFaceElement element = fontFaceElements[i];
+ fontFaces.put(element.getStyleName(), element);
+ }
+ }
+
+ final Iterator<FontFaceElement> values = fontFaces.values().iterator();
+ while (values.hasNext())
+ {
+ final FontFaceElement element = values.next();
+ writeElement(element);
+ }
+
+ xmlWriter.writeCloseTag();
+ }
+
+ private void writeStyles(final OfficeStyles styles)
+ throws IOException
+ {
+ final OfficeStyle[] allStyles = styles.getAllStyles();
+ for (int i = 0; i < allStyles.length; i++)
+ {
+ final OfficeStyle style = allStyles[i];
+ writeSection(style);
+ }
+
+ final DataStyle[] allDataStyles = styles.getAllDataStyles();
+ for (int i = 0; i < allDataStyles.length; i++)
+ {
+ final DataStyle style = allDataStyles[i];
+ writeSection(style);
+ }
+
+ final PageLayout[] allPageStyles = styles.getAllPageStyles();
+ for (int i = 0; i < allPageStyles.length; i++)
+ {
+ final PageLayout style = allPageStyles[i];
+ writeSection(style);
+ }
+
+ writeSectionChildren(styles.getOtherStyles());
+ }
+
+ private void writeElement(final Element element)
+ throws IOException
+ {
+ final String type = element.getType();
+ final String namespace = element.getNamespace();
+ final AttributeList attrList = buildAttributeList(element.getAttributeMap());
+ xmlWriter.writeTag(namespace, type, attrList, XmlWriterSupport.CLOSE);
+ }
+
+ private void writeSection(final Section section)
+ throws IOException
+ {
+ final String type = section.getType();
+ final String namespace = section.getNamespace();
+ final AttributeList attrList = buildAttributeList(section.getAttributeMap());
+ if (section.getNodeCount() == 0)
+ {
+ xmlWriter.writeTag(namespace, type, attrList, XmlWriterSupport.CLOSE);
+ return;
+ }
+
+ xmlWriter.writeTag(namespace, type, attrList, XmlWriterSupport.OPEN);
+ writeSectionChildren(section.getNodeArray());
+
+ xmlWriter.writeCloseTag();
+ }
+
+ private void writeSectionChildren(final Node[] nodes)
+ throws IOException
+ {
+ for (int i = 0; i < nodes.length; i++)
+ {
+ final Node node = nodes[i];
+ if (node instanceof Section)
+ {
+ writeSection((Section) node);
+ }
+ else if (node instanceof Element)
+ {
+ writeElement((Element) node);
+ }
+ else if (node instanceof RawText)
+ {
+ final RawText text = (RawText) node;
+ xmlWriter.writeText(text.getText());
+ }
+ else if (node instanceof StaticText)
+ {
+ final StaticText text = (StaticText) node;
+ xmlWriter.writeTextNormalized(text.getText(), false);
+ }
+ }
+ }
+
+ private AttributeList buildAttributeList(final AttributeMap attrs)
+ {
+ final AttributeList attrList = new AttributeList();
+ final String[] namespaces = attrs.getNameSpaces();
+ for (int i = 0; i < namespaces.length; i++)
+ {
+ final String attrNamespace = namespaces[i];
+ if (isFilteredNamespace(attrNamespace))
+ {
+ continue;
+ }
+
+ final Map localAttributes = attrs.getAttributes(attrNamespace);
+ final Iterator entries = localAttributes.entrySet().iterator();
+ while (entries.hasNext())
+ {
+ final Map.Entry entry = (Map.Entry) entries.next();
+ final String key = String.valueOf(entry.getKey());
+ attrList.setAttribute(attrNamespace, key, String.valueOf(entry.getValue()));
+ }
+ }
+ return attrList;
+ }
+
+ private boolean isFilteredNamespace(final String namespace)
+ {
+ if (Namespaces.LIBLAYOUT_NAMESPACE.equals(namespace))
+ {
+ return true;
+ }
+ if (JFreeReportInfo.REPORT_NAMESPACE.equals(namespace))
+ {
+ return true;
+ }
+ if (JFreeReportInfo.COMPATIBILITY_NAMESPACE.equals(namespace))
+ {
+ return true;
+ }
+ if (OfficeNamespaces.OOREPORT_NS.equals(namespace))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ private void performWriteRootTag()
+ throws IOException
+ {
+ final AttributeList rootAttributes = new AttributeList();
+ rootAttributes.addNamespaceDeclaration("office",
+ OfficeNamespaces.OFFICE_NS);
+ rootAttributes.addNamespaceDeclaration("style", OfficeNamespaces.STYLE_NS);
+ rootAttributes.addNamespaceDeclaration("text", OfficeNamespaces.TEXT_NS);
+ rootAttributes.addNamespaceDeclaration("table", OfficeNamespaces.TABLE_NS);
+ rootAttributes.addNamespaceDeclaration("draw", OfficeNamespaces.DRAWING_NS);
+ rootAttributes.addNamespaceDeclaration("fo", OfficeNamespaces.FO_NS);
+ rootAttributes.addNamespaceDeclaration("xlink", OfficeNamespaces.XLINK_NS);
+ rootAttributes.addNamespaceDeclaration("dc", OfficeNamespaces.PURL_NS);
+ rootAttributes.addNamespaceDeclaration("meta", OfficeNamespaces.META_NS);
+ rootAttributes.addNamespaceDeclaration("number",
+ OfficeNamespaces.DATASTYLE_NS);
+ rootAttributes.addNamespaceDeclaration("svg", OfficeNamespaces.SVG_NS);
+ rootAttributes.addNamespaceDeclaration("chart", OfficeNamespaces.CHART_NS);
+ rootAttributes.addNamespaceDeclaration("chartooo", OfficeNamespaces.CHARTOOO_NS);
+ rootAttributes.addNamespaceDeclaration("dr3d", OfficeNamespaces.DR3D_NS);
+ rootAttributes.addNamespaceDeclaration("math", OfficeNamespaces.MATHML_NS);
+ rootAttributes.addNamespaceDeclaration("form", OfficeNamespaces.FORM_NS);
+ rootAttributes.addNamespaceDeclaration("script",
+ OfficeNamespaces.SCRIPT_NS);
+ rootAttributes.addNamespaceDeclaration("ooo", OfficeNamespaces.OO2004_NS);
+ rootAttributes.addNamespaceDeclaration("ooow", OfficeNamespaces.OOW2004_NS);
+ rootAttributes.addNamespaceDeclaration("oooc", OfficeNamespaces.OOC2004_NS);
+ rootAttributes.addNamespaceDeclaration("dom",
+ OfficeNamespaces.XML_EVENT_NS);
+ rootAttributes.addNamespaceDeclaration("xforms",
+ OfficeNamespaces.XFORMS_NS);
+ rootAttributes.addNamespaceDeclaration("xsd", OfficeNamespaces.XSD_NS);
+ rootAttributes.addNamespaceDeclaration("xsi", OfficeNamespaces.XSI_NS);
+ rootAttributes.addNamespaceDeclaration("grddl", OfficeNamespaces.GRDDL_NS);
+ rootAttributes.setAttribute(OfficeNamespaces.OFFICE_NS, "version",
+ OfficeDocumentReportTarget.ODF_VERSION);
+
+ this.xmlWriter.writeXmlDeclaration("UTF-8");
+ this.xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS,
+ "document-styles", rootAttributes, XmlWriterSupport.OPEN);
+ }
+
+ public void close()
+ throws IOException
+ {
+ xmlWriter.close();
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/chart/ChartRawReportProcessor.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/chart/ChartRawReportProcessor.java
new file mode 100644
index 000000000..544b40506
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/chart/ChartRawReportProcessor.java
@@ -0,0 +1,98 @@
+/*
+ * 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.output.chart;
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.OutputRepository;
+
+import org.jfree.report.DataSourceException;
+import org.jfree.report.ReportDataFactoryException;
+import org.jfree.report.ReportProcessingException;
+import org.jfree.report.flow.ReportJob;
+import org.jfree.report.flow.ReportStructureRoot;
+import org.jfree.report.flow.ReportTarget;
+import org.jfree.report.flow.SinglePassReportProcessor;
+
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+
+/**
+ *
+ */
+public class ChartRawReportProcessor extends SinglePassReportProcessor
+{
+
+ private final OutputRepository outputRepository;
+ private final String targetName;
+ private final InputRepository inputRepository;
+ private final ImageService imageService;
+ private final DataSourceFactory dataSourceFactory;
+
+ public ChartRawReportProcessor(final InputRepository inputRepository,
+ final OutputRepository outputRepository,
+ final String targetName,
+ final ImageService imageService,
+ final DataSourceFactory dataSourceFactory)
+ {
+ if (inputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (outputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (targetName == null)
+ {
+ throw new NullPointerException();
+ }
+ if (imageService == null)
+ {
+ throw new NullPointerException();
+ }
+ if (dataSourceFactory == null)
+ {
+ throw new NullPointerException();
+ }
+ this.targetName = targetName;
+ this.inputRepository = inputRepository;
+ this.outputRepository = outputRepository;
+ this.imageService = imageService;
+ this.dataSourceFactory = dataSourceFactory;
+ }
+
+ @Override
+ protected ReportTarget createReportTarget(final ReportJob job)
+ throws ReportProcessingException
+ {
+ final ReportStructureRoot report = job.getReportStructureRoot();
+ final ResourceManager resourceManager = report.getResourceManager();
+
+ return new ChartRawReportTarget(job, resourceManager, report.getBaseResource(),
+ inputRepository, outputRepository, targetName, imageService, dataSourceFactory);
+ }
+
+ @Override
+ public void processReport(final ReportJob job) throws ReportDataFactoryException, DataSourceException,
+ ReportProcessingException
+ {
+ final ReportTarget reportTarget = createReportTarget(job);
+ processReportRun(job, reportTarget);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/chart/ChartRawReportTarget.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/chart/ChartRawReportTarget.java
new file mode 100644
index 000000000..1029b14b2
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/chart/ChartRawReportTarget.java
@@ -0,0 +1,255 @@
+/*
+ * 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.output.chart;
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.PentahoReportEngineMetaData;
+import org.libreoffice.report.pentaho.output.OfficeDocumentReportTarget;
+
+import java.io.IOException;
+import org.jfree.layouting.util.AttributeMap;
+import org.jfree.report.DataFlags;
+import org.jfree.report.DataSourceException;
+import org.jfree.report.ReportProcessingException;
+import org.jfree.report.flow.ReportJob;
+import org.jfree.report.flow.ReportStructureRoot;
+import org.jfree.report.flow.ReportTargetUtil;
+
+import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+import org.pentaho.reporting.libraries.xmlns.common.AttributeList;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriter;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriterSupport;
+
+public class ChartRawReportTarget extends OfficeDocumentReportTarget
+{
+
+ private boolean inFilterElements = false;
+ private boolean tableRowsStarted = false;
+ private int tableCount = 0;
+ private int closeTags = 0;
+
+ public ChartRawReportTarget(final ReportJob reportJob,
+ final ResourceManager resourceManager,
+ final ResourceKey baseResource,
+ final InputRepository inputRepository,
+ final OutputRepository outputRepository,
+ final String target,
+ final ImageService imageService,
+ final DataSourceFactory dataSourceFactory)
+ throws ReportProcessingException
+ {
+ super(reportJob, resourceManager, baseResource, inputRepository, outputRepository, target, imageService, dataSourceFactory);
+ }
+
+ @Override
+ protected String getTargetMimeType()
+ {
+ return "application/vnd.oasis.opendocument.chart";
+ }
+
+ private String getStartContent()
+ {
+ return "chart";
+ }
+
+ public String getExportDescriptor()
+ {
+ return "raw/" + PentahoReportEngineMetaData.OPENDOCUMENT_CHART;
+ }
+
+ @Override
+ protected void startContent(final AttributeMap attrs) throws IOException, DataSourceException, ReportProcessingException
+ {
+ inFilterElements = false;
+ closeTags = 0;
+ tableCount = 0;
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, getStartContent(), null, XmlWriterSupport.OPEN);
+ writeNullDate();
+ ++closeTags;
+ }
+
+ @Override
+ protected void endContent(final AttributeMap attrs) throws IOException, DataSourceException, ReportProcessingException
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+ while (closeTags > 0)
+ {
+ xmlWriter.writeCloseTag();
+ --closeTags;
+ }
+ }
+
+ @Override
+ protected void startReportSection(final AttributeMap attrs, final int role)
+ throws ReportProcessingException
+ {
+ }
+
+ @Override
+ protected void endReportSection(final AttributeMap attrs, final int role)
+ {
+ }
+
+ @Override
+ protected void startOther(final AttributeMap attrs) throws IOException, DataSourceException, ReportProcessingException
+ {
+ final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
+ if (!isFilteredNamespace(namespace))
+ {
+ final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
+ try
+ {
+ processElement(attrs, namespace, elementType);
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException(OfficeDocumentReportTarget.FAILED, e);
+ }
+ }
+ }
+
+ private boolean isFiltered(final String elementType)
+ {
+ return OfficeToken.TABLE_HEADER_COLUMNS.equals(elementType) || OfficeToken.TABLE_HEADER_ROWS.equals(elementType) || OfficeToken.TABLE_COLUMNS.equals(elementType);
+ }
+
+ @Override
+ protected void endOther(final AttributeMap attrs) throws IOException, DataSourceException, ReportProcessingException
+ {
+ if (tableRowsStarted && getCurrentRole() == ROLE_TEMPLATE)
+ {
+ return;
+ }
+ final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
+ if (isFilteredNamespace(namespace))
+ return;
+
+ final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
+ // if this is the report namespace, write out a table definition ..
+ if (OfficeNamespaces.TABLE_NS.equals(namespace))
+ {
+ if (OfficeToken.TABLE.equals(elementType) || OfficeToken.TABLE_ROWS.equals(elementType))
+ {
+ return;
+ }
+ else if (isFiltered(elementType))
+ {
+ inFilterElements = false;
+ if (tableCount > 1)
+ {
+ return;
+ }
+ }
+ }
+ else if (OfficeNamespaces.CHART_NS.equals(namespace) && "chart".equals(elementType))
+ {
+ return;
+ }
+ if (inFilterElements && tableCount > 1)
+ {
+ return;
+ }
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeCloseTag();
+ --closeTags;
+ }
+
+ @Override
+ public void processContent(final DataFlags value)
+ throws DataSourceException, ReportProcessingException
+ {
+ if (!(tableRowsStarted && getCurrentRole() == ROLE_TEMPLATE))
+ {
+ super.processContent(value);
+ }
+ }
+
+ private void processElement(final AttributeMap attrs, final String namespace, final String elementType)
+ throws IOException, ReportProcessingException
+ {
+ if (tableRowsStarted && getCurrentRole() == ROLE_TEMPLATE)
+ {
+ return;
+ }
+ if (OfficeNamespaces.TABLE_NS.equals(namespace))
+ {
+ if (OfficeToken.TABLE.equals(elementType))
+ {
+ tableCount += 1;
+ if (tableCount > 1)
+ {
+ return;
+ }
+ }
+ else if (OfficeToken.TABLE_ROWS.equals(elementType))
+ {
+ if (tableCount > 1)
+ {
+ return;
+ }
+ tableRowsStarted = true;
+ }
+ else if (isFiltered(elementType))
+ {
+ inFilterElements = true;
+ if (tableCount > 1)
+ {
+ return;
+ }
+ }
+ }
+ if (inFilterElements && tableCount > 1)
+ {
+ return;
+ }
+
+ // All styles have to be processed or you will lose the paragraph-styles and inline text-styles.
+ performStyleProcessing(attrs);
+
+ final AttributeList attrList = buildAttributeList(attrs);
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeTag(namespace, elementType, attrList, XmlWriter.OPEN);
+ ++closeTags;
+ }
+
+
+ @Override
+ public void processText(final String text) throws DataSourceException, ReportProcessingException
+ {
+ if (inFilterElements && tableCount > 1)
+ {
+ return;
+ }
+ super.processText(text);
+ }
+
+ @Override
+ public void endReport(final ReportStructureRoot report)
+ throws DataSourceException, ReportProcessingException
+ {
+ super.endReport(report);
+ copyMeta();
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/spreadsheet/SpreadsheetRawReportProcessor.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/spreadsheet/SpreadsheetRawReportProcessor.java
new file mode 100644
index 000000000..6283a6ce1
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/spreadsheet/SpreadsheetRawReportProcessor.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.output.spreadsheet;
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.pentaho.PentahoFormulaContext;
+
+import org.jfree.report.DataSourceException;
+import org.jfree.report.ReportDataFactoryException;
+import org.jfree.report.ReportProcessingException;
+import org.jfree.report.data.ReportContextImpl;
+import org.jfree.report.flow.AbstractReportProcessor;
+import org.jfree.report.flow.ReportContext;
+import org.jfree.report.flow.ReportJob;
+import org.jfree.report.flow.ReportStructureRoot;
+import org.jfree.report.flow.ReportTarget;
+
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+
+public class SpreadsheetRawReportProcessor extends AbstractReportProcessor
+{
+
+ private final OutputRepository outputRepository;
+ private final String targetName;
+ private final InputRepository inputRepository;
+ private final ImageService imageService;
+ private final DataSourceFactory dataSourceFactory;
+
+ public SpreadsheetRawReportProcessor(final InputRepository inputRepository,
+ final OutputRepository outputRepository,
+ final String targetName,
+ final ImageService imageService,
+ final DataSourceFactory dataSourceFactory)
+ {
+ if (outputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (targetName == null)
+ {
+ throw new NullPointerException();
+ }
+ if (imageService == null)
+ {
+ throw new NullPointerException();
+ }
+ if (inputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (dataSourceFactory == null)
+ {
+ throw new NullPointerException();
+ }
+
+ this.targetName = targetName;
+ this.inputRepository = inputRepository;
+ this.outputRepository = outputRepository;
+ this.imageService = imageService;
+ this.dataSourceFactory = dataSourceFactory;
+ }
+
+ private ReportTarget createReportTarget(final ReportJob job) throws ReportProcessingException
+ {
+ final ReportStructureRoot report = job.getReportStructureRoot();
+ final ResourceManager resourceManager = report.getResourceManager();
+ return new SpreadsheetRawReportTarget(job, resourceManager, report.getBaseResource(), inputRepository, outputRepository, targetName, imageService, dataSourceFactory);
+ }
+
+ public void processReport(final ReportJob job) throws ReportDataFactoryException, DataSourceException,
+ ReportProcessingException
+ {
+ final ReportTarget reportTarget = createReportTarget(job);
+ // first run: collect table cell sizes for all tables
+ processReportRun(job, reportTarget);
+ // second run: uses table cell data to output a single uniform table
+ processReportRun(job, reportTarget);
+ }
+
+ @Override
+ protected ReportContext createReportContext(final ReportJob job,
+ final ReportTarget target)
+ {
+ final ReportContext context = super.createReportContext(job, target);
+ if (context instanceof ReportContextImpl)
+ {
+ final ReportContextImpl impl = (ReportContextImpl) context;
+ impl.setFormulaContext(new PentahoFormulaContext(impl.getFormulaContext(), job.getConfiguration()));
+ }
+ return context;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/spreadsheet/SpreadsheetRawReportTarget.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/spreadsheet/SpreadsheetRawReportTarget.java
new file mode 100644
index 000000000..b1d979e7b
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/spreadsheet/SpreadsheetRawReportTarget.java
@@ -0,0 +1,944 @@
+/*
+ * 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.output.spreadsheet;
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.PentahoReportEngineMetaData;
+import org.libreoffice.report.pentaho.model.OfficeMasterPage;
+import org.libreoffice.report.pentaho.model.OfficeMasterStyles;
+import org.libreoffice.report.pentaho.model.OfficeStyle;
+import org.libreoffice.report.pentaho.model.OfficeStyles;
+import org.libreoffice.report.pentaho.model.OfficeStylesCollection;
+import org.libreoffice.report.pentaho.model.PageSection;
+import org.libreoffice.report.pentaho.output.OfficeDocumentReportTarget;
+import org.libreoffice.report.pentaho.output.StyleUtilities;
+import org.libreoffice.report.pentaho.output.text.MasterPageFactory;
+import org.libreoffice.report.pentaho.styles.LengthCalculator;
+
+import java.io.IOException;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.jfree.layouting.input.style.values.CSSNumericType;
+import org.jfree.layouting.input.style.values.CSSNumericValue;
+import org.jfree.layouting.util.AttributeMap;
+import org.jfree.report.DataFlags;
+import org.jfree.report.DataSourceException;
+import org.jfree.report.JFreeReportInfo;
+import org.jfree.report.ReportProcessingException;
+import org.jfree.report.flow.ReportJob;
+import org.jfree.report.flow.ReportStructureRoot;
+import org.jfree.report.flow.ReportTargetUtil;
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+import org.jfree.report.util.IntegerCache;
+
+import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+import org.pentaho.reporting.libraries.xmlns.common.AttributeList;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriter;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriterSupport;
+
+
+/**
+ * Creation-Date: 03.11.2007
+ *
+ */
+public class SpreadsheetRawReportTarget extends OfficeDocumentReportTarget
+{
+
+ private static final String[] FOPROPS = new String[]
+ {
+ "letter-spacing", "font-variant", "text-transform"
+ };
+ private static final String NUMBERCOLUMNSSPANNED = "number-columns-spanned";
+ private static final String[] STYLEPROPS = new String[]
+ {
+ "text-combine", "font-pitch-complex", "text-rotation-angle", "font-name", "text-blinking", "letter-kerning", "text-combine-start-char", "text-combine-end-char", "text-position", "text-scale"
+ };
+ private static final int CELL_WIDTH_FACTOR = 10000;
+ private static final String TRANSPARENT = "transparent";
+ private boolean paragraphFound = false;
+ private boolean paragraphHandled = false;
+
+ /**
+ * This class represents a column boundary, not in width, but it's actual boundary location. One of the motivations
+ * for creating this class was to be able to record the boundaries for each incoming table while consuming as few
+ * objects/memory as possible.
+ */
+ private static class ColumnBoundary implements Comparable<ColumnBoundary>
+ {
+
+ private final Set<Integer> tableIndices;
+ private final long boundary;
+
+ private ColumnBoundary(final long boundary)
+ {
+ this.tableIndices = new HashSet<Integer>();
+ this.boundary = boundary;
+ }
+
+ public void addTableIndex(final int table)
+ {
+ tableIndices.add(IntegerCache.getInteger(table));
+ }
+
+ public float getBoundary()
+ {
+ return boundary;
+ }
+
+ public boolean isContainedByTable(final int table)
+ {
+ final Integer index = IntegerCache.getInteger(table);
+ return tableIndices.contains(index);
+ }
+
+ public int compareTo(final ColumnBoundary arg0)
+ {
+ if (arg0.equals(this))
+ {
+ return 0;
+ }
+ if (boundary > arg0.boundary)
+ {
+ return 1;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ @Override
+ public boolean equals(final Object obj)
+ {
+ return obj instanceof ColumnBoundary && ((ColumnBoundary) obj).boundary == boundary;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ assert false : "hashCode not designed";
+ return 42; // any arbitrary constant will do
+ }
+ }
+ private String tableBackgroundColor; // null means transparent ...
+ private boolean elementBoundaryCollectionPass;
+ private boolean oleHandled;
+ private final List<ColumnBoundary> columnBoundaryList;
+ private long currentRowBoundaryMarker;
+ private ColumnBoundary[] sortedBoundaryArray;
+ private ColumnBoundary[] boundariesForTableArray;
+ private int tableCounter;
+ private int columnCounter;
+ private int columnSpanCounter;
+ private int currentSpan = 0;
+ private String unitsOfMeasure;
+ final private List<AttributeMap> shapes;
+ final private List<AttributeMap> ole;
+ final private List<CSSNumericValue> rowHeights;
+
+ public SpreadsheetRawReportTarget(final ReportJob reportJob,
+ final ResourceManager resourceManager,
+ final ResourceKey baseResource,
+ final InputRepository inputRepository,
+ final OutputRepository outputRepository,
+ final String target,
+ final ImageService imageService,
+ final DataSourceFactory dataSourceFactory)
+ throws ReportProcessingException
+ {
+ super(reportJob, resourceManager, baseResource, inputRepository, outputRepository, target, imageService, dataSourceFactory);
+ columnBoundaryList = new ArrayList<ColumnBoundary>();
+ elementBoundaryCollectionPass = true;
+ rowHeights = new ArrayList<CSSNumericValue>();
+ shapes = new ArrayList<AttributeMap>();
+ ole = new ArrayList<AttributeMap>();
+ oleHandled = false;
+ }
+
+ @Override
+ public void startOther(final AttributeMap attrs) throws DataSourceException, ReportProcessingException
+ {
+ if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.OBJECT_OLE, attrs))
+ {
+ if (isElementBoundaryCollectionPass() && getCurrentRole() != ROLE_TEMPLATE)
+ {
+ ole.add(attrs);
+ }
+ oleHandled = true;
+ return;
+ }
+ final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
+ if (isRepeatingSection() || isFilteredNamespace(namespace))
+ {
+ return;
+ }
+
+ final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
+ if (OfficeNamespaces.TEXT_NS.equals(namespace) && OfficeToken.P.equals(elementType) && !paragraphHandled)
+ {
+ paragraphFound = true;
+ return;
+ }
+
+ if (OfficeNamespaces.DRAWING_NS.equals(namespace) && OfficeToken.FRAME.equals(elementType))
+ {
+ if (isElementBoundaryCollectionPass() && getCurrentRole() != ROLE_TEMPLATE)
+ {
+ final LengthCalculator len = new LengthCalculator();
+ for (int i = 0; i < rowHeights.size(); i++)
+ {
+ len.add(rowHeights.get(i));
+ }
+
+ rowHeights.clear();
+ final CSSNumericValue currentRowHeight = len.getResult();
+ rowHeights.add(currentRowHeight);
+ attrs.setAttribute(OfficeNamespaces.DRAWING_NS, "z-index", String.valueOf(shapes.size()));
+ final String y = (String) attrs.getAttribute(OfficeNamespaces.SVG_NS, "y");
+ if (y != null)
+ {
+ len.add(parseLength(y));
+ final CSSNumericValue currentY = len.getResult();
+ attrs.setAttribute(OfficeNamespaces.SVG_NS, "y", currentY.getValue() + currentY.getType().getType());
+ }
+ shapes.add(attrs);
+ }
+ return;
+ }
+ if (oleHandled)
+ {
+ if (isElementBoundaryCollectionPass() && getCurrentRole() != ROLE_TEMPLATE)
+ {
+ ole.add(attrs);
+ }
+ return;
+ }
+
+ // if this is the report namespace, write out a table definition ..
+ if (OfficeNamespaces.TABLE_NS.equals(namespace) && OfficeToken.TABLE.equals(elementType))
+ {
+ // whenever we see a new table, we increment our tableCounter
+ // this is used to keep tracked of the boundary conditions per table
+ tableCounter++;
+ }
+
+ if (isElementBoundaryCollectionPass())
+ {
+ collectBoundaryForElement(attrs);
+ }
+ else
+ {
+ try
+ {
+ processElement(attrs, namespace, elementType);
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException(OfficeDocumentReportTarget.FAILED, e);
+ }
+ }
+ }
+
+ @Override
+ protected void startReportSection(final AttributeMap attrs, final int role) throws ReportProcessingException
+ {
+ if ((role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_HEADER || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_FOOTER) && (!PageSection.isPrintWithReportHeader(attrs) || !PageSection.isPrintWithReportFooter(attrs)))
+ {
+ startBuffering(new OfficeStylesCollection(), true);
+ }
+ else
+ {
+ super.startReportSection(attrs, role);
+ }
+ }
+
+ @Override
+ protected void endReportSection(final AttributeMap attrs, final int role) throws IOException, ReportProcessingException
+ {
+ if ((role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_HEADER || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_FOOTER) && (!PageSection.isPrintWithReportHeader(attrs) || !PageSection.isPrintWithReportFooter(attrs)))
+ {
+ finishBuffering();
+ }
+ else
+ {
+ super.endReportSection(attrs, role);
+ }
+ }
+
+ private void handleParagraph()
+ {
+ if (paragraphFound)
+ {
+ try
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, null, XmlWriterSupport.OPEN);
+ paragraphHandled = true;
+ paragraphFound = false;
+ }
+ catch (IOException ex)
+ {
+ LOGGER.severe("ReportProcessing failed: " + ex);
+ }
+ }
+ }
+
+ private void processElement(final AttributeMap attrs, final String namespace, final String elementType)
+ throws IOException, ReportProcessingException
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE, attrs))
+ {
+ // a new table means we must clear our "calculated" table boundary array cache
+ boundariesForTableArray = null;
+
+ final String tableStyle = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
+ if (tableStyle == null)
+ {
+ tableBackgroundColor = null;
+ }
+ else
+ {
+ final Object raw = StyleUtilities.queryStyle(getPredefinedStylesCollection(), OfficeToken.TABLE, tableStyle,
+ "table-properties", OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR);
+ if (raw == null || TRANSPARENT.equals(raw))
+ {
+ tableBackgroundColor = null;
+ }
+ else
+ {
+ tableBackgroundColor = String.valueOf(raw);
+ }
+ }
+ return;
+ }
+
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_COLUMN, attrs) || ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_COLUMNS, attrs))
+ {
+ return;
+ }
+
+ // covered-table-cell elements may appear in the input from row or column spans. In the event that we hit a
+ // column-span we simply ignore these elements because we are going to adjust the span to fit the uniform table.
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.COVERED_TABLE_CELL, attrs))
+ {
+ if (columnSpanCounter > 0)
+ {
+ columnSpanCounter--;
+ }
+
+ if (columnSpanCounter == 0)
+ {
+ // if we weren't expecting a covered-table-cell, let's use it, it's probably from a row-span
+ columnCounter++;
+ final int span = getColumnSpanForCell(tableCounter, columnCounter, 1);
+ // use the calculated span for the column in the uniform table to create any additional covered-table-cell
+ // elements
+ for (int i = 0; i < span; i++)
+ {
+ xmlWriter.writeTag(namespace, OfficeToken.COVERED_TABLE_CELL, null, XmlWriter.CLOSE);
+ }
+ }
+ return;
+ }
+
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_ROW, attrs))
+ {
+ // a new row means our column counter gets reset
+ columnCounter = 0;
+ // Lets make sure the color of the table is ok ..
+ if (tableBackgroundColor != null)
+ {
+ final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
+ final OfficeStyle style = deriveStyle(OfficeToken.TABLE_ROW, styleName);
+ Element tableRowProperties = style.getTableRowProperties();
+ if (tableRowProperties == null)
+ {
+ tableRowProperties = new Section();
+ tableRowProperties.setNamespace(OfficeNamespaces.STYLE_NS);
+ tableRowProperties.setType("table-row-properties");
+ tableRowProperties.setAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR, tableBackgroundColor);
+ style.addNode(tableRowProperties);
+ }
+ else
+ {
+ final Object oldValue = tableRowProperties.getAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR);
+ if (oldValue == null || TRANSPARENT.equals(oldValue))
+ {
+ tableRowProperties.setAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR, tableBackgroundColor);
+ }
+ }
+ attrs.setAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME, style.getStyleName());
+ }
+ }
+ else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_CELL, attrs))
+ {
+ columnCounter++;
+ final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
+ if (styleName != null)
+ {
+ final OfficeStyle cellStyle = getPredefinedStylesCollection().getStyle(OfficeToken.TABLE_CELL, styleName);
+ if (cellStyle != null)
+ {
+ final Section textProperties = (Section) cellStyle.getTextProperties();
+ if (textProperties != null)
+ {
+ for (String i : FOPROPS)
+ {
+ textProperties.setAttribute(OfficeNamespaces.FO_NS, i, null);
+ }
+ textProperties.setAttribute(OfficeNamespaces.TEXT_NS, "display", null);
+ for (String i : STYLEPROPS)
+ {
+ textProperties.setAttribute(OfficeNamespaces.STYLE_NS, i, null);
+ }
+ }
+ final Section props = (Section) cellStyle.getTableCellProperties();
+ if (props != null)
+ {
+ final Object raw = props.getAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR);
+ if (TRANSPARENT.equals(raw))
+ {
+ props.setAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR, null);
+ }
+ }
+ }
+ attrs.setAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME, styleName);
+ }
+
+ final String numColSpanStr = (String) attrs.getAttribute(namespace, NUMBERCOLUMNSSPANNED);
+ int initialColumnSpan = columnSpanCounter = 1;
+ if (numColSpanStr != null)
+ {
+ initialColumnSpan = Integer.parseInt(numColSpanStr);
+ columnSpanCounter = initialColumnSpan;
+ }
+ final int span = getColumnSpanForCell(tableCounter, columnCounter, initialColumnSpan);
+ if (initialColumnSpan > 1)
+ {
+ // add the initial column span to our column counter index (subtract 1, since it is counted by default)
+ columnCounter += initialColumnSpan - 1;
+ }
+
+ // there's no point to create number-columns-spanned attributes if we only span 1 column
+ if (span > 1)
+ {
+ attrs.setAttribute(namespace, NUMBERCOLUMNSSPANNED, "" + span);
+ currentSpan = span;
+ }
+ // we must also generate "covered-table-cell" elements for each column spanned
+ // but we'll do this in the endElement, after we close this OfficeToken.TABLE_CELL
+ }
+
+ // All styles have to be processed or you will lose the paragraph-styles and inline text-styles.
+ performStyleProcessing(attrs);
+
+ final AttributeList attrList = buildAttributeList(attrs);
+ xmlWriter.writeTag(namespace, elementType, attrList, XmlWriter.OPEN);
+ }
+
+ private void collectBoundaryForElement(final AttributeMap attrs)
+ {
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_COLUMNS, attrs))
+ {
+ // A table row resets the column counter.
+ resetCurrentRowBoundaryMarker();
+ }
+ else if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_COLUMN, attrs))
+ {
+ final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
+ if (styleName == null)
+ {
+ // This should not happen, but if it does, we will ignore that cell.
+ return;
+ }
+
+ final OfficeStyle style = getPredefinedStylesCollection().getStyle(OfficeToken.TABLE_COLUMN, styleName);
+ if (style == null)
+ {
+ // Now this is very bad. It means that there is no style defined with the given name.
+ return;
+ }
+
+ final Element tableColumnProperties = style.getTableColumnProperties();
+ String widthStr = (String) tableColumnProperties.getAttribute("column-width");
+ widthStr = widthStr.substring(0, widthStr.indexOf(getUnitsOfMeasure(widthStr)));
+ final float val = Float.parseFloat(widthStr) * CELL_WIDTH_FACTOR;
+ addColumnWidthToRowBoundaryMarker((long) val);
+ ColumnBoundary currentRowBoundary = new ColumnBoundary(getCurrentRowBoundaryMarker());
+ final List<ColumnBoundary> columnBoundaryList_ = getColumnBoundaryList();
+ final int idx = columnBoundaryList_.indexOf(currentRowBoundary);
+ if (idx == -1)
+ {
+ columnBoundaryList_.add(currentRowBoundary);
+ }
+ else
+ {
+ currentRowBoundary = columnBoundaryList_.get(idx);
+ }
+ currentRowBoundary.addTableIndex(tableCounter);
+ }
+ }
+
+ private String getUnitsOfMeasure(final String str)
+ {
+ if (unitsOfMeasure == null || "".equals(unitsOfMeasure))
+ {
+ if (str == null || "".equals(str))
+ {
+ unitsOfMeasure = "cm";
+ return unitsOfMeasure;
+ }
+
+ // build units of measure, set it
+ int i = str.length() - 1;
+ for (; i >= 0; i--)
+ {
+ final char c = str.charAt(i);
+ if (Character.isDigit(c) || c == '.' || c == ',')
+ {
+ break;
+ }
+ }
+ unitsOfMeasure = str.substring(i + 1);
+ }
+ return unitsOfMeasure;
+ }
+
+ private void createTableShapes() throws ReportProcessingException
+ {
+ if (!shapes.isEmpty())
+ {
+ try
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+ // at this point we need to generate the table-columns section based on our boundary table
+ // <table:shapes>
+ // <draw:frame />
+
+ // </table:shapes>
+ xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, OfficeToken.SHAPES, null, XmlWriterSupport.OPEN);
+
+
+ for (int i = 0; i < shapes.size(); i++)
+ {
+ final AttributeMap attrs = shapes.get(i);
+ final AttributeList attrList = buildAttributeList(attrs);
+ attrList.removeAttribute(OfficeNamespaces.DRAWING_NS, OfficeToken.STYLE_NAME);
+ xmlWriter.writeTag(OfficeNamespaces.DRAWING_NS, OfficeToken.FRAME, attrList, XmlWriterSupport.OPEN);
+ startChartProcessing(ole.get(i));
+
+ xmlWriter.writeCloseTag();
+ }
+ xmlWriter.writeCloseTag();
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException(OfficeDocumentReportTarget.FAILED, e);
+ }
+ }
+ }
+
+ private void createTableColumns() throws ReportProcessingException
+ {
+ try
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+ // at this point we need to generate the table-columns section based on our boundary table
+ // <table-columns>
+ // <table-column style-name="coX"/>
+
+ // </table-columns>
+ // the first boundary is '0' which is a placeholder so we will ignore it
+ xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_COLUMNS, null, XmlWriterSupport.OPEN);
+
+ // blow away current column styles
+ // start processing at i=1 because we added a boundary for "0" which is virtual
+ final ColumnBoundary[] cba = getSortedColumnBoundaryArray();
+ for (int i = 1; i < cba.length; i++)
+ {
+ final ColumnBoundary cb = cba[i];
+ float columnWidth = cb.getBoundary();
+ if (i > 1)
+ {
+ columnWidth -= cba[i - 1].getBoundary();
+ }
+ columnWidth = columnWidth / CELL_WIDTH_FACTOR;
+ final OfficeStyle style = deriveStyle(OfficeToken.TABLE_COLUMN, ("co" + i + "_"));
+ final Section tableColumnProperties = new Section();
+ tableColumnProperties.setType("table-column-properties");
+ tableColumnProperties.setNamespace(style.getNamespace());
+ final String width = String.format("%f", columnWidth);
+ tableColumnProperties.setAttribute(style.getNamespace(),
+ "column-width", width + getUnitsOfMeasure(null));
+ style.addNode(tableColumnProperties);
+
+ final AttributeList myAttrList = new AttributeList();
+ myAttrList.setAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME, style.getStyleName());
+ xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_COLUMN, myAttrList, XmlWriterSupport.CLOSE);
+ }
+ xmlWriter.writeCloseTag();
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException(OfficeDocumentReportTarget.FAILED, e);
+ }
+ }
+
+ @Override
+ protected void endOther(final AttributeMap attrs) throws DataSourceException, ReportProcessingException
+ {
+ if (ReportTargetUtil.isElementOfType(JFreeReportInfo.REPORT_NAMESPACE, OfficeToken.OBJECT_OLE, attrs) || oleHandled)
+ {
+ oleHandled = false;
+ return;
+ }
+
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_ROW, attrs) && isElementBoundaryCollectionPass() && getCurrentRole() != ROLE_TEMPLATE)
+ {
+ final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
+ rowHeights.add(computeRowHeight(styleName));
+ }
+
+ if (isRepeatingSection() || isElementBoundaryCollectionPass())
+ {
+ return;
+ }
+
+ final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
+ if (isFilteredNamespace(namespace))
+ {
+ return;
+ }
+ final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
+ if (OfficeNamespaces.DRAWING_NS.equals(namespace) && OfficeToken.FRAME.equals(elementType))
+ {
+ return;
+ }
+
+ // if this is the report namespace, write out a table definition ..
+ if (OfficeNamespaces.TABLE_NS.equals(namespace) && (OfficeToken.TABLE.equals(elementType) || OfficeToken.COVERED_TABLE_CELL.equals(elementType) || OfficeToken.TABLE_COLUMN.equals(elementType) || OfficeToken.TABLE_COLUMNS.equals(elementType)))
+ {
+ return;
+ }
+
+ if (!paragraphHandled && OfficeNamespaces.TEXT_NS.equals(namespace) && OfficeToken.P.equals(elementType))
+ {
+ if (!paragraphHandled)
+ {
+ return;
+ }
+
+ paragraphHandled = false;
+ }
+ try
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeCloseTag();
+ // table-cell elements may have a number-columns-spanned attribute which indicates how many
+ // 'covered-table-cell' elements we need to generate
+ generateCoveredTableCells(attrs);
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException(OfficeDocumentReportTarget.FAILED, e);
+ }
+ }
+
+ private void generateCoveredTableCells(final AttributeMap attrs) throws IOException
+ {
+ if (!ReportTargetUtil.isElementOfType(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_CELL, attrs))
+ {
+ return;
+ }
+
+ // do this after we close the tag
+ final XmlWriter xmlWriter = getXmlWriter();
+ final int span = currentSpan;
+ currentSpan = 0;
+ for (int i = 1; i < span; i++)
+ {
+ xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, OfficeToken.COVERED_TABLE_CELL, null, XmlWriter.CLOSE);
+ }
+ }
+
+ public String getExportDescriptor()
+ {
+ return "raw/" + PentahoReportEngineMetaData.OPENDOCUMENT_SPREADSHEET;
+ }
+
+
+ @Override
+ public void processText(final String text) throws DataSourceException, ReportProcessingException
+ {
+ if (!(isRepeatingSection() || isElementBoundaryCollectionPass()))
+ {
+ handleParagraph();
+ super.processText(text);
+ }
+ }
+
+ @Override
+ public void processContent(final DataFlags value) throws DataSourceException, ReportProcessingException
+ {
+ if (!(isRepeatingSection() || isElementBoundaryCollectionPass()))
+ {
+ handleParagraph();
+ super.processContent(value);
+ }
+ }
+
+ private String getStartContent()
+ {
+ return "spreadsheet";
+ }
+
+ @Override
+ protected void startContent(final AttributeMap attrs) throws IOException, DataSourceException,
+ ReportProcessingException
+ {
+ if (!isElementBoundaryCollectionPass())
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, getStartContent(), null, XmlWriterSupport.OPEN);
+
+ writeNullDate();
+
+ final AttributeMap tableAttributes = new AttributeMap();
+ tableAttributes.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.NAMESPACE_ATTRIBUTE, OfficeNamespaces.TABLE_NS);
+ tableAttributes.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, Element.TYPE_ATTRIBUTE, OfficeToken.TABLE);
+ tableAttributes.setAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME, generateInitialTableStyle());
+ tableAttributes.setAttribute(OfficeNamespaces.TABLE_NS, "name", "Report");
+
+ performStyleProcessing(tableAttributes);
+
+ xmlWriter.writeTag(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE, buildAttributeList(tableAttributes), XmlWriterSupport.OPEN);
+ createTableShapes();
+ createTableColumns();
+ }
+ }
+
+ private String generateInitialTableStyle() throws ReportProcessingException
+ {
+ final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
+ final OfficeStyles commonStyles = predefStyles.getAutomaticStyles();
+ if (!commonStyles.containsStyle(OfficeToken.TABLE, "Initial_Table"))
+ {
+ final String masterPageName = createMasterPage();
+
+ final OfficeStyle tableStyle = new OfficeStyle();
+ tableStyle.setStyleFamily(OfficeToken.TABLE);
+ tableStyle.setStyleName("Initial_Table");
+ tableStyle.setAttribute(OfficeNamespaces.STYLE_NS, "master-page-name", masterPageName);
+ final Element tableProperties = produceFirstChild(tableStyle, OfficeNamespaces.STYLE_NS, "table-properties");
+ tableProperties.setAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR, TRANSPARENT);
+ commonStyles.addStyle(tableStyle);
+ }
+ return "Initial_Table";
+ }
+
+ private String createMasterPage() throws ReportProcessingException
+ {
+ final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
+ final MasterPageFactory masterPageFactory = new MasterPageFactory(predefStyles.getMasterStyles());
+ final OfficeMasterPage masterPage;
+ if (!masterPageFactory.containsMasterPage("Standard", null, null))
+ {
+ masterPage = masterPageFactory.createMasterPage("Standard", null, null);
+
+ final CSSNumericValue zeroLength = CSSNumericValue.createValue(CSSNumericType.CM, 0);
+ final String pageLayoutTemplate = masterPage.getPageLayout();
+ if (pageLayoutTemplate == null)
+ {
+ // there is no pagelayout. Create one ..
+ final String derivedLayout = masterPageFactory.createPageStyle(getGlobalStylesCollection().getAutomaticStyles(), zeroLength, zeroLength);
+ masterPage.setPageLayout(derivedLayout);
+ }
+ else
+ {
+ final String derivedLayout = masterPageFactory.derivePageStyle(pageLayoutTemplate,
+ getPredefinedStylesCollection().getAutomaticStyles(),
+ getGlobalStylesCollection().getAutomaticStyles(), zeroLength, zeroLength);
+ masterPage.setPageLayout(derivedLayout);
+ }
+
+ final OfficeStylesCollection officeStylesCollection = getGlobalStylesCollection();
+ final OfficeMasterStyles officeMasterStyles = officeStylesCollection.getMasterStyles();
+ officeMasterStyles.addMasterPage(masterPage);
+ }
+ else
+ {
+ masterPage = masterPageFactory.getMasterPage("Standard", null, null);
+ }
+ return masterPage.getStyleName();
+ }
+
+ @Override
+ protected void endContent(final AttributeMap attrs) throws IOException, DataSourceException,
+ ReportProcessingException
+ {
+ // todo
+ if (!isElementBoundaryCollectionPass())
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeCloseTag();
+ xmlWriter.writeCloseTag();
+ }
+ }
+
+ @Override
+ public void endReport(final ReportStructureRoot report) throws DataSourceException, ReportProcessingException
+ {
+ super.endReport(report);
+ setElementBoundaryCollectionPass(false);
+ resetTableCounter();
+ columnCounter = 0;
+ copyMeta();
+ }
+
+ private boolean isElementBoundaryCollectionPass()
+ {
+ return elementBoundaryCollectionPass;
+ }
+
+ private void setElementBoundaryCollectionPass(final boolean elementBoundaryCollectionPass)
+ {
+ this.elementBoundaryCollectionPass = elementBoundaryCollectionPass;
+ }
+
+ private ColumnBoundary[] getSortedColumnBoundaryArray()
+ {
+ if (sortedBoundaryArray == null)
+ {
+ getColumnBoundaryList().add(new ColumnBoundary(0));
+ sortedBoundaryArray = getColumnBoundaryList().toArray(new ColumnBoundary[getColumnBoundaryList().size()]);
+ Arrays.sort(sortedBoundaryArray);
+ }
+ return sortedBoundaryArray;
+ }
+
+ private List<ColumnBoundary> getColumnBoundaryList()
+ {
+ return columnBoundaryList;
+ }
+
+ private void addColumnWidthToRowBoundaryMarker(final long width)
+ {
+ currentRowBoundaryMarker += width;
+ }
+
+ private long getCurrentRowBoundaryMarker()
+ {
+ return currentRowBoundaryMarker;
+ }
+
+ private void resetTableCounter()
+ {
+ tableCounter = 0;
+ }
+
+ private void resetCurrentRowBoundaryMarker()
+ {
+ currentRowBoundaryMarker = 0;
+ }
+
+ private ColumnBoundary[] getBoundariesForTable(final int table)
+ {
+ if (boundariesForTableArray == null)
+ {
+ final List<ColumnBoundary> boundariesForTable = new ArrayList<ColumnBoundary>();
+ final List<ColumnBoundary> boundaryList = getColumnBoundaryList();
+ for (int i = 0; i < boundaryList.size(); i++)
+ {
+ final ColumnBoundary b = boundaryList.get(i);
+ if (b.isContainedByTable(table))
+ {
+ boundariesForTable.add(b);
+ }
+ }
+ boundariesForTableArray = boundariesForTable.toArray(new ColumnBoundary[boundariesForTable.size()]);
+ Arrays.sort(boundariesForTableArray);
+ }
+ return boundariesForTableArray;
+ }
+
+ private int getColumnSpanForCell(final int table, final int col, final int initialColumnSpan)
+ {
+ final ColumnBoundary[] globalBoundaries = getSortedColumnBoundaryArray();
+ final ColumnBoundary[] tableBoundaries = getBoundariesForTable(table);
+ // how many column boundaries in the globalBoundaries list fall between the currentRowWidth and the next boundary
+ // for the current row
+
+ float cellBoundary = tableBoundaries[col - 1].getBoundary();
+ float cellWidth = tableBoundaries[col - 1].getBoundary();
+
+ if (col > 1)
+ {
+ cellWidth = cellWidth - tableBoundaries[col - 2].getBoundary();
+ }
+
+ if (initialColumnSpan > 1)
+ {
+ // ok we've got some additional spanning specified on the input
+ final int index = (col - 1) + (initialColumnSpan - 1);
+ cellWidth += tableBoundaries[index].getBoundary() - tableBoundaries[col - 1].getBoundary();
+ cellBoundary = tableBoundaries[index].getBoundary();
+ }
+
+ int beginBoundaryIndex = 0;
+ int endBoundaryIndex = globalBoundaries.length - 1;
+ for (int i = 0; i < globalBoundaries.length; i++)
+ {
+ // find beginning boundary
+ if (globalBoundaries[i].getBoundary() <= cellBoundary - cellWidth)
+ {
+ beginBoundaryIndex = i;
+ }
+ if (globalBoundaries[i].getBoundary() <= cellBoundary)
+ {
+ endBoundaryIndex = i;
+ }
+ }
+ final int span = endBoundaryIndex - beginBoundaryIndex;
+ // span will be zero for the first column, so we adjust it to 1
+ if (span == 0)
+ {
+ return 1;
+ }
+ return span;
+ }
+
+ @Override
+ protected String getTargetMimeType()
+ {
+ return "application/vnd.oasis.opendocument.spreadsheet";
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/text/MasterPageFactory.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/MasterPageFactory.java
new file mode 100644
index 000000000..f5caa1284
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/MasterPageFactory.java
@@ -0,0 +1,382 @@
+/*
+ * 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.output.text;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.OfficeMasterPage;
+import org.libreoffice.report.pentaho.model.OfficeMasterStyles;
+import org.libreoffice.report.pentaho.model.OfficeStyles;
+import org.libreoffice.report.pentaho.model.PageLayout;
+import org.libreoffice.report.pentaho.model.RawText;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jfree.layouting.input.style.values.CSSNumericValue;
+import org.jfree.report.ReportProcessingException;
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+import org.jfree.report.util.AttributeNameGenerator;
+
+
+/**
+ * Todo: Document me!
+ *
+ * @since 14.03.2007
+ */
+public class MasterPageFactory
+{
+
+ private static class MasterPageFactoryKey
+ {
+
+ private final String template;
+ private final String pageHeader;
+ private final String pageFooter;
+
+ public MasterPageFactoryKey(final String template,
+ final String pageHeader,
+ final String pageFooter)
+ {
+ this.template = template;
+ this.pageHeader = pageHeader;
+ this.pageFooter = pageFooter;
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this != o)
+ {
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final MasterPageFactoryKey that = (MasterPageFactoryKey) o;
+
+ if (pageFooter != null ? !pageFooter.equals(
+ that.pageFooter) : that.pageFooter != null)
+ {
+ return false;
+ }
+ if (pageHeader != null ? !pageHeader.equals(
+ that.pageHeader) : that.pageHeader != null)
+ {
+ return false;
+ }
+ if (template != null ? !template.equals(
+ that.template) : that.template != null)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result = (template != null ? template.hashCode() : 0);
+ result = 31 * result + (pageHeader != null ? pageHeader.hashCode() : 0);
+ result = 31 * result + (pageFooter != null ? pageFooter.hashCode() : 0);
+ return result;
+ }
+
+ }
+
+ private static class PageLayoutKey
+ {
+
+ private final String templateName;
+ private final CSSNumericValue headerHeight;
+ private final CSSNumericValue footerHeight;
+
+ public PageLayoutKey(final String templateName,
+ final CSSNumericValue headerHeight,
+ final CSSNumericValue footerHeight)
+ {
+ this.templateName = templateName;
+ this.headerHeight = headerHeight;
+ this.footerHeight = footerHeight;
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final PageLayoutKey key = (PageLayoutKey) o;
+
+ if (footerHeight != null ? !footerHeight.equals(
+ key.footerHeight) : key.footerHeight != null)
+ {
+ return false;
+ }
+ if (headerHeight != null ? !headerHeight.equals(
+ key.headerHeight) : key.headerHeight != null)
+ {
+ return false;
+ }
+ return !(templateName != null ? !templateName.equals(
+ key.templateName) : key.templateName != null);
+
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int result;
+ result = (templateName != null ? templateName.hashCode() : 0);
+ result = 31 * result + (headerHeight != null ? headerHeight.hashCode() : 0);
+ result = 31 * result + (footerHeight != null ? footerHeight.hashCode() : 0);
+ return result;
+ }
+ }
+ // todo: Patch the page-layout ...
+ private static final String DEFAULT_PAGE_NAME = "Default";
+ private final OfficeMasterStyles predefinedStyles;
+ private final AttributeNameGenerator masterPageNameGenerator;
+ private final Map<MasterPageFactoryKey,OfficeMasterPage> masterPages;
+ private final AttributeNameGenerator pageLayoutNameGenerator;
+ private final Map<PageLayoutKey,String> pageLayouts;
+
+ public MasterPageFactory(final OfficeMasterStyles predefinedStyles)
+ {
+ this.predefinedStyles = predefinedStyles;
+ this.masterPages = new HashMap<MasterPageFactoryKey,OfficeMasterPage>();
+ this.masterPageNameGenerator = new AttributeNameGenerator();
+ this.pageLayouts = new HashMap<PageLayoutKey,String>();
+ this.pageLayoutNameGenerator = new AttributeNameGenerator();
+ }
+
+ public OfficeMasterPage getMasterPage(final String template,
+ final String pageHeader,
+ final String pageFooter)
+ {
+ final MasterPageFactoryKey key =
+ new MasterPageFactoryKey(template, pageHeader, pageFooter);
+ return masterPages.get(key);
+ }
+
+ public boolean containsMasterPage(final String template,
+ final String pageHeader,
+ final String pageFooter)
+ {
+ final MasterPageFactoryKey key =
+ new MasterPageFactoryKey(template, pageHeader, pageFooter);
+ return masterPages.containsKey(key);
+ }
+
+ public OfficeMasterPage createMasterPage(final String template,
+ final String pageHeader,
+ final String pageFooter)
+ {
+ final MasterPageFactoryKey key =
+ new MasterPageFactoryKey(template, pageHeader, pageFooter);
+ final OfficeMasterPage cached = masterPages.get(key);
+ if (cached != null)
+ {
+ return cached;
+ }
+
+ final String targetName = (masterPages.isEmpty()) ? "Standard" : template;
+
+ OfficeMasterPage predef = predefinedStyles.getMasterPage(template);
+ if (predef == null)
+ {
+ // This is a 'magic' name ..
+ // todo: It could be that this should be called 'Standard' instead
+ predef = predefinedStyles.getMasterPage(MasterPageFactory.DEFAULT_PAGE_NAME);
+ }
+
+ if (predef != null)
+ {
+ try
+ {
+ // derive
+ final OfficeMasterPage derived = (OfficeMasterPage) predef.clone();
+ return setupMasterPage(derived, targetName, pageHeader, pageFooter,
+ key);
+ }
+ catch (CloneNotSupportedException cne)
+ {
+ throw new IllegalStateException("Implementation error: unable to derive page", cne);
+ }
+ }
+
+ final OfficeMasterPage masterPage = new OfficeMasterPage();
+ masterPage.setNamespace(OfficeNamespaces.STYLE_NS);
+ masterPage.setType("master-page");
+ return setupMasterPage(masterPage, targetName, pageHeader, pageFooter, key);
+ }
+
+ private OfficeMasterPage setupMasterPage(final OfficeMasterPage derived,
+ final String targetName,
+ final String pageHeader,
+ final String pageFooter,
+ final MasterPageFactoryKey key)
+ {
+ derived.setStyleName(masterPageNameGenerator.generateName(targetName));
+ masterPages.put(key, derived);
+
+ if (pageHeader != null)
+ {
+ final Section header = new Section();
+ header.setNamespace(OfficeNamespaces.STYLE_NS);
+ header.setType("header");
+ header.addNode(new RawText(pageHeader));
+ derived.addNode(header);
+ }
+
+ if (pageFooter != null)
+ {
+ final Section footer = new Section();
+ footer.setNamespace(OfficeNamespaces.STYLE_NS);
+ footer.setType("footer");
+ footer.addNode(new RawText(pageFooter));
+ derived.addNode(footer);
+ }
+
+ return derived;
+ }
+
+ public String createPageStyle(final OfficeStyles commonStyles,
+ final CSSNumericValue headerHeight,
+ final CSSNumericValue footerHeight)
+ {
+ final PageLayoutKey key =
+ new PageLayoutKey(null, headerHeight, footerHeight);
+ final PageLayout derived = new PageLayout();
+ final String name = pageLayoutNameGenerator.generateName("autogenerated");
+ derived.setStyleName(name);
+ commonStyles.addPageStyle(derived);
+
+ if (headerHeight != null)
+ {
+ final Section headerStyle = new Section();
+ headerStyle.setNamespace(OfficeNamespaces.STYLE_NS);
+ headerStyle.setType("header-style");
+ derived.addNode(headerStyle);
+ MasterPageFactory.applyHeaderFooterHeight(headerStyle, headerHeight);
+ }
+
+ if (footerHeight != null)
+ {
+ final Section footerStyle = new Section();
+ footerStyle.setNamespace(OfficeNamespaces.STYLE_NS);
+ footerStyle.setType("footer-style");
+ derived.addNode(footerStyle);
+ MasterPageFactory.applyHeaderFooterHeight(footerStyle, footerHeight);
+ }
+ pageLayouts.put(key, name);
+ return name;
+ }
+
+ public String derivePageStyle(final String pageStyleTemplate,
+ final OfficeStyles predefined,
+ final OfficeStyles commonStyles,
+ final CSSNumericValue headerHeight,
+ final CSSNumericValue footerHeight)
+ throws ReportProcessingException
+ {
+ if (pageStyleTemplate == null)
+ {
+ throw new NullPointerException("A style-name must be given");
+ }
+
+ final PageLayoutKey key =
+ new PageLayoutKey(pageStyleTemplate, headerHeight, footerHeight);
+ final String pageLayoutName = pageLayouts.get(key);
+ if (pageLayoutName != null)
+ {
+ // there's already a suitable version included.
+ return pageLayoutName;
+ }
+
+ final PageLayout original = predefined.getPageStyle(pageStyleTemplate);
+ if (original == null)
+ {
+ throw new ReportProcessingException("Invalid page-layout '" + pageStyleTemplate + "', will not continue.");
+ }
+
+ try
+ {
+ final PageLayout derived = (PageLayout) original.clone();
+ final String name = pageLayoutNameGenerator.generateName(
+ pageStyleTemplate);
+ derived.setStyleName(name);
+ commonStyles.addPageStyle(derived);
+
+ if (headerHeight != null)
+ {
+ Section headerStyle = derived.getHeaderStyle();
+ if (headerStyle == null)
+ {
+ headerStyle = new Section();
+ headerStyle.setNamespace(OfficeNamespaces.STYLE_NS);
+ headerStyle.setType("header-style");
+ derived.addNode(headerStyle);
+ }
+ MasterPageFactory.applyHeaderFooterHeight(headerStyle, headerHeight);
+ }
+
+ if (footerHeight != null)
+ {
+ Section footerStyle = derived.getFooterStyle();
+ if (footerStyle == null)
+ {
+ footerStyle = new Section();
+ footerStyle.setNamespace(OfficeNamespaces.STYLE_NS);
+ footerStyle.setType("footer-style");
+ derived.addNode(footerStyle);
+ }
+
+ MasterPageFactory.applyHeaderFooterHeight(footerStyle, footerHeight);
+ }
+ pageLayouts.put(key, name);
+ return name;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new IllegalStateException("Clone failed.", e);
+ }
+ }
+
+ private static void applyHeaderFooterHeight(final Section headerFooterStyle,
+ final CSSNumericValue style)
+ {
+ Element headerFooterProps = headerFooterStyle.findFirstChild(OfficeNamespaces.STYLE_NS, "header-footer-properties");
+ if (headerFooterProps == null)
+ {
+ headerFooterProps = new Section();
+ headerFooterProps.setNamespace(OfficeNamespaces.STYLE_NS);
+ headerFooterProps.setType("header-footer-properties");
+ headerFooterStyle.addNode(headerFooterProps);
+ }
+ headerFooterProps.setAttribute(OfficeNamespaces.SVG_NS, "height", style.getValue() + style.getType().getType());
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/text/PageBreakDefinition.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/PageBreakDefinition.java
new file mode 100644
index 000000000..e92e644ec
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/PageBreakDefinition.java
@@ -0,0 +1,39 @@
+/*
+ * 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.output.text;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 24.03.2007
+ */
+public class PageBreakDefinition
+{
+
+ private final boolean resetPageNumber;
+
+ public PageBreakDefinition(final boolean resetPageNumber)
+ {
+ this.resetPageNumber = resetPageNumber;
+ }
+
+ public boolean isResetPageNumber()
+ {
+ return resetPageNumber;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/text/PageContext.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/PageContext.java
new file mode 100644
index 000000000..180635bc6
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/PageContext.java
@@ -0,0 +1,218 @@
+/*
+ * 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.output.text;
+
+import org.libreoffice.report.pentaho.styles.LengthCalculator;
+
+import org.jfree.layouting.input.style.values.CSSNumericValue;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 24.03.2007
+ */
+public class PageContext
+{
+
+
+ public static final int KEEP_TOGETHER_GROUP = 1;
+ public static final int KEEP_TOGETHER_FIRST_DETAIL = 2;
+ private PageContext parent;
+ private String header;
+ private CSSNumericValue headerHeight;
+ private String footer;
+ private CSSNumericValue footerHeight;
+ private int keepTogether;
+ private Integer columnCount = null;
+ private boolean sectionOpen;
+
+ public PageContext()
+ {
+ this(null);
+ }
+
+ public PageContext(final PageContext parent)
+ {
+ this.parent = parent;
+ if (parent != null)
+ {
+ this.keepTogether = parent.getKeepTogether();
+ }
+ }
+
+ public int getActiveColumns()
+ {
+ PageContext pc = this;
+ while (pc != null)
+ {
+ // TODO: IS this code correct? Why not columnCount = pc.getColumnCount(); ?
+ if (columnCount != null)
+ {
+ return columnCount;
+ }
+ pc = pc.getParent();
+ }
+ return 1;
+ }
+
+ public void setColumnCount(final Integer columnCount)
+ {
+ this.columnCount = columnCount;
+ }
+
+ public Integer getColumnCount()
+ {
+ return columnCount;
+ }
+
+ public String getHeader()
+ {
+ return header;
+ }
+
+ public void setHeader(final String header, final CSSNumericValue height)
+ {
+ this.header = header;
+ this.headerHeight = height;
+ }
+
+ public String getFooter()
+ {
+ return footer;
+ }
+
+ private CSSNumericValue getHeaderHeight()
+ {
+ return headerHeight;
+ }
+
+ private CSSNumericValue getFooterHeight()
+ {
+ return footerHeight;
+ }
+
+ public void setFooter(final String footer, final CSSNumericValue height)
+ {
+ this.footer = footer;
+ this.footerHeight = height;
+ }
+
+ public int getKeepTogether()
+ {
+ return keepTogether;
+ }
+
+ public void setKeepTogether(final int keepTogether)
+ {
+ this.keepTogether = keepTogether;
+ }
+
+ public PageContext getParent()
+ {
+ return parent;
+ }
+
+ public CSSNumericValue getAllFooterSize()
+ {
+ if (parent == null)
+ {
+ return footerHeight;
+ }
+
+ final LengthCalculator lnc = new LengthCalculator();
+ PageContext pc = this;
+ while (pc != null)
+ {
+ lnc.add(pc.getFooterHeight());
+ pc = pc.getParent();
+ }
+ return lnc.getResult();
+ }
+
+ public CSSNumericValue getAllHeaderSize()
+ {
+ if (parent == null)
+ {
+ return headerHeight;
+ }
+
+ final LengthCalculator lnc = new LengthCalculator();
+ PageContext pc = this;
+ while (pc != null)
+ {
+ lnc.add(pc.getHeaderHeight());
+ pc = pc.getParent();
+ }
+ return lnc.getResult();
+ }
+
+ public String getPageFooterContent()
+ {
+ if (parent == null)
+ {
+ return getFooter();
+ }
+
+ final StringBuffer b = new StringBuffer();
+
+ PageContext pc = this;
+ while (pc != null)
+ {
+ final String footer_ = pc.getFooter();
+ if (footer_ != null)
+ {
+ b.append(footer_);
+ }
+ pc = pc.getParent();
+ }
+
+ if (b.length() != 0)
+ {
+ return b.toString();
+ }
+ return null;
+ }
+
+ public String getPageHeaderContent()
+ {
+ if (parent == null)
+ {
+ return getHeader();
+ }
+
+ final StringBuffer b = new StringBuffer();
+ b.append(parent.getPageHeaderContent());
+ b.append(getHeader());
+
+ if (b.length() != 0)
+ {
+ return b.toString();
+ }
+ return null;
+ }
+
+ public boolean isSectionOpen()
+ {
+ return sectionOpen;
+ }
+
+ public void setSectionOpen(final boolean sectionOpen)
+ {
+ this.sectionOpen = sectionOpen;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/text/TextRawReportProcessor.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/TextRawReportProcessor.java
new file mode 100644
index 000000000..8718043bf
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/TextRawReportProcessor.java
@@ -0,0 +1,108 @@
+/*
+ * 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.output.text;
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.pentaho.PentahoFormulaContext;
+
+import org.jfree.report.ReportProcessingException;
+import org.jfree.report.data.ReportContextImpl;
+import org.jfree.report.flow.ReportContext;
+import org.jfree.report.flow.ReportJob;
+import org.jfree.report.flow.ReportStructureRoot;
+import org.jfree.report.flow.ReportTarget;
+import org.jfree.report.flow.SinglePassReportProcessor;
+
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+
+/**
+ * Creation-Date: 03.07.2006, 17:08:25
+ *
+ */
+public class TextRawReportProcessor extends SinglePassReportProcessor
+{
+
+ private final OutputRepository outputRepository;
+ private final String targetName;
+ private final InputRepository inputRepository;
+ private final ImageService imageService;
+ private final DataSourceFactory dataSourceFactory;
+
+ public TextRawReportProcessor(final InputRepository inputRepository,
+ final OutputRepository outputRepository,
+ final String targetName,
+ final ImageService imageService,
+ final DataSourceFactory dataSourceFactory)
+ {
+ if (inputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (outputRepository == null)
+ {
+ throw new NullPointerException();
+ }
+ if (targetName == null)
+ {
+ throw new NullPointerException();
+ }
+ if (imageService == null)
+ {
+ throw new NullPointerException();
+ }
+ if (dataSourceFactory == null)
+ {
+ throw new NullPointerException();
+ }
+
+ this.targetName = targetName;
+ this.inputRepository = inputRepository;
+ this.outputRepository = outputRepository;
+ this.imageService = imageService;
+ this.dataSourceFactory = dataSourceFactory;
+ }
+
+ @Override
+ protected ReportTarget createReportTarget(final ReportJob job)
+ throws ReportProcessingException
+ {
+ final ReportStructureRoot report = job.getReportStructureRoot();
+ final ResourceManager resourceManager = report.getResourceManager();
+
+ return new TextRawReportTarget(job, resourceManager, report.getBaseResource(),
+ inputRepository, outputRepository, targetName, imageService, dataSourceFactory);
+ }
+
+ @Override
+ protected ReportContext createReportContext(final ReportJob job,
+ final ReportTarget target)
+ {
+ final ReportContext context = super.createReportContext(job, target);
+ if (context instanceof ReportContextImpl)
+ {
+ final ReportContextImpl impl = (ReportContextImpl) context;
+ impl.setFormulaContext(new PentahoFormulaContext(impl.getFormulaContext(), job.getConfiguration()));
+ }
+ return context;
+ }
+}
+
+
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/text/TextRawReportTarget.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/TextRawReportTarget.java
new file mode 100644
index 000000000..d8e50d2d4
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/TextRawReportTarget.java
@@ -0,0 +1,1423 @@
+/*
+ * 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.output.text;
+
+
+import org.libreoffice.report.DataSourceFactory;
+import org.libreoffice.report.ImageService;
+import org.libreoffice.report.InputRepository;
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.OutputRepository;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.PentahoReportEngineMetaData;
+import org.libreoffice.report.pentaho.layoutprocessor.FormatValueUtility;
+import org.libreoffice.report.pentaho.model.OfficeMasterPage;
+import org.libreoffice.report.pentaho.model.OfficeMasterStyles;
+import org.libreoffice.report.pentaho.model.OfficeStyle;
+import org.libreoffice.report.pentaho.model.OfficeStyles;
+import org.libreoffice.report.pentaho.model.OfficeStylesCollection;
+import org.libreoffice.report.pentaho.model.PageSection;
+import org.libreoffice.report.pentaho.output.OfficeDocumentReportTarget;
+import org.libreoffice.report.pentaho.output.StyleUtilities;
+import org.libreoffice.report.pentaho.styles.LengthCalculator;
+
+import java.io.IOException;
+
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
+
+
+import org.jfree.layouting.input.style.values.CSSNumericValue;
+import org.jfree.layouting.util.AttributeMap;
+import org.jfree.report.DataSourceException;
+import org.jfree.report.JFreeReportInfo;
+import org.jfree.report.ReportProcessingException;
+import org.jfree.report.flow.ReportJob;
+import org.jfree.report.flow.ReportStructureRoot;
+import org.jfree.report.flow.ReportTargetUtil;
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+import org.jfree.report.util.AttributeNameGenerator;
+import org.jfree.report.util.IntegerCache;
+
+import org.pentaho.reporting.libraries.base.util.FastStack;
+import org.pentaho.reporting.libraries.base.util.ObjectUtilities;
+import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+import org.pentaho.reporting.libraries.xmlns.common.AttributeList;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriter;
+import org.pentaho.reporting.libraries.xmlns.writer.XmlWriterSupport;
+
+
+/**
+ * Creation-Date: 03.07.2006, 16:28:00
+ *
+ */
+public class TextRawReportTarget extends OfficeDocumentReportTarget
+{
+
+ private static final String ALWAYS = "always";
+ private static final String KEEP_TOGETHER = "keep-together";
+ private static final String KEEP_WITH_NEXT = "keep-with-next";
+ private static final String MAY_BREAK_BETWEEN_ROWS = "may-break-between-rows";
+ private static final String NAME = "name";
+ private static final String NONE = "none";
+ private static final String NORMAL = "normal";
+ private static final String PARAGRAPH_PROPERTIES = "paragraph-properties";
+ private static final String STANDARD = "Standard";
+ private static final String TABLE_PROPERTIES = "table-properties";
+ private static final String VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT = "variables_paragraph_with_next";
+ private static final String VARIABLES_HIDDEN_STYLE_WITHOUT_KEEPWNEXT = "variables_paragraph_without_next";
+ private static final int TABLE_LAYOUT_VARIABLES_PARAGRAPH = 0;
+ private static final int TABLE_LAYOUT_SINGLE_DETAIL_TABLE = 2;
+ private static final int CP_SETUP = 0;
+ private static final int CP_FIRST_TABLE = 1;
+ private static final int CP_NEXT_TABLE = 2;
+ // This is the initial state of the detail-band processing. It states, that we are now waiting for a
+ // detail-band to be printed.
+ private static final int DETAIL_SECTION_WAIT = 0;
+ // The first detail section has started.
+ private static final int DETAIL_SECTION_FIRST_STARTED = 1;
+ // The first detail section has been printed.
+ private static final int DETAIL_SECTION_FIRST_PRINTED = 2;
+ // Another detail section has started
+ private static final int DETAIL_SECTION_OTHER_STARTED = 3;
+ // The other detail section has been printed.
+ private static final int DETAIL_SECTION_OTHER_PRINTED = 4;
+ private boolean pageFooterOnReportFooter;
+ private boolean pageFooterOnReportHeader;
+ private boolean pageHeaderOnReportFooter;
+ private boolean pageHeaderOnReportHeader;
+ private int contentProcessingState;
+ private OfficeMasterPage currentMasterPage;
+ private final FastStack activePageContext;
+ private MasterPageFactory masterPageFactory;
+ private LengthCalculator sectionHeight;
+ private String variables;
+ private PageBreakDefinition pageBreakDefinition;
+ private VariablesDeclarations variablesDeclarations;
+ private boolean columnBreakPending;
+ private boolean sectionKeepTogether;
+ private final AttributeNameGenerator sectionNames;
+ private int detailBandProcessingState;
+ private final int tableLayoutConfig;
+ private int expectedTableRowCount;
+ private boolean firstCellSeen;
+
+ public TextRawReportTarget(final ReportJob reportJob,
+ final ResourceManager resourceManager,
+ final ResourceKey baseResource,
+ final InputRepository inputRepository,
+ final OutputRepository outputRepository,
+ final String target,
+ final ImageService imageService,
+ final DataSourceFactory datasourcefactory)
+ throws ReportProcessingException
+ {
+ super(reportJob, resourceManager, baseResource, inputRepository, outputRepository, target, imageService, datasourcefactory);
+ activePageContext = new FastStack();
+ this.sectionNames = new AttributeNameGenerator();
+
+ this.tableLayoutConfig = TABLE_LAYOUT_SINGLE_DETAIL_TABLE;
+ }
+
+ @Override
+ protected String getTargetMimeType()
+ {
+ return "application/vnd.oasis.opendocument.text";
+ }
+
+ /**
+ * Checks, whether a manual page break should be inserted at the next possible location.
+ *
+ * @return true, if a pagebreak is pending, false otherwise.
+ */
+ private boolean isPagebreakPending()
+ {
+ return pageBreakDefinition != null;
+ }
+
+ private boolean isResetPageNumber()
+ {
+ return pageBreakDefinition != null && pageBreakDefinition.isResetPageNumber();
+ }
+
+ /**
+ * Defines, whether a manual pagebreak should be inserted at the next possible location.
+ *
+ * @param pageBreakDefinition the new flag value.
+ */
+ private void setPagebreakDefinition(final PageBreakDefinition pageBreakDefinition)
+ {
+ this.pageBreakDefinition = pageBreakDefinition;
+ }
+
+ private PageBreakDefinition getPagebreakDefinition()
+ {
+ return pageBreakDefinition;
+ }
+
+ // todo
+ private boolean isKeepTableWithNext()
+ {
+ final int keepTogetherState = getCurrentContext().getKeepTogether();
+ if (keepTogetherState == PageContext.KEEP_TOGETHER_GROUP)
+ {
+ return true;
+ }
+
+ final boolean keepWithNext;
+ keepWithNext = keepTogetherState == PageContext.KEEP_TOGETHER_FIRST_DETAIL && (detailBandProcessingState == DETAIL_SECTION_WAIT);
+ return keepWithNext;
+ }
+
+ private boolean isSectionPagebreakAfter(final AttributeMap attrs)
+ {
+ final Object forceNewPage =
+ attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "force-new-page");
+ return "after-section".equals(forceNewPage) || "before-after-section".equals(forceNewPage);
+ }
+
+ private boolean isSectionPagebreakBefore(final AttributeMap attrs)
+ {
+ final Object forceNewPage =
+ attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "force-new-page");
+ return "before-section".equals(forceNewPage) || "before-after-section".equals(forceNewPage);
+ }
+
+ private PageContext getCurrentContext()
+ {
+ return (PageContext) activePageContext.peek();
+ }
+
+ private String createMasterPage(final boolean printHeader,
+ final boolean printFooter)
+ throws ReportProcessingException
+ {
+ // create the master page for the report-header.
+ // If there is a page-header or footer in the report that gets
+ // suppressed on the report-header, we have to insert a pagebreak
+ // afterwards.
+
+ final String activePageFooter;
+ // Check, whether the report header can have a page-header
+ final PageContext context = getCurrentContext();
+ if (printFooter)
+ {
+ activePageFooter = context.getPageFooterContent();
+ }
+ else
+ {
+ activePageFooter = null;
+ }
+ final String activePageHeader;
+ if (printHeader)
+ {
+ // we have to insert a manual pagebreak after the report header.
+ activePageHeader = context.getPageHeaderContent();
+ }
+ else
+ {
+ activePageHeader = null;
+ }
+
+ final String masterPageName;
+ if (currentMasterPage == null || !masterPageFactory.containsMasterPage(STANDARD, activePageHeader, activePageFooter))
+ {
+
+ final CSSNumericValue headerSize = context.getAllHeaderSize();
+ final CSSNumericValue footerSize = context.getAllFooterSize();
+
+
+ currentMasterPage = masterPageFactory.createMasterPage(STANDARD, activePageHeader, activePageFooter);
+
+ // todo: Store the page-layouts as well.
+ // The page layouts are derived from a common template, but as the
+ // header-heights differ, we have to derive these beasts instead
+ // of copying them
+
+ final OfficeStylesCollection officeStylesCollection = getGlobalStylesCollection();
+ final OfficeMasterStyles officeMasterStyles = officeStylesCollection.getMasterStyles();
+ final String pageLayoutTemplate = currentMasterPage.getPageLayout();
+ if (pageLayoutTemplate == null)
+ {
+ // there is no pagelayout. Create one ..
+ final String derivedLayout = masterPageFactory.createPageStyle(getGlobalStylesCollection().getAutomaticStyles(), headerSize, footerSize);
+ currentMasterPage.setPageLayout(derivedLayout);
+ }
+ else
+ {
+ final String derivedLayout = masterPageFactory.derivePageStyle(pageLayoutTemplate,
+ getPredefinedStylesCollection().getAutomaticStyles(),
+ getGlobalStylesCollection().getAutomaticStyles(), headerSize, footerSize);
+ currentMasterPage.setPageLayout(derivedLayout);
+ }
+ officeMasterStyles.addMasterPage(currentMasterPage);
+ masterPageName = currentMasterPage.getStyleName();
+ }
+ else
+ {
+ // retrieve the master-page.
+ final OfficeMasterPage masterPage = masterPageFactory.getMasterPage(STANDARD, activePageHeader, activePageFooter);
+ if (ObjectUtilities.equal(masterPage.getStyleName(), currentMasterPage.getStyleName()))
+ {
+ // They are the same,
+ masterPageName = null;
+ }
+ else
+ {
+ // reuse the existing one ..
+ currentMasterPage = masterPage;
+ masterPageName = currentMasterPage.getStyleName();
+ }
+ }
+
+ // if either the pageheader or footer are *not* printed with the
+ // report header, then this implies that we have to insert a manual
+ // pagebreak at the end of the section.
+
+ if ((!printHeader && context.getHeader() != null) || (!printFooter && context.getFooter() != null))
+ {
+ setPagebreakDefinition(new PageBreakDefinition(isResetPageNumber()));
+ }
+
+ return masterPageName;
+ }
+
+ private boolean isColumnBreakPending()
+ {
+ return columnBreakPending;
+ }
+
+ private void setColumnBreakPending(final boolean columnBreakPending)
+ {
+ this.columnBreakPending = columnBreakPending;
+ }
+
+ private Integer parseInt(final Object value)
+ {
+ if (value instanceof Number)
+ {
+ final Number n = (Number) value;
+ return IntegerCache.getInteger(n.intValue());
+ }
+ if (value instanceof String)
+ {
+ try
+ {
+ return IntegerCache.getInteger(Integer.parseInt((String) value));
+ }
+ catch (NumberFormatException nfe)
+ {
+ //return null; // ignore
+ }
+ }
+ return null;
+ }
+
+ private BufferState applyColumnsToPageBand(final BufferState contents,
+ final int numberOfColumns)
+ throws IOException, ReportProcessingException
+ {
+ if (numberOfColumns <= 1)
+ {
+ return contents;
+ }
+ startBuffering(getGlobalStylesCollection(), true);
+ // derive section style ..
+
+ // This is a rather cheap solution to the problem. In a sane world, we would have to feed the
+ // footer multiple times. Right now, we simply rely on the balancing, which should make sure that
+ // the column's content are evenly distributed.
+ final XmlWriter writer = getXmlWriter();
+ final AttributeList attrs = new AttributeList();
+ attrs.setAttribute(OfficeNamespaces.TEXT_NS, OfficeToken.STYLE_NAME, generateSectionStyle(numberOfColumns));
+ attrs.setAttribute(OfficeNamespaces.TEXT_NS, NAME, sectionNames.generateName("Section"));
+ writer.writeTag(OfficeNamespaces.TEXT_NS, "section", attrs, XmlWriterSupport.OPEN);
+ for (int i = 0; i < numberOfColumns; i++)
+ {
+ writer.writeStream(contents.getXmlAsReader());
+ }
+
+ writer.writeCloseTag();
+ return finishBuffering();
+ }
+
+ private String generateSectionStyle(final int columnCount)
+ {
+ final OfficeStyles automaticStyles = getStylesCollection().getAutomaticStyles();
+ final String styleName = getAutoStyleNameGenerator().generateName("auto_section_style");
+
+ final Section sectionProperties = new Section();
+ sectionProperties.setNamespace(OfficeNamespaces.STYLE_NS);
+ sectionProperties.setType("section-properties");
+ sectionProperties.setAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR, "transparent");
+ sectionProperties.setAttribute(OfficeNamespaces.TEXT_NS, "dont-balance-text-columns", OfficeToken.FALSE);
+ sectionProperties.setAttribute(OfficeNamespaces.STYLE_NS, "editable", OfficeToken.FALSE);
+
+ if (columnCount > 1)
+ {
+ final Section columns = new Section();
+ columns.setNamespace(OfficeNamespaces.STYLE_NS);
+ columns.setType("columns");
+ columns.setAttribute(OfficeNamespaces.FO_NS, "column-count", String.valueOf(columnCount));
+ columns.setAttribute(OfficeNamespaces.STYLE_NS, "column-gap", "0cm");
+ sectionProperties.addNode(columns);
+
+ for (int i = 0; i < columnCount; i++)
+ {
+ final Section column = new Section();
+ column.setNamespace(OfficeNamespaces.STYLE_NS);
+ column.setType("column");
+ column.setAttribute(OfficeNamespaces.STYLE_NS, "rel-width", "1*");
+ column.setAttribute(OfficeNamespaces.FO_NS, "start-indent", "0cm");
+ column.setAttribute(OfficeNamespaces.FO_NS, "end-indent", "0cm");
+ columns.addNode(column);
+ }
+ }
+
+ final OfficeStyle style = new OfficeStyle();
+ style.setNamespace(OfficeNamespaces.STYLE_NS);
+ style.setType("style");
+ style.setAttribute(OfficeNamespaces.STYLE_NS, NAME, styleName);
+ style.setAttribute(OfficeNamespaces.STYLE_NS, "family", "section");
+ style.addNode(sectionProperties);
+
+ automaticStyles.addStyle(style);
+ return styleName;
+ }
+
+ /**
+ * Starts the output of a new office document. This method writes the generic 'office:document-content' tag along with
+ * all known namespace declarations.
+ *
+ * @param report the report object.
+ * @throws org.jfree.report.DataSourceException
+ * if there was an error accessing the datasource
+ * @throws org.jfree.report.ReportProcessingException
+ * if some other error occurred.
+ */
+ @Override
+ public void startReport(final ReportStructureRoot report)
+ throws DataSourceException, ReportProcessingException
+ {
+ super.startReport(report);
+ variablesDeclarations = new VariablesDeclarations();
+ detailBandProcessingState = DETAIL_SECTION_WAIT;
+ sectionNames.reset();
+
+ pageFooterOnReportFooter = false;
+ pageFooterOnReportHeader = false;
+ pageHeaderOnReportFooter = false;
+ pageHeaderOnReportHeader = false;
+ contentProcessingState = TextRawReportTarget.CP_SETUP;
+
+ activePageContext.clear();
+ activePageContext.push(new PageContext());
+
+ final OfficeStylesCollection predefStyles = getPredefinedStylesCollection();
+ masterPageFactory = new MasterPageFactory(predefStyles.getMasterStyles());
+
+ predefStyles.getAutomaticStyles().addStyle(createVariablesStyle(true));
+ predefStyles.getAutomaticStyles().addStyle(createVariablesStyle(false));
+ }
+
+ private OfficeStyle createVariablesStyle(final boolean keepWithNext)
+ {
+ final OfficeStyle variablesSectionStyle = new OfficeStyle();
+ variablesSectionStyle.setStyleFamily(OfficeToken.PARAGRAPH);
+ if (keepWithNext)
+ {
+ variablesSectionStyle.setStyleName(TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT);
+ }
+ else
+ {
+ variablesSectionStyle.setStyleName(TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITHOUT_KEEPWNEXT);
+ }
+
+ final Section paragraphProps = new Section();
+ paragraphProps.setNamespace(OfficeNamespaces.STYLE_NS);
+ paragraphProps.setType(PARAGRAPH_PROPERTIES);
+ paragraphProps.setAttribute(OfficeNamespaces.FO_NS, OfficeToken.BACKGROUND_COLOR, "transparent");
+ paragraphProps.setAttribute(OfficeNamespaces.FO_NS, "text-align", "start");
+ paragraphProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_WITH_NEXT, ALWAYS);
+ paragraphProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_TOGETHER, ALWAYS);
+ paragraphProps.setAttribute(OfficeNamespaces.STYLE_NS, "vertical-align", "top");
+ variablesSectionStyle.addNode(paragraphProps);
+
+ final Section textProps = new Section();
+ textProps.setNamespace(OfficeNamespaces.STYLE_NS);
+ textProps.setType("text-properties");
+ textProps.setAttribute(OfficeNamespaces.FO_NS, "font-variant", NORMAL);
+ textProps.setAttribute(OfficeNamespaces.FO_NS, "text-transform", NONE);
+ textProps.setAttribute(OfficeNamespaces.FO_NS, "color", "#ffffff");
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-outline", OfficeToken.FALSE);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-blinking", OfficeToken.FALSE);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-line-through-style", NONE);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-line-through-mode", "continuous");
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-position", "0% 100%");
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "font-name", "Tahoma");
+ textProps.setAttribute(OfficeNamespaces.FO_NS, "font-size", "1pt");
+ textProps.setAttribute(OfficeNamespaces.FO_NS, "letter-spacing", NORMAL);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "letter-kerning", OfficeToken.FALSE);
+ textProps.setAttribute(OfficeNamespaces.FO_NS, "font-style", NORMAL);
+ textProps.setAttribute(OfficeNamespaces.FO_NS, "text-shadow", NONE);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-underline-style", NONE);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-underline-mode", "continuous");
+ textProps.setAttribute(OfficeNamespaces.FO_NS, "font-weight", NORMAL);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-rotation-angle", "0");
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-emphasize", NONE);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-combine", NONE);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-combine-start-char", "");
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-combine-end-char", "");
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-blinking", OfficeToken.FALSE);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-scale", "100%");
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "font-relief", NONE);
+ textProps.setAttribute(OfficeNamespaces.STYLE_NS, "text-display", NONE);
+ variablesSectionStyle.addNode(textProps);
+ return variablesSectionStyle;
+ }
+
+ @Override
+ protected void startContent(final AttributeMap attrs)
+ throws IOException, DataSourceException, ReportProcessingException
+ {
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "text", null, XmlWriterSupport.OPEN);
+
+ writeNullDate();
+
+ // now start the buffering. We have to insert the variables declaration
+ // later ..
+ startBuffering(getStylesCollection(), true);
+
+ final Object columnCountRaw = attrs.getAttribute(OfficeNamespaces.FO_NS, "column-count");
+ final Integer colCount = parseInt(columnCountRaw);
+ if (colCount != null)
+ {
+ final PageContext pageContext = getCurrentContext();
+ pageContext.setColumnCount(colCount);
+ }
+
+ }
+
+ @Override
+ protected void startOther(final AttributeMap attrs)
+ throws IOException, DataSourceException, ReportProcessingException
+ {
+ final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
+ final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
+
+ if (ObjectUtilities.equal(JFreeReportInfo.REPORT_NAMESPACE, namespace))
+ {
+ if (ObjectUtilities.equal(OfficeToken.IMAGE, elementType))
+ {
+ startImageProcessing(attrs);
+ }
+ else if (ObjectUtilities.equal(OfficeToken.OBJECT_OLE, elementType) && getCurrentRole() != ROLE_TEMPLATE)
+ {
+ startChartProcessing(attrs);
+ }
+ return;
+ }
+ else if (isFilteredNamespace(namespace))
+ {
+ throw new IllegalStateException("This element should be hidden: " + namespace + ", " + elementType);
+ }
+
+ if (isTableMergeActive() && detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED && ObjectUtilities.equal(OfficeNamespaces.TABLE_NS, namespace) && ObjectUtilities.equal(OfficeToken.TABLE_COLUMNS, elementType))
+ {
+ // Skip the columns section if the tables get merged...
+ startBuffering(getStylesCollection(), true);
+ }
+ else
+ {
+ openSection();
+
+ final boolean isTableNS = ObjectUtilities.equal(OfficeNamespaces.TABLE_NS, namespace);
+ if (isTableNS)
+ {
+ if (ObjectUtilities.equal(OfficeToken.TABLE, elementType))
+ {
+ startTable(attrs);
+ return;
+ }
+
+ if (ObjectUtilities.equal(OfficeToken.TABLE_ROW, elementType))
+ {
+ startRow(attrs);
+ return;
+ }
+ }
+
+
+ if (ObjectUtilities.equal(OfficeNamespaces.TEXT_NS, namespace))
+ {
+ if (ObjectUtilities.equal("variable-set", elementType))
+ {
+ // update the variables-declaration thingie ..
+ final String varName = (String) attrs.getAttribute(OfficeNamespaces.TEXT_NS, NAME);
+ final String varType = (String) attrs.getAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE);
+ final String newVarName = variablesDeclarations.produceVariable(varName, varType);
+ attrs.setAttribute(OfficeNamespaces.TEXT_NS, NAME, newVarName);
+ }
+ else if (ObjectUtilities.equal("variable-get", elementType))
+ {
+ final String varName = (String) attrs.getAttribute(OfficeNamespaces.TEXT_NS, NAME);
+ final String varType = (String) attrs.getAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE);
+ final String newVarName = variablesDeclarations.produceVariable(varName, varType);
+ attrs.setAttribute(OfficeNamespaces.TEXT_NS, NAME, newVarName);
+ }
+ }
+
+ if (tableLayoutConfig == TABLE_LAYOUT_VARIABLES_PARAGRAPH && variables != null)
+ {
+ // This cannot happen as long as the report sections only contain tables. But at some point in the
+ // future they will be made of paragraphs, and then we are prepared ..
+
+ StyleUtilities.copyStyle(OfficeToken.PARAGRAPH,
+ TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, getStylesCollection(),
+ getGlobalStylesCollection(), getPredefinedStylesCollection());
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME,
+ TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, XmlWriterSupport.OPEN);
+ xmlWriter.writeText(variables);
+ xmlWriter.writeCloseTag();
+ variables = null;
+ }
+
+ final boolean keepTogetherOnParagraph = true;
+
+ if (keepTogetherOnParagraph)
+ {
+ if (ReportTargetUtil.isElementOfType(OfficeNamespaces.TEXT_NS, OfficeToken.P, attrs))
+ {
+ final int keepTogetherState = getCurrentContext().getKeepTogether();
+ if (!firstCellSeen && (sectionKeepTogether || keepTogetherState == PageContext.KEEP_TOGETHER_GROUP))
+ {
+ OfficeStyle style = null;
+ final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TEXT_NS, OfficeToken.STYLE_NAME);
+ if (styleName == null)
+ {
+ final boolean keep = (keepTogetherState == PageContext.KEEP_TOGETHER_GROUP || expectedTableRowCount > 0) && isParentKeepTogether();
+ final ArrayList<String> propertyNameSpaces = new ArrayList<String>();
+ final ArrayList<String> propertyNames = new ArrayList<String>();
+ final ArrayList<String> propertyValues = new ArrayList<String>();
+
+ propertyNameSpaces.add(OfficeNamespaces.FO_NS);
+ propertyNameSpaces.add(OfficeNamespaces.FO_NS);
+ propertyNames.add(KEEP_TOGETHER);
+ propertyValues.add(ALWAYS);
+ if (keep)
+ {
+ propertyNames.add(KEEP_WITH_NEXT);
+ propertyValues.add(ALWAYS);
+ }
+ else
+ {
+ propertyNames.add(KEEP_WITH_NEXT);
+ propertyValues.add(null);
+ }
+ style = StyleUtilities.queryStyleByProperties(getStylesCollection(), OfficeToken.PARAGRAPH, PARAGRAPH_PROPERTIES, propertyNameSpaces, propertyNames, propertyValues);
+ }
+ if (style == null)
+ {
+ style = deriveStyle(OfficeToken.PARAGRAPH, styleName);
+ // Lets set the 'keep-together' flag...
+
+ Element paragraphProps = style.getParagraphProperties();
+ if (paragraphProps == null)
+ {
+ paragraphProps = new Section();
+ paragraphProps.setNamespace(OfficeNamespaces.STYLE_NS);
+ paragraphProps.setType(PARAGRAPH_PROPERTIES);
+ style.addNode(paragraphProps);
+ }
+ paragraphProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_TOGETHER, ALWAYS);
+
+ // We prevent pagebreaks within the two adjacent rows (this one and the next one) if
+ // either a group-wide keep-together is defined or if we haven't reached the end of the
+ // current section yet.
+ if ((keepTogetherState == PageContext.KEEP_TOGETHER_GROUP || expectedTableRowCount > 0) && isParentKeepTogether())
+ {
+ paragraphProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_WITH_NEXT, ALWAYS);
+ }
+ }
+
+ attrs.setAttribute(OfficeNamespaces.TEXT_NS, OfficeToken.STYLE_NAME, style.getStyleName());
+ }
+ }
+ }
+
+ if (ObjectUtilities.equal(OfficeNamespaces.DRAWING_NS, namespace) && ObjectUtilities.equal(OfficeToken.FRAME, elementType))
+ {
+ final String styleName = (String) attrs.getAttribute(OfficeNamespaces.DRAWING_NS, OfficeToken.STYLE_NAME);
+ final OfficeStyle predefAutoStyle = getPredefinedStylesCollection().getAutomaticStyles().getStyle(OfficeToken.GRAPHIC, styleName);
+ if (predefAutoStyle != null)
+ {
+ // special ole handling
+ final Element graphicProperties = predefAutoStyle.getGraphicProperties();
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, VERTICAL_POS, "from-top");
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, HORIZONTAL_POS, "from-left");
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "vertical-rel", "paragraph-content");
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "horizontal-rel", "paragraph");
+ graphicProperties.setAttribute(OfficeNamespaces.STYLE_NS, "flow-with-text", "false");
+ graphicProperties.setAttribute(OfficeNamespaces.DRAWING_NS, "ole-draw-aspect", "1");
+
+ }
+ }
+
+ // process the styles as usual
+ performStyleProcessing(attrs);
+ final XmlWriter xmlWriter = getXmlWriter();
+ final AttributeList attrList = buildAttributeList(attrs);
+ xmlWriter.writeTag(namespace, elementType, attrList, XmlWriterSupport.OPEN);
+
+ if (tableLayoutConfig != TABLE_LAYOUT_VARIABLES_PARAGRAPH
+ && variables != null
+ && !isRepeatingSection()
+ && ReportTargetUtil.isElementOfType(OfficeNamespaces.TEXT_NS, OfficeToken.P, attrs))
+ {
+ xmlWriter.writeText(variables);
+ variables = null;
+ }
+ }
+ }
+
+ private void startRow(final AttributeMap attrs)
+ throws IOException, ReportProcessingException
+ {
+ firstCellSeen = false;
+ expectedTableRowCount -= 1;
+ final String rowStyle = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
+ final CSSNumericValue rowHeight = computeRowHeight(rowStyle);
+ sectionHeight.add(rowHeight);
+
+ // process the styles as usual
+ performStyleProcessing(attrs);
+
+ final AttributeList attrList = buildAttributeList(attrs);
+ getXmlWriter().writeTag(OfficeNamespaces.TABLE_NS, OfficeToken.TABLE_ROW, attrList, XmlWriterSupport.OPEN);
+ }
+
+ private void startTable(final AttributeMap attrs)
+ throws ReportProcessingException, IOException
+ {
+ final Integer trc = (Integer) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "table-row-count");
+ if (trc == null)
+ {
+ expectedTableRowCount = -1;
+ }
+ else
+ {
+ expectedTableRowCount = trc;
+ }
+
+ if (isSectionPagebreakBefore(attrs))
+ {
+ // force a pagebreak ..
+ setPagebreakDefinition(new PageBreakDefinition(isResetPageNumber()));
+ }
+
+ // it's a table. This means, it is a root-level element
+ final PageBreakDefinition breakDefinition;
+ String masterPageName = null;
+ final int currentRole = getCurrentRole();
+ if (contentProcessingState == TextRawReportTarget.CP_FIRST_TABLE)
+ {
+ contentProcessingState = TextRawReportTarget.CP_NEXT_TABLE;
+
+ // Processing the report header now.
+ if (currentRole == OfficeDocumentReportTarget.ROLE_REPORT_HEADER)
+ {
+ breakDefinition = new PageBreakDefinition(isResetPageNumber());
+ masterPageName = createMasterPage(pageHeaderOnReportHeader, pageFooterOnReportHeader);
+ if (masterPageName == null)
+ {
+ // we should always have a master-page ...
+ masterPageName = currentMasterPage.getStyleName();
+ }
+ }
+ else if (currentRole == OfficeDocumentReportTarget.ROLE_REPORT_FOOTER)
+ {
+ breakDefinition = new PageBreakDefinition(isResetPageNumber());
+ masterPageName = createMasterPage(pageHeaderOnReportFooter, pageFooterOnReportFooter);
+ if (masterPageName == null && isSectionPagebreakBefore(attrs))
+ {
+ // If we have a manual pagebreak, then activate the current master-page again.
+ masterPageName = currentMasterPage.getStyleName();
+ }
+ // But we skip this (and therefore the resulting pagebreak) if there is no manual break
+ // and no other condition that would force a break.
+ }
+ else if (currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER || currentRole == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER)
+ {
+ breakDefinition = null;
+ // no pagebreaks ..
+ }
+ else if (currentMasterPage == null || isPagebreakPending())
+ {
+ // Must be the first table, as we have no master-page yet.
+ masterPageName = createMasterPage(true, true);
+ setPagebreakDefinition(null);
+ if (masterPageName == null)
+ {
+ // we should always have a master-page ...
+ masterPageName = currentMasterPage.getStyleName();
+ }
+ breakDefinition = new PageBreakDefinition(isResetPageNumber());
+ }
+ else
+ {
+ breakDefinition = null;
+ }
+ }
+ else if (isPagebreakPending() && currentRole != OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER && currentRole != OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER)
+ {
+ // Derive an automatic style for the pagebreak.
+ breakDefinition = getPagebreakDefinition();
+ setPagebreakDefinition(null);
+ masterPageName = createMasterPage(true, true);
+ if (masterPageName == null || isSectionPagebreakBefore(attrs))
+ {
+ // If we have a manual pagebreak, then activate the current master-page again.
+ masterPageName = currentMasterPage.getStyleName();
+ }
+ }
+ else
+ {
+ breakDefinition = null;
+ }
+
+ final XmlWriter xmlWriter = getXmlWriter();
+ if (detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED && masterPageName != null)
+ {
+ // close the last table-tag, we will open a new one
+ xmlWriter.writeCloseTag();
+ // Reset the detail-state to 'started' so that the table's columns get printed now.
+ detailBandProcessingState = DETAIL_SECTION_OTHER_STARTED;
+ }
+
+ if (tableLayoutConfig == TABLE_LAYOUT_VARIABLES_PARAGRAPH && variables != null)
+ {
+ if (masterPageName != null)
+ {
+ // write a paragraph that uses the VARIABLES_HIDDEN_STYLE as
+ // primary style. Derive that one and add the manual pagebreak.
+ // The predefined style already has the 'keep-together' flags set.
+
+ final OfficeStyle style = deriveStyle(OfficeToken.PARAGRAPH, TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT);
+ style.setAttribute(OfficeNamespaces.STYLE_NS, "master-page-name", masterPageName);
+ if (breakDefinition.isResetPageNumber())
+ {
+ final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
+ paragraphProps.setAttribute(OfficeNamespaces.STYLE_NS, "page-number", "1");
+ }
+ if (isColumnBreakPending())
+ {
+ final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
+ paragraphProps.setAttribute(OfficeNamespaces.FO_NS, "break-before", "column");
+ setColumnBreakPending(false);
+ }
+ xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME, style.getStyleName(), XmlWriterSupport.OPEN);
+
+ masterPageName = null;
+ //breakDefinition = null;
+ }
+ else if (isColumnBreakPending())
+ {
+ setColumnBreakPending(false);
+
+ final OfficeStyle style = deriveStyle(OfficeToken.PARAGRAPH, TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT);
+ final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
+ paragraphProps.setAttribute(OfficeNamespaces.STYLE_NS, "page-number", "1");
+
+ xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME, style.getStyleName(), XmlWriterSupport.OPEN);
+ }
+ else
+ {
+ // Write a paragraph without adding the pagebreak. We can reuse the global style, but we have to make
+ // sure that the style is part of the current 'auto-style' collection.
+
+ StyleUtilities.copyStyle(OfficeToken.PARAGRAPH,
+ TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, getStylesCollection(),
+ getGlobalStylesCollection(), getPredefinedStylesCollection());
+ xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME,
+ TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, XmlWriterSupport.OPEN);
+ }
+ xmlWriter.writeText(variables);
+ xmlWriter.writeCloseTag();
+ variables = null;
+ }
+
+ final boolean keepWithNext = isKeepTableWithNext();
+ final boolean localKeepTogether = OfficeToken.TRUE.equals(attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, KEEP_TOGETHER));
+ final boolean tableMergeActive = isTableMergeActive();
+ this.sectionKeepTogether = tableMergeActive && localKeepTogether;
+
+ // Check, whether we have a reason to derive a style...
+ if (masterPageName != null || (!tableMergeActive && (localKeepTogether || keepWithNext)) || isColumnBreakPending())
+ {
+ final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
+ final OfficeStyle style = deriveStyle("table", styleName);
+
+ if (masterPageName != null)
+ {
+ // Patch the current styles.
+ // This usually only happens on Table-Styles or Paragraph-Styles
+ style.setAttribute(OfficeNamespaces.STYLE_NS, "master-page-name", masterPageName);
+ if (breakDefinition.isResetPageNumber())
+ {
+ final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
+ paragraphProps.setAttribute(OfficeNamespaces.STYLE_NS, "page-number", "1");
+ }
+ }
+ if (isColumnBreakPending())
+ {
+ final Element paragraphProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, PARAGRAPH_PROPERTIES);
+ paragraphProps.setAttribute(OfficeNamespaces.FO_NS, "break-before", "column");
+ setColumnBreakPending(false);
+ }
+
+ // Inhibit breaks inside the table only if it has been defined and if we do not create one single
+ // big detail section. In that case, this flag would be invalid and would cause layout-errors.
+ if (!tableMergeActive)
+ {
+ if (localKeepTogether)
+ {
+ final Element tableProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, TABLE_PROPERTIES);
+ tableProps.setAttribute(OfficeNamespaces.STYLE_NS, MAY_BREAK_BETWEEN_ROWS, OfficeToken.FALSE);
+ }
+ }
+ else
+ {
+ if (detailBandProcessingState == DETAIL_SECTION_WAIT)
+ {
+ detailBandProcessingState = DETAIL_SECTION_FIRST_STARTED;
+ }
+ else if (detailBandProcessingState == DETAIL_SECTION_FIRST_PRINTED)
+ {
+ detailBandProcessingState = DETAIL_SECTION_OTHER_STARTED;
+ }
+ }
+ if (keepWithNext)
+ {
+ boolean addKeepWithNext = true;
+ if (currentRole == ROLE_GROUP_FOOTER)
+ {
+ addKeepWithNext = isParentKeepTogether();
+ }
+
+ final Element tableProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, TABLE_PROPERTIES);
+ tableProps.setAttribute(OfficeNamespaces.STYLE_NS, MAY_BREAK_BETWEEN_ROWS, OfficeToken.FALSE);
+ if (addKeepWithNext)
+ {
+ tableProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_WITH_NEXT, ALWAYS);
+ // A keep-with-next does not work, if the may-break-betweek rows is not set to false ..
+ }
+ }
+ attrs.setAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME, style.getStyleName());
+ // no need to copy the styles, this was done while deriving the
+ // style ..
+ }
+ else
+ {
+ // Check, whether we may be able to skip the table.
+ if (tableMergeActive)
+ {
+ if (detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED)
+ {
+ // Skip the whole thing ..
+ return;
+ }
+ else if (detailBandProcessingState == DETAIL_SECTION_WAIT)
+ {
+ if (keepWithNext)
+ {
+ final String styleName = (String) attrs.getAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME);
+
+ final OfficeStyle style = deriveStyle(OfficeToken.TABLE, styleName);
+ final Element tableProps = produceFirstChild(style, OfficeNamespaces.STYLE_NS, TABLE_PROPERTIES);
+ // A keep-with-next does not work, if the may-break-betweek rows is not set to false ..
+ tableProps.setAttribute(OfficeNamespaces.STYLE_NS, MAY_BREAK_BETWEEN_ROWS, OfficeToken.FALSE);
+ final String hasGroupFooter = (String) attrs.getAttribute(JFreeReportInfo.REPORT_NAMESPACE, "has-group-footer");
+ if (hasGroupFooter != null && hasGroupFooter.equals(OfficeToken.TRUE))
+ {
+ tableProps.setAttribute(OfficeNamespaces.FO_NS, KEEP_WITH_NEXT, ALWAYS);
+ }
+
+ attrs.setAttribute(OfficeNamespaces.TABLE_NS, OfficeToken.STYLE_NAME, style.getStyleName());
+ }
+ detailBandProcessingState = DETAIL_SECTION_FIRST_STARTED;
+ }
+ else if (detailBandProcessingState == DETAIL_SECTION_FIRST_PRINTED)
+ {
+ detailBandProcessingState = DETAIL_SECTION_OTHER_STARTED;
+ }
+ }
+
+ // process the styles as usual
+ performStyleProcessing(attrs);
+ }
+
+ final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
+ final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
+ final AttributeList attrList = buildAttributeList(attrs);
+ xmlWriter.writeTag(namespace, elementType, attrList, XmlWriterSupport.OPEN);
+ }
+
+ private boolean isParentKeepTogether()
+ {
+ PageContext context = getCurrentContext();
+ if (context != null)
+ {
+ context = context.getParent();
+ if (context != null)
+ {
+ return context.getKeepTogether() == PageContext.KEEP_TOGETHER_GROUP;
+ }
+ }
+ return false;
+ }
+
+ private boolean isTableMergeActive()
+ {
+ return getCurrentRole() == ROLE_DETAIL && tableLayoutConfig == TABLE_LAYOUT_SINGLE_DETAIL_TABLE;
+ }
+
+ private void openSection()
+ throws IOException
+ {
+ if (isRepeatingSection())
+ {
+ // repeating sections have other ways of defining columns ..
+ return;
+ }
+ if (getCurrentRole() == ROLE_TEMPLATE || getCurrentRole() == ROLE_SPREADSHEET_PAGE_HEADER || getCurrentRole() == ROLE_SPREADSHEET_PAGE_FOOTER)
+ {
+ // the template section would break the multi-column stuff and we don't open up sections there
+ // anyway ..
+ return;
+ }
+
+ final PageContext pageContext = getCurrentContext();
+ final Integer columnCount = pageContext.getColumnCount();
+ if (columnCount != null && !pageContext.isSectionOpen())
+ {
+ final AttributeList attrs = new AttributeList();
+ attrs.setAttribute(OfficeNamespaces.TEXT_NS, OfficeToken.STYLE_NAME, generateSectionStyle(columnCount));
+ attrs.setAttribute(OfficeNamespaces.TEXT_NS, NAME, sectionNames.generateName("Section"));
+ getXmlWriter().writeTag(OfficeNamespaces.TEXT_NS, "section", attrs, XmlWriterSupport.OPEN);
+
+ pageContext.setSectionOpen(true);
+ }
+
+ }
+
+ @Override
+ protected void startReportSection(final AttributeMap attrs, final int role)
+ throws ReportProcessingException
+ {
+ sectionHeight = new LengthCalculator();
+ if (role == OfficeDocumentReportTarget.ROLE_TEMPLATE || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_HEADER || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_FOOTER)
+ {
+ // Start buffering with a dummy styles-collection, so that the global styles don't get polluted...
+ startBuffering(new OfficeStylesCollection(), true);
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_PAGE_HEADER)
+ {
+ startBuffering(getGlobalStylesCollection(), true);
+ pageHeaderOnReportHeader = PageSection.isPrintWithReportHeader(attrs);
+ pageHeaderOnReportFooter = PageSection.isPrintWithReportFooter(attrs);
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_PAGE_FOOTER)
+ {
+ startBuffering(getGlobalStylesCollection(), true);
+ pageFooterOnReportHeader = PageSection.isPrintWithReportHeader(attrs);
+ pageFooterOnReportFooter = PageSection.isPrintWithReportFooter(attrs);
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER || role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER)
+ {
+ startBuffering(getGlobalStylesCollection(), true);
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_VARIABLES)
+ {
+ startBuffering(getGlobalStylesCollection(), false);
+ }
+ else
+ {
+ contentProcessingState = TextRawReportTarget.CP_FIRST_TABLE;
+ if (role == OfficeDocumentReportTarget.ROLE_GROUP_HEADER || role == OfficeDocumentReportTarget.ROLE_GROUP_FOOTER)
+ {
+ // if we have a repeating header, then skip the first one ..
+ // if this is a repeating footer, skip the last one. This means,
+ // we have to buffer all group footers and wait for the next section...
+ startBuffering(getContentStylesCollection(), true);
+ }
+
+ if (role != OfficeDocumentReportTarget.ROLE_DETAIL)
+ {
+ // reset the detail-state. The flag will be updated on startTable and endOther(Table) if the
+ // current role is ROLE_DETAIL
+ detailBandProcessingState = DETAIL_SECTION_WAIT;
+ }
+ }
+ }
+
+ @Override
+ protected void startGroup(final AttributeMap attrs)
+ {
+ super.startGroup(attrs);
+ final PageContext pageContext = new PageContext(getCurrentContext());
+ activePageContext.push(pageContext);
+
+ final Object resetPageNumber = attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "reset-page-number");
+ if (OfficeToken.TRUE.equals(resetPageNumber))
+ {
+ setPagebreakDefinition(new PageBreakDefinition(true));
+ }
+
+ final Object keepTogether = attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, KEEP_TOGETHER);
+ if ("whole-group".equals(keepTogether))
+ {
+ pageContext.setKeepTogether(PageContext.KEEP_TOGETHER_GROUP);
+ }
+ else if ("with-first-detail".equals(keepTogether) && pageContext.getKeepTogether() != PageContext.KEEP_TOGETHER_GROUP)
+ {
+ pageContext.setKeepTogether(PageContext.KEEP_TOGETHER_FIRST_DETAIL);
+ }
+
+ final Object columnCountRaw = attrs.getAttribute(OfficeNamespaces.FO_NS, "column-count");
+ final Integer colCount = parseInt(columnCountRaw);
+ if (colCount != null)
+ {
+ pageContext.setColumnCount(colCount);
+ }
+
+ final Object newColumn = attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "start-new-column");
+ if (OfficeToken.TRUE.equals(newColumn))
+ {
+ setColumnBreakPending(true);
+ }
+ }
+
+ @Override
+ protected void startGroupInstance(final AttributeMap attrs)
+ {
+ if (getGroupContext().isGroupWithRepeatingSection())
+ {
+ setPagebreakDefinition(new PageBreakDefinition(isResetPageNumber()));
+ }
+ }
+
+ @Override
+ protected void endGroup(final AttributeMap attrs)
+ throws ReportProcessingException
+ {
+ if (getGroupContext().isGroupWithRepeatingSection())
+ {
+ setPagebreakDefinition(new PageBreakDefinition(isResetPageNumber()));
+ }
+
+ super.endGroup(attrs);
+ finishSection();
+
+ activePageContext.pop();
+ }
+
+ private void finishSection()
+ throws ReportProcessingException
+ {
+ final PageContext pageContext = getCurrentContext();
+ if (pageContext.isSectionOpen())
+ {
+ pageContext.setSectionOpen(false);
+ try
+ {
+ getXmlWriter().writeCloseTag();
+ }
+ catch (IOException e)
+ {
+ throw new ReportProcessingException("IOError", e);
+ }
+ }
+ }
+
+ @Override
+ protected void endReportSection(final AttributeMap attrs, final int role)
+ throws IOException, ReportProcessingException
+ {
+ if (role == ROLE_TEMPLATE || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_HEADER || role == OfficeDocumentReportTarget.ROLE_SPREADSHEET_PAGE_FOOTER)
+ {
+ finishBuffering();
+ return;
+ }
+
+ final CSSNumericValue result = sectionHeight.getResult();
+ if (role == OfficeDocumentReportTarget.ROLE_PAGE_HEADER)
+ {
+ final PageContext pageContext = getCurrentContext();
+ pageContext.setHeader(applyColumnsToPageBand(finishBuffering(), pageContext.getActiveColumns()).getXmlBuffer(), result);
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_PAGE_FOOTER)
+ {
+ final PageContext pageContext = getCurrentContext();
+ pageContext.setFooter(applyColumnsToPageBand(finishBuffering(), pageContext.getActiveColumns()).getXmlBuffer(), result);
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_HEADER)
+ {
+ final PageContext pageContext = getCurrentContext();
+ pageContext.setHeader(applyColumnsToPageBand(finishBuffering(), pageContext.getActiveColumns()).getXmlBuffer(), result);
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_REPEATING_GROUP_FOOTER)
+ {
+ final PageContext pageContext = getCurrentContext();
+ pageContext.setFooter(applyColumnsToPageBand(finishBuffering(), pageContext.getActiveColumns()).getXmlBuffer(), result);
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_VARIABLES)
+ {
+ if (variables == null)
+ {
+ variables = finishBuffering().getXmlBuffer();
+ }
+ else
+ {
+ variables += finishBuffering().getXmlBuffer();
+ }
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_GROUP_HEADER)
+ {
+ final String headerText = finishBuffering().getXmlBuffer();
+ final int iterationCount = getGroupContext().getParent().getIterationCount();
+ final boolean repeat = OfficeToken.TRUE.equals(attrs.getAttribute(OfficeNamespaces.OOREPORT_NS, "repeat-section"));
+ if (!repeat || iterationCount > 0)
+ {
+ getXmlWriter().writeText(headerText);
+ }
+ }
+ else if (role == OfficeDocumentReportTarget.ROLE_GROUP_FOOTER)
+ {
+ final String footerText = finishBuffering().getXmlBuffer();
+ // how do we detect whether this is the last group footer?
+ getXmlWriter().writeText(footerText);
+ }
+
+ }
+
+ @Override
+ public void endReport(final ReportStructureRoot report)
+ throws DataSourceException, ReportProcessingException
+ {
+ super.endReport(report);
+ variablesDeclarations = null;
+
+ try
+ {
+ // Write the settings ..
+ final AttributeList rootAttributes = new AttributeList();
+ rootAttributes.addNamespaceDeclaration("office", OfficeNamespaces.OFFICE_NS);
+ rootAttributes.addNamespaceDeclaration("config", OfficeNamespaces.CONFIG);
+ rootAttributes.addNamespaceDeclaration("ooo", OfficeNamespaces.OO2004_NS);
+ rootAttributes.setAttribute(OfficeNamespaces.OFFICE_NS, "version",
+ OfficeDocumentReportTarget.ODF_VERSION);
+ final OutputStream outputStream = getOutputRepository().createOutputStream("settings.xml", "text/xml");
+ final XmlWriter xmlWriter = new XmlWriter(new OutputStreamWriter(outputStream, "UTF-8"), createTagDescription());
+ xmlWriter.setAlwaysAddNamespace(true);
+ xmlWriter.writeXmlDeclaration("UTF-8");
+ xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "document-settings", rootAttributes, XmlWriterSupport.OPEN);
+ xmlWriter.writeTag(OfficeNamespaces.OFFICE_NS, "settings", XmlWriterSupport.OPEN);
+ xmlWriter.writeTag(OfficeNamespaces.CONFIG, "config-item-set", NAME, "ooo:configuration-settings", XmlWriterSupport.OPEN);
+
+ final AttributeList configAttributes = new AttributeList();
+ configAttributes.setAttribute(OfficeNamespaces.CONFIG, NAME, "TableRowKeep");
+ configAttributes.setAttribute(OfficeNamespaces.CONFIG, "type", "boolean");
+ xmlWriter.writeTag(OfficeNamespaces.CONFIG, "config-item", configAttributes, XmlWriterSupport.OPEN);
+ xmlWriter.writeText(OfficeToken.TRUE);
+ xmlWriter.writeCloseTag();
+
+ xmlWriter.writeCloseTag();
+ xmlWriter.writeCloseTag();
+ xmlWriter.writeCloseTag();
+ xmlWriter.close();
+
+ copyMeta();
+ }
+ catch (IOException ioe)
+ {
+ throw new ReportProcessingException("Failed to write settings document", ioe);
+ }
+ }
+
+ @Override
+ protected void endOther(final AttributeMap attrs)
+ throws IOException, DataSourceException, ReportProcessingException
+ {
+ final String namespace = ReportTargetUtil.getNamespaceFromAttribute(attrs);
+ final String elementType = ReportTargetUtil.getElemenTypeFromAttribute(attrs);
+
+ final boolean isInternalNS = ObjectUtilities.equal(JFreeReportInfo.REPORT_NAMESPACE, namespace);
+ final boolean isTableNs = ObjectUtilities.equal(OfficeNamespaces.TABLE_NS, namespace);
+ if (isTableMergeActive() && detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED && isTableNs && ObjectUtilities.equal(OfficeToken.TABLE_COLUMNS, elementType))
+ {
+ finishBuffering();
+ return;
+ }
+
+ if (isInternalNS && (ObjectUtilities.equal(OfficeToken.IMAGE, elementType) || ObjectUtilities.equal(OfficeToken.OBJECT_OLE, elementType)))
+ {
+ return;
+ }
+
+ final XmlWriter xmlWriter = getXmlWriter();
+ if (tableLayoutConfig != TABLE_LAYOUT_VARIABLES_PARAGRAPH && isTableNs && ObjectUtilities.equal(OfficeToken.TABLE_CELL, elementType) && !isRepeatingSection())
+ {
+ if (variables != null)
+ {
+ // This cannot happen as long as the report sections only contain tables. But at some point in the
+ // future they will be made of paragraphs, and then we are prepared ..
+ final String tag;
+ if (sectionKeepTogether && expectedTableRowCount > 0)
+ {
+ tag = TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT;
+ }
+ else
+ {
+ tag = TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITHOUT_KEEPWNEXT;
+ }
+ StyleUtilities.copyStyle(OfficeToken.PARAGRAPH,
+ tag, getStylesCollection(),
+ getGlobalStylesCollection(), getPredefinedStylesCollection());
+ xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME,
+ tag, XmlWriterSupport.OPEN);
+ xmlWriter.writeText(variables);
+ xmlWriter.writeCloseTag();
+ variables = null;
+ }
+ /**
+ // Only generate the empty paragraph, if we have to add the keep-together ..
+ else if (cellEmpty && expectedTableRowCount > 0 &&
+ sectionKeepTogether && !firstCellSeen)
+ {
+ // we have no variables ..
+ StyleUtilities.copyStyle(OfficeToken.PARAGRAPH,
+ TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, getStylesCollection(),
+ getGlobalStylesCollection(), getPredefinedStylesCollection());
+ xmlWriter.writeTag(OfficeNamespaces.TEXT_NS, OfficeToken.P, OfficeToken.STYLE_NAME,
+ TextRawReportTarget.VARIABLES_HIDDEN_STYLE_WITH_KEEPWNEXT, XmlWriterSupport.CLOSE);
+ }
+ */
+ }
+
+ if (isTableNs && (ObjectUtilities.equal(OfficeToken.TABLE_CELL, elementType) || ObjectUtilities.equal(OfficeToken.COVERED_TABLE_CELL, elementType)))
+ {
+ firstCellSeen = true;
+ }
+ if (isTableNs && ObjectUtilities.equal(OfficeToken.TABLE, elementType))
+ {
+ if (getCurrentRole() == ROLE_DETAIL)
+ {
+ if (!isTableMergeActive())
+ {
+ // We do not merge the detail bands, so an ordinary close will do.
+ xmlWriter.writeCloseTag();
+ }
+ else if (detailBandProcessingState == DETAIL_SECTION_FIRST_STARTED)
+ {
+ final int keepTogetherState = getCurrentContext().getKeepTogether();
+ if (keepTogetherState == PageContext.KEEP_TOGETHER_FIRST_DETAIL)
+ {
+ xmlWriter.writeCloseTag();
+ detailBandProcessingState = DETAIL_SECTION_FIRST_PRINTED;
+ }
+ else
+ {
+ detailBandProcessingState = DETAIL_SECTION_OTHER_PRINTED;
+ }
+ }
+ else if (detailBandProcessingState == DETAIL_SECTION_OTHER_STARTED)
+ {
+ detailBandProcessingState = DETAIL_SECTION_OTHER_PRINTED;
+ }
+ }
+ else
+ {
+ xmlWriter.writeCloseTag();
+ }
+ if (isSectionPagebreakAfter(attrs))
+ {
+ setPagebreakDefinition(new PageBreakDefinition(false));
+ }
+ }
+ else
+ {
+ xmlWriter.writeCloseTag();
+ }
+ }
+
+ @Override
+ protected void endGroupBody(final AttributeMap attrs)
+ throws IOException
+ {
+ if (tableLayoutConfig == TABLE_LAYOUT_SINGLE_DETAIL_TABLE && detailBandProcessingState == DETAIL_SECTION_OTHER_PRINTED)
+ {
+ // closes the table ..
+ final XmlWriter xmlWriter = getXmlWriter();
+ xmlWriter.writeCloseTag();
+ detailBandProcessingState = DETAIL_SECTION_WAIT;
+ }
+
+ }
+
+ @Override
+ protected void endContent(final AttributeMap attrs)
+ throws IOException, DataSourceException, ReportProcessingException
+ {
+ finishSection();
+ final BufferState bodyText = finishBuffering();
+ final XmlWriter writer = getXmlWriter();
+
+ final Map definedMappings = variablesDeclarations.getDefinedMappings();
+ if (!definedMappings.isEmpty())
+ {
+ writer.writeTag(OfficeNamespaces.TEXT_NS, "variable-decls", XmlWriterSupport.OPEN);
+ final Iterator mappingsIt = definedMappings.entrySet().iterator();
+ while (mappingsIt.hasNext())
+ {
+ final Map.Entry entry = (Map.Entry) mappingsIt.next();
+ final AttributeList entryList = new AttributeList();
+ entryList.setAttribute(OfficeNamespaces.TEXT_NS, NAME, (String) entry.getKey());
+ entryList.setAttribute(OfficeNamespaces.OFFICE_NS, FormatValueUtility.VALUE_TYPE, (String) entry.getValue());
+ writer.writeTag(OfficeNamespaces.TEXT_NS, "variable-decl", entryList, XmlWriterSupport.CLOSE);
+ }
+ writer.writeCloseTag();
+ }
+
+ writer.writeStream(bodyText.getXmlAsReader());
+ writer.setLineEmpty(true);
+ writer.writeCloseTag();
+ }
+
+ public String getExportDescriptor()
+ {
+ return "raw/" + PentahoReportEngineMetaData.OPENDOCUMENT_TEXT;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/output/text/VariablesDeclarations.java b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/VariablesDeclarations.java
new file mode 100644
index 000000000..a2d82f545
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/output/text/VariablesDeclarations.java
@@ -0,0 +1,98 @@
+/*
+ * 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.output.text;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.jfree.report.util.AttributeNameGenerator;
+
+
+/**
+ * A collection that holds all used variables. A variable is primarily keyed by
+ * its original name. If a variable contains more than one type, it is also
+ * keyed by the type.
+ *
+ * @since 26.03.2007
+ */
+public class VariablesDeclarations
+{
+
+ private final AttributeNameGenerator nameGenerator;
+ private final Map<String, HashMap<String,String> > variables;
+
+ public VariablesDeclarations()
+ {
+ variables = new HashMap<String, HashMap<String,String> >();
+ nameGenerator = new AttributeNameGenerator();
+ }
+
+ public String produceVariable(final String name,
+ final String type)
+ {
+ HashMap<String,String> holder = variables.get(name);
+ if (holder == null)
+ {
+ holder = new HashMap<String,String>();
+ variables.put(name, holder);
+ }
+
+ final String mapping = holder.get(type);
+ if (mapping != null)
+ {
+ return mapping;
+ }
+ final String result = nameGenerator.generateName(name);
+ if (holder.isEmpty())
+ {
+ // create the default mapping as well...
+ holder.put(null, name);
+ holder.put("time", name);
+ holder.put("date", name);
+ holder.put("datetime", name);
+ holder.put("float", name);
+ holder.put("string", name);
+ holder.put("boolean", name);
+ }
+ holder.put(type, name);
+ return result;
+ }
+
+ public Map<String,String> getDefinedMappings()
+ {
+ final HashMap<String,String> mappings = new HashMap<String,String>();
+ final Iterator<HashMap<String,String>> vars = variables.values().iterator();
+ while (vars.hasNext())
+ {
+ final HashMap<String,String> types = vars.next();
+ final Iterator<Map.Entry<String,String>> varsByType = types.entrySet().iterator();
+ while (varsByType.hasNext())
+ {
+ final Map.Entry<String,String> entry = varsByType.next();
+ final String type = entry.getKey();
+ if (type != null)
+ {
+ final String varName = entry.getValue();
+ mappings.put(varName, type);
+ }
+ }
+ }
+ return mappings;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/ElementReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/ElementReadHandler.java
new file mode 100644
index 000000000..fdec734c0
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/ElementReadHandler.java
@@ -0,0 +1,78 @@
+/*
+ * 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.parser;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * Creation-Date: 03.07.2006, 14:22:34
+ *
+ */
+public abstract class ElementReadHandler extends AbstractXmlReadHandler
+{
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ final Element element = getElement();
+ copyElementType(element);
+ copyAttributes(attrs, element);
+ }
+
+ protected void copyElementType(final Element element)
+ {
+ element.setType(getTagName());
+ element.setNamespace(getUri());
+ }
+
+ protected void copyAttributes(final Attributes attrs, final Element element)
+ {
+ final int length = attrs.getLength();
+ for (int i = 0; i < length; i++)
+ {
+ final String value = attrs.getValue(i);
+ final String namespace = attrs.getURI(i);
+ final String attr = attrs.getLocalName(i);
+ element.setAttribute(namespace, attr, value);
+ }
+ }
+
+ /**
+ * Returns the object for this element or null, if this element does not
+ * create an object.
+ *
+ * @return the object.
+ */
+ public Object getObject() throws SAXException
+ {
+ return getElement();
+ }
+
+ public abstract Element getElement();
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/OfficeDocumentXmlResourceFactory.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/OfficeDocumentXmlResourceFactory.java
new file mode 100644
index 000000000..5322e52ef
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/OfficeDocumentXmlResourceFactory.java
@@ -0,0 +1,39 @@
+/*
+ * 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.parser;
+
+import org.libreoffice.report.pentaho.model.OfficeDocument;
+
+import org.jfree.report.modules.factories.report.base.JFreeReportXmlResourceFactory;
+
+/**
+ * A LibLoader resource factory for OfficeDocument objects. OfficeDocuments are
+ * JFreeReport instances which have some additional properties.
+ *
+ * @since 09.03.2007
+ */
+@SuppressWarnings("ucd")
+public class OfficeDocumentXmlResourceFactory extends JFreeReportXmlResourceFactory
+{
+
+ @Override
+ public Class getFactoryType()
+ {
+ return OfficeDocument.class;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/OfficeStylesXmlResourceFactory.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/OfficeStylesXmlResourceFactory.java
new file mode 100644
index 000000000..8a12da80c
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/OfficeStylesXmlResourceFactory.java
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package org.libreoffice.report.pentaho.parser;
+
+import org.libreoffice.report.pentaho.model.OfficeStylesCollection;
+
+import org.jfree.report.JFreeReportBoot;
+
+import org.pentaho.reporting.libraries.base.config.Configuration;
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlResourceFactory;
+
+/**
+ * A LibLoader resource factory for loading an OfficeStyles-collection. This
+ * implementation is meant to parse the 'styles.xml' file.
+ *
+ * @since 09.03.2007
+ */
+@SuppressWarnings("ucd")
+public class OfficeStylesXmlResourceFactory extends AbstractXmlResourceFactory
+{
+
+ @Override
+ protected Configuration getConfiguration()
+ {
+ return JFreeReportBoot.getInstance().getGlobalConfig();
+ }
+
+ public Class getFactoryType()
+ {
+ return OfficeStylesCollection.class;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/StarStyleXmlFactoryModule.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/StarStyleXmlFactoryModule.java
new file mode 100644
index 000000000..7c7b70533
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/StarStyleXmlFactoryModule.java
@@ -0,0 +1,50 @@
+/*
+ * 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.parser;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.parser.office.DocumentStylesReadHandler;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlDocumentInfo;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlFactoryModule;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+@SuppressWarnings("ucd")
+public class StarStyleXmlFactoryModule implements XmlFactoryModule
+{
+
+ public XmlReadHandler createReadHandler(final XmlDocumentInfo documentInfo)
+ {
+ return new DocumentStylesReadHandler();
+ }
+
+ public int getDocumentSupport(final XmlDocumentInfo documentInfo)
+ {
+ final String rootNamespace = documentInfo.getRootElementNameSpace();
+ if (OfficeNamespaces.OFFICE_NS.equals(rootNamespace) && "document-styles".equals(documentInfo.getRootElement()))
+ {
+ return XmlFactoryModule.RECOGNIZED_BY_NAMESPACE;
+ }
+ return XmlFactoryModule.NOT_RECOGNIZED;
+ }
+
+ public String getDefaultNamespace(final XmlDocumentInfo documentInfo)
+ {
+ return null;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/StarXmlFactoryModule.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/StarXmlFactoryModule.java
new file mode 100644
index 000000000..ef81b23ad
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/StarXmlFactoryModule.java
@@ -0,0 +1,50 @@
+/*
+ * 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.parser;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.parser.office.DocumentContentReadHandler;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlDocumentInfo;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlFactoryModule;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+@SuppressWarnings("ucd")
+public class StarXmlFactoryModule implements XmlFactoryModule
+{
+
+ public XmlReadHandler createReadHandler(final XmlDocumentInfo documentInfo)
+ {
+ return new DocumentContentReadHandler();
+ }
+
+ public int getDocumentSupport(final XmlDocumentInfo documentInfo)
+ {
+ final String rootNamespace = documentInfo.getRootElementNameSpace();
+ if (OfficeNamespaces.OFFICE_NS.equals(rootNamespace) && ("document-content".equals(documentInfo.getRootElement()) || "document".equals(documentInfo.getRootElement())))
+ {
+ return XmlFactoryModule.RECOGNIZED_BY_NAMESPACE;
+ }
+ return XmlFactoryModule.NOT_RECOGNIZED;
+ }
+
+ public String getDefaultNamespace(final XmlDocumentInfo documentInfo)
+ {
+ return null;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/chart/ChartReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/chart/ChartReadHandler.java
new file mode 100644
index 000000000..4956dfb7a
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/chart/ChartReadHandler.java
@@ -0,0 +1,102 @@
+/*
+ * 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.parser.chart;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.rpt.DetailRootTableReadHandler;
+import org.libreoffice.report.pentaho.parser.rpt.ReportReadHandler;
+import org.libreoffice.report.pentaho.parser.text.TextContentReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+public class ChartReadHandler extends ElementReadHandler
+{
+
+ private final Section element;
+ private final List<ElementReadHandler> children;
+ private final ReportReadHandler reportHandler;
+
+ public ChartReadHandler(ReportReadHandler reportHandler)
+ {
+ this.reportHandler = reportHandler;
+ children = new ArrayList<ElementReadHandler>();
+ element = new Section();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if ("detail".equals(tagName))
+ {
+ final DetailRootTableReadHandler detail = new DetailRootTableReadHandler();
+ reportHandler.setDetail(detail);
+ return detail;
+ }
+ else if ("p".equals(tagName) && OfficeNamespaces.TEXT_NS.equals(uri))
+ {
+ final TextContentReadHandler readHandler = new TextContentReadHandler();
+ children.add(readHandler);
+ return readHandler;
+ }
+ final ChartReadHandler erh = new ChartReadHandler(reportHandler);
+ children.add(erh);
+ return erh;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (ElementReadHandler handler : children)
+ {
+ element.addNode(handler.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/data/DataStyleReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/data/DataStyleReadHandler.java
new file mode 100644
index 000000000..a3ef5963f
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/data/DataStyleReadHandler.java
@@ -0,0 +1,125 @@
+/*
+ * 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.parser.data;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.DataStyle;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.StaticText;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+public class DataStyleReadHandler extends ElementReadHandler
+{
+
+ private final DataStyle dataStyle;
+ private final List<Object> children;
+ private final boolean hasCData;
+
+ public DataStyleReadHandler(final boolean hasCData)
+ {
+ this.hasCData = hasCData;
+ this.dataStyle = new DataStyle();
+ this.children = new ArrayList<Object>();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.DATASTYLE_NS.equals(uri) || OfficeNamespaces.STYLE_NS.equals(uri))
+ {
+ final DataStyleReadHandler xrh = new DataStyleReadHandler("text".equals(tagName) || "currency-symbol".equals(tagName) || "embedded-text".equals(tagName));
+ children.add(xrh);
+ return xrh;
+ }
+
+ return null;
+ }
+
+ /**
+ * This method is called to process the character data between element tags.
+ *
+ * @param ch the character buffer.
+ * @param start the start index.
+ * @param length the length.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ public void characters(final char[] ch, final int start, final int length)
+ throws SAXException
+ {
+ if (hasCData)
+ {
+ children.add(new StaticText(new String(ch, start, length)));
+ }
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < children.size(); i++)
+ {
+ final Object o = children.get(i);
+ if (o instanceof ElementReadHandler)
+ {
+ final ElementReadHandler handler = (ElementReadHandler) o;
+ dataStyle.addNode(handler.getElement());
+ }
+ else if (o instanceof StaticText)
+ {
+ dataStyle.addNode((StaticText) o);
+ }
+ }
+ }
+
+ public DataStyle getDataStyle()
+ {
+ return dataStyle;
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return dataStyle;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/draw/ObjectOleReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/draw/ObjectOleReadHandler.java
new file mode 100644
index 000000000..1b7e8cb73
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/draw/ObjectOleReadHandler.java
@@ -0,0 +1,77 @@
+/*
+ * 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.parser.draw;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.ObjectOleElement;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import org.jfree.report.structure.Element;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ *
+ */
+public class ObjectOleReadHandler extends ElementReadHandler
+{
+
+ private static final String RPT_CHART_CLASS_ID = "80243D39-6741-46C5-926E-069164FF87BB";
+ private static final String OOO_CHART_CLASS_ID = "12DCAE26-281F-416F-A234-C3086127382E";
+ private final ObjectOleElement element;
+
+ public ObjectOleReadHandler(final ObjectOleElement element)
+ {
+ this.element = element;
+ }
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ super.startParsing(attrs);
+
+ final String url = attrs.getValue(OfficeNamespaces.XLINK_NS, "href");
+ if (url != null)
+ {
+ element.setUrl(url);
+ }
+
+ String classid = attrs.getValue(OfficeNamespaces.DRAWING_NS, "class-id");
+ if (classid != null)
+ {
+ if (classid.equalsIgnoreCase(RPT_CHART_CLASS_ID))
+ {
+ classid = OOO_CHART_CLASS_ID;
+ }
+ element.setClassId(classid);
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/BodyReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/BodyReadHandler.java
new file mode 100644
index 000000000..d7d7fafb8
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/BodyReadHandler.java
@@ -0,0 +1,85 @@
+/*
+ * 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.parser.office;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.rpt.ReportReadHandler;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class BodyReadHandler extends ElementReadHandler
+{
+
+ private ElementReadHandler reportReadHandler;
+ private final Section body;
+
+ public BodyReadHandler()
+ {
+ body = new Section();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri, final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.OFFICE_NS.equals(uri) && "report".equals(tagName))
+ {
+ reportReadHandler = new ReportReadHandler();
+ return reportReadHandler;
+ }
+
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ if (reportReadHandler != null)
+ {
+ body.addNode(reportReadHandler.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return body;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/DocumentContentReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/DocumentContentReadHandler.java
new file mode 100644
index 000000000..65a48252e
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/DocumentContentReadHandler.java
@@ -0,0 +1,225 @@
+/*
+ * 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.parser.office;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.OfficeDocument;
+import org.libreoffice.report.pentaho.model.OfficeStylesCollection;
+import org.libreoffice.report.pentaho.parser.style.OfficeStylesReadHandler;
+
+import java.util.logging.Logger;
+
+import org.jfree.report.JFreeReport;
+
+import org.pentaho.reporting.libraries.resourceloader.Resource;
+import org.pentaho.reporting.libraries.resourceloader.ResourceException;
+import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
+import org.pentaho.reporting.libraries.resourceloader.ResourceKeyCreationException;
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * This is the root handler for the document context. The
+ * 'office:document-context' element is encountered, if the document is split
+ * into separate files.
+ *
+ * <p>Alternatively, there is the option to keep everything in one file. The root
+ * element for that format is 'office:document'.</p>
+ */
+public class DocumentContentReadHandler extends AbstractXmlReadHandler
+{
+
+ private static final Logger LOGGER = Logger.getLogger(DocumentContentReadHandler.class.getName());
+ private OfficeDocument report;
+ private FontFaceDeclsReadHandler fontFaceReadHandler;
+ private BodyReadHandler bodyReadHandler;
+ private OfficeStylesCollection officeStylesCollection;
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs)
+ throws SAXException
+ {
+ super.startParsing(attrs);
+ // parse the external 'styles.xml' if it exists
+ // parse the external 'meta.xml' if it exists
+ // parse the external 'settings.xml' if it exists
+ this.report = parseContentXml();
+ this.report.setVirtual(true);
+ this.report.setType("document-content");
+ this.report.setNamespace(OfficeNamespaces.OFFICE_NS);
+ this.report.setVirtual(true);
+ this.officeStylesCollection = parseStylesXml();
+ }
+
+ private OfficeStylesCollection parseStylesXml()
+ {
+ final ResourceKey contextKey = getRootHandler().getContext();
+ final ResourceManager resourceManager = getRootHandler().getResourceManager();
+
+ try
+ {
+ final ResourceKey key =
+ resourceManager.deriveKey(contextKey, "styles.xml");
+ final Resource resource =
+ resourceManager.create(key, contextKey, OfficeStylesCollection.class);
+ final OfficeStylesCollection styles =
+ (OfficeStylesCollection) resource.getResource();
+ if (styles != null)
+ {
+ return styles;
+ }
+ }
+ catch (ResourceKeyCreationException e)
+ {
+ // ignore ..
+ LOGGER.config("Failed to create resource-key for 'styles.xml'. Ignoring: " + e);
+ }
+ catch (ResourceException e)
+ {
+ // ignore ..
+ LOGGER.config("Failed to parse resource for 'styles.xml'. Ignoring: " + e);
+ }
+
+ return new OfficeStylesCollection();
+ }
+
+ private OfficeDocument parseContentXml()
+ {
+ // Check whether this is a content.xml.
+ if (!OfficeNamespaces.OFFICE_NS.equals(getUri()) || "document-content".equals(getTagName()))
+ {
+ return new OfficeDocument();
+ }
+
+ // we may have to parse an existing content.xml.
+ final ResourceKey contextKey = getRootHandler().getContext();
+ final ResourceManager resourceManager = getRootHandler().getResourceManager();
+ try
+ {
+ final ResourceKey key =
+ resourceManager.deriveKey(contextKey, "content.xml");
+ final Resource resource =
+ resourceManager.create(key, contextKey, JFreeReport.class);
+ final OfficeDocument doc = (OfficeDocument) resource.getResource();
+ if (doc != null)
+ {
+ return doc;
+ }
+ }
+ catch (ResourceKeyCreationException e)
+ {
+ // ignore ..
+ LOGGER.config("Failed to create resource-key for 'content.xml'. Ignoring.");
+ }
+ catch (ResourceException e)
+ {
+ // ignore ..
+ LOGGER.config("Failed to parse resource for 'content.xml'. Ignoring.");
+ }
+ return new OfficeDocument();
+
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.OFFICE_NS.equals(uri))
+ {
+ if ("font-face-decls".equals(tagName))
+ {
+ if (fontFaceReadHandler == null)
+ {
+ fontFaceReadHandler = new FontFaceDeclsReadHandler(officeStylesCollection.getFontFaceDecls());
+ }
+ return fontFaceReadHandler;
+ }
+ else if ("automatic-styles".equals(tagName))
+ {
+ return new OfficeStylesReadHandler(officeStylesCollection.getAutomaticStyles());
+ }
+ else if ("styles".equals(tagName))
+ {
+ return new OfficeStylesReadHandler(officeStylesCollection.getCommonStyles());
+ }
+ else if ("master-styles".equals(tagName))
+ {
+ return new MasterStylesReadHandler(officeStylesCollection.getMasterStyles());
+ }
+ else if ("body".equals(tagName))
+ {
+ bodyReadHandler = new BodyReadHandler();
+ return bodyReadHandler;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing()
+ throws SAXException
+ {
+ // The office-document is the only node of the report. It allows us to
+ // switch the layout-processing implementation later on.
+
+ report.setStylesCollection(officeStylesCollection);
+
+ if (bodyReadHandler != null)
+ {
+ report.addNode(bodyReadHandler.getElement());
+ }
+ }
+
+ /**
+ * Returns the object for this element or null, if this element does not
+ * create an object.
+ *
+ * @return the object.
+ */
+ public Object getObject()
+ throws SAXException
+ {
+ return report;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/DocumentStylesReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/DocumentStylesReadHandler.java
new file mode 100644
index 000000000..70320ce5e
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/DocumentStylesReadHandler.java
@@ -0,0 +1,98 @@
+/*
+ * 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.parser.office;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.OfficeStylesCollection;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.style.OfficeStylesReadHandler;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * The root parser for a 'styles.xml' document. This generates the global
+ * (or common) style collection. These styles contain the named common styles
+ * and the page layouts.
+ *
+ * @since 08.03.2007
+ */
+public class DocumentStylesReadHandler extends ElementReadHandler
+{
+
+ private final OfficeStylesCollection officeStylesCollection;
+ private FontFaceDeclsReadHandler fontFaceReadHandler;
+
+ public DocumentStylesReadHandler()
+ {
+ officeStylesCollection = new OfficeStylesCollection();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (!OfficeNamespaces.OFFICE_NS.equals(uri))
+ {
+ return null;
+ }
+
+ if ("font-face-decls".equals(tagName))
+ {
+ if (fontFaceReadHandler == null)
+ {
+ fontFaceReadHandler = new FontFaceDeclsReadHandler(officeStylesCollection.getFontFaceDecls());
+ }
+ return fontFaceReadHandler;
+ }
+ else if ("automatic-styles".equals(tagName))
+ {
+ return new OfficeStylesReadHandler(officeStylesCollection.getAutomaticStyles());
+ }
+ else if ("styles".equals(tagName))
+ {
+ return new OfficeStylesReadHandler(officeStylesCollection.getCommonStyles());
+ }
+ else if ("master-styles".equals(tagName))
+ {
+ return new MasterStylesReadHandler(officeStylesCollection.getMasterStyles());
+ }
+ return null;
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return officeStylesCollection;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/FontFaceDeclsReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/FontFaceDeclsReadHandler.java
new file mode 100644
index 000000000..83c5b1f6a
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/FontFaceDeclsReadHandler.java
@@ -0,0 +1,105 @@
+/*
+ * 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.parser.office;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.FontFaceDeclsSection;
+import org.libreoffice.report.pentaho.model.FontFaceElement;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.style.FontFaceReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Reads the font-face declarations section. This one can only contain
+ * font-face elements.
+ *
+ * @since 13.03.2007
+ */
+public class FontFaceDeclsReadHandler extends ElementReadHandler
+{
+
+ private final FontFaceDeclsSection fontFaceDecls;
+ private final List<FontFaceReadHandler> fontFaceReadHandlers;
+
+ public FontFaceDeclsReadHandler(final FontFaceDeclsSection fontFaceDecls)
+ {
+ this.fontFaceDecls = fontFaceDecls;
+ this.fontFaceReadHandlers = new ArrayList<FontFaceReadHandler>();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (!OfficeNamespaces.STYLE_NS.equals(uri))
+ {
+ return null;
+ }
+
+ if ("font-face".equals(tagName))
+ {
+ final FontFaceReadHandler frh = new FontFaceReadHandler();
+ fontFaceReadHandlers.add(frh);
+ return frh;
+ }
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing()
+ throws SAXException
+ {
+ for (int i = 0; i < fontFaceReadHandlers.size(); i++)
+ {
+ final FontFaceReadHandler handler = fontFaceReadHandlers.get(i);
+ fontFaceDecls.addFontFace((FontFaceElement) handler.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return fontFaceDecls;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/MasterStylesReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/MasterStylesReadHandler.java
new file mode 100644
index 000000000..f86cae8e5
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/office/MasterStylesReadHandler.java
@@ -0,0 +1,111 @@
+/*
+ * 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.parser.office;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.OfficeMasterStyles;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.style.MasterPageReadHandler;
+import org.libreoffice.report.pentaho.parser.style.StyleDefinitionReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Todo: Document me!
+ *
+ * @since 13.03.2007
+ */
+public class MasterStylesReadHandler extends ElementReadHandler
+{
+
+ private final OfficeMasterStyles masterStyles;
+ private final List<ElementReadHandler> otherHandlers;
+ private final List<MasterPageReadHandler> masterPageHandlers;
+
+ public MasterStylesReadHandler(final OfficeMasterStyles masterStyles)
+ {
+ this.masterStyles = masterStyles;
+ this.masterPageHandlers = new ArrayList<MasterPageReadHandler>();
+ this.otherHandlers = new ArrayList<ElementReadHandler>();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.STYLE_NS.equals(uri) && "master-page".equals(tagName))
+ {
+ final MasterPageReadHandler mrh = new MasterPageReadHandler();
+ masterPageHandlers.add(mrh);
+ return mrh;
+ }
+
+ final StyleDefinitionReadHandler readHandler =
+ new StyleDefinitionReadHandler();
+ otherHandlers.add(readHandler);
+ return readHandler;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing()
+ throws SAXException
+ {
+ for (int i = 0; i < otherHandlers.size(); i++)
+ {
+ final ElementReadHandler handler = otherHandlers.get(i);
+ masterStyles.getOtherNodes().addNode(handler.getElement());
+ }
+
+ for (int i = 0; i < masterPageHandlers.size(); i++)
+ {
+ final MasterPageReadHandler handler = masterPageHandlers.get(i);
+ masterStyles.addMasterPage(handler.getMasterPage());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return masterStyles;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ConditionalPrintExpressionReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ConditionalPrintExpressionReadHandler.java
new file mode 100644
index 000000000..cb70d4436
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ConditionalPrintExpressionReadHandler.java
@@ -0,0 +1,72 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.expressions.FormulaFunction;
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * Handles the 'report:conditional-print-expression' element that can appear
+ * in all report elements and all root-level sections.
+ *
+ * @since 02.03.2007
+ */
+public class ConditionalPrintExpressionReadHandler
+ extends AbstractXmlReadHandler
+{
+
+ private final Element element;
+
+ public ConditionalPrintExpressionReadHandler(final Element element)
+ {
+ this.element = element;
+ }
+
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ super.startParsing(attrs);
+ final String formula = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "formula");
+ if (formula != null)
+ {
+ final FormulaFunction valueExpression = new FormulaFunction();
+ valueExpression.setFormula(formula);
+ element.setDisplayCondition(valueExpression);
+ }
+
+ }
+
+ /**
+ * Returns the object for this element or null, if this element does not
+ * create an object.
+ *
+ * @return the object.
+ */
+ public Object getObject()
+ throws SAXException
+ {
+ return element;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/DetailRootTableReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/DetailRootTableReadHandler.java
new file mode 100644
index 000000000..2a0677065
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/DetailRootTableReadHandler.java
@@ -0,0 +1,29 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.pentaho.model.OfficeDetailSection;
+
+public class DetailRootTableReadHandler extends RootTableReadHandler
+{
+
+ public DetailRootTableReadHandler()
+ {
+ super(new OfficeDetailSection());
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FixedContentReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FixedContentReadHandler.java
new file mode 100644
index 000000000..9896c7a93
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FixedContentReadHandler.java
@@ -0,0 +1,90 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.FixedTextElement;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.text.TextContentReadHandler;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.IgnoreAnyChildReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * Creation-Date: 01.10.2006, 18:48:11
+ *
+ */
+public class FixedContentReadHandler extends ElementReadHandler
+{
+
+ private final FixedTextElement element;
+
+ public FixedContentReadHandler()
+ {
+ element = new FixedTextElement();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.TEXT_NS.equals(uri) && OfficeToken.P.equals(tagName))
+ {
+ // expect a paragraph (which will be ignored; it is a structural
+ // component that needs not to be printed at all.
+ return new TextContentReadHandler(element.getContent());
+ }
+
+ if (OfficeNamespaces.OOREPORT_NS.equals(uri))
+ {
+ // expect a report control. The control will modify the current
+ // element (as we do not separate the elements that strictly ..)
+ if ("report-control".equals(tagName))
+ {
+ return new IgnoreAnyChildReadHandler();
+ }
+ if ("report-element".equals(tagName))
+ {
+ return new ReportElementReadHandler(element);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FormatConditionReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FormatConditionReadHandler.java
new file mode 100644
index 000000000..8c3cb6ca9
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FormatConditionReadHandler.java
@@ -0,0 +1,91 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.FormatCondition;
+import org.libreoffice.report.pentaho.model.ReportElement;
+
+import org.jfree.report.expressions.FormulaExpression;
+
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.ParseException;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * I'm quite sure I should parse something here. But what?
+ *
+ */
+public class FormatConditionReadHandler extends AbstractXmlReadHandler
+{
+
+ private final ReportElement element;
+
+ public FormatConditionReadHandler(final ReportElement element)
+ {
+ if (element == null)
+ {
+ throw new NullPointerException();
+ }
+ this.element = element;
+ }
+
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ super.startParsing(attrs);
+
+
+ final String formula =
+ attrs.getValue(OfficeNamespaces.OOREPORT_NS, "formula");
+ if (formula == null)
+ {
+ throw new ParseException("Required attribute 'formula' is missing.", getLocator());
+ }
+ final String stylename =
+ attrs.getValue(OfficeNamespaces.OOREPORT_NS, OfficeToken.STYLE_NAME);
+ if (stylename == null)
+ {
+ throw new ParseException("Required attribute 'style-name' is missing.", getLocator());
+ }
+ final FormulaExpression valueExpression = new FormulaExpression();
+ valueExpression.setFormula(formula);
+
+ final String enabledText = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "enabled");
+ final boolean enabled = (enabledText == null || OfficeToken.TRUE.equals(enabledText));
+ final FormatCondition formatCondition =
+ new FormatCondition(valueExpression, stylename, enabled);
+ element.addFormatCondition(formatCondition);
+
+ }
+
+ /**
+ * Returns the object for this element or null, if this element does not
+ * create an object.
+ *
+ * @return the object.
+ */
+ public Object getObject()
+ throws SAXException
+ {
+ return element;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FormattedTextReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FormattedTextReadHandler.java
new file mode 100644
index 000000000..7810f972e
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FormattedTextReadHandler.java
@@ -0,0 +1,111 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.FormattedTextElement;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import org.jfree.report.expressions.FormulaExpression;
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.IgnoreAnyChildReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * Creation-Date: 01.10.2006, 19:06:45
+ *
+ */
+public class FormattedTextReadHandler extends ElementReadHandler
+{
+
+ private final FormattedTextElement element;
+
+ public FormattedTextReadHandler()
+ {
+ element = new FormattedTextElement();
+ }
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ super.startParsing(attrs);
+
+ final String formula = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "formula");
+ if (formula != null)
+ {
+ final FormulaExpression valueExpression = new FormulaExpression();
+ valueExpression.setFormula(formula);
+ element.setValueExpression(valueExpression);
+ }
+
+ // * Print-Repeated-Values
+ // * Print-In-First-New-Section
+ // * Print-When-Group-Change
+
+ // * Print-When-Section-Overflows
+ // That property cannot be evaluated yet, as this would require us to
+ // have a clue about pagebreaking. We don't have that - not yet and never
+ // in the future, as pagebreaks are computed by OpenOffice instead
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.OOREPORT_NS.equals(uri))
+ {
+ // expect a report control. The control will modify the current
+ // element (as we do not separate the elements that strictly...)
+ if ("report-control".equals(tagName))
+ {
+ return new IgnoreAnyChildReadHandler();
+ }
+ if ("report-element".equals(tagName))
+ {
+ return new ReportElementReadHandler(element);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FunctionReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FunctionReadHandler.java
new file mode 100644
index 000000000..14def5e75
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/FunctionReadHandler.java
@@ -0,0 +1,103 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.jfree.report.expressions.Expression;
+import org.jfree.report.expressions.FormulaExpression;
+import org.jfree.report.expressions.FormulaFunction;
+
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.ParseException;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * Parses a named expression. These expressions are encountered on reports and
+ * groups and compute global values. Expressions must have a unique name.
+ *
+ */
+public class FunctionReadHandler extends AbstractXmlReadHandler
+{
+
+ private Expression expression;
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs)
+ throws SAXException
+ {
+ final String formula = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "formula");
+ if (formula == null)
+ {
+ throw new ParseException("Required attribute 'formula' is missing", getLocator());
+ }
+
+ final String name = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "name");
+ if (name == null)
+ {
+ throw new ParseException("Required attribute 'name' is missing", getLocator());
+ }
+ final String initialFormula = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "initial-formula");
+ final String deepTraversing = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "deep-traversing");
+
+ if (initialFormula != null)
+ {
+ final FormulaFunction function = new FormulaFunction();
+ function.setInitial(initialFormula);
+ function.setFormula(formula);
+ this.expression = function;
+ }
+ else
+ {
+ final FormulaExpression expression = new FormulaExpression();
+ expression.setFormula(formula);
+ this.expression = expression;
+ }
+
+ expression.setName(name);
+ expression.setDeepTraversing(OfficeToken.TRUE.equals(deepTraversing));
+ final String preEvaluated = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "pre-evaluated");
+ expression.setPrecompute(OfficeToken.TRUE.equals(preEvaluated));
+ }
+
+ /**
+ * Returns the object for this element or null, if this element does not
+ * create an object.
+ *
+ * @return the object.
+ */
+ public Object getObject()
+ throws SAXException
+ {
+ return getExpression();
+ }
+
+ public Expression getExpression()
+ {
+ return expression;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/GroupReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/GroupReadHandler.java
new file mode 100644
index 000000000..642c6ded9
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/GroupReadHandler.java
@@ -0,0 +1,181 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package org.libreoffice.report.pentaho.parser.rpt;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.OfficeGroup;
+import org.libreoffice.report.pentaho.model.OfficeGroupInstanceSection;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.JFreeReportInfo;
+import org.jfree.report.expressions.FormulaExpression;
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+public class GroupReadHandler extends ElementReadHandler
+{
+
+ private GroupSectionReadHandler groupHeader;
+ private GroupSectionReadHandler groupFooter;
+ private GroupReadHandler childGroup;
+ private RootTableReadHandler detailSection;
+ private final OfficeGroup group;
+ private final OfficeGroupInstanceSection groupInstanceSection;
+ private final List<FunctionReadHandler> functionHandlers;
+ private final ReportReadHandler rh;
+
+ public GroupReadHandler(final ReportReadHandler _rh)
+ {
+ rh = _rh;
+ group = new OfficeGroup();
+ groupInstanceSection = new OfficeGroupInstanceSection();
+ groupInstanceSection.setNamespace(JFreeReportInfo.REPORT_NAMESPACE);
+ groupInstanceSection.setType("group-instance");
+ group.addNode(groupInstanceSection);
+ functionHandlers = new ArrayList<FunctionReadHandler>();
+ }
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ super.startParsing(attrs);
+
+ final String groupExpr = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "group-expression");
+ if (groupExpr != null && !"".equals(groupExpr))
+ {
+ final FormulaExpression function = new FormulaExpression();
+ function.setFormula(groupExpr);
+ groupInstanceSection.setGroupingExpression(function);
+ }
+ final String sortExpr = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "sort-expression");
+ if (sortExpr != null && !"".equals(sortExpr))
+ {
+ groupInstanceSection.setSortingExpression(sortExpr);
+ }
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (!OfficeNamespaces.OOREPORT_NS.equals(uri))
+ {
+ return null;
+ }
+ if ("function".equals(tagName))
+ {
+ final FunctionReadHandler erh = new FunctionReadHandler();
+ functionHandlers.add(erh);
+ return erh;
+ }
+ if ("group-header".equals(tagName))
+ {
+ groupHeader = new GroupSectionReadHandler();
+ return groupHeader;
+ }
+ if ("group".equals(tagName))
+ {
+ childGroup = new GroupReadHandler(rh);
+ return childGroup;
+ }
+ if ("detail".equals(tagName))
+ {
+ detailSection = new DetailRootTableReadHandler();
+ rh.setDetail(detailSection);
+ return detailSection;
+ }
+ if ("group-footer".equals(tagName))
+ {
+ ((Element) ((Section) rh.getDetail().getElement()).getNode(0)).setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "has-group-footer", OfficeToken.TRUE);
+ groupFooter = new GroupSectionReadHandler();
+ return groupFooter;
+ }
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < functionHandlers.size(); i++)
+ {
+ final FunctionReadHandler handler = functionHandlers.get(i);
+ groupInstanceSection.addExpression(handler.getExpression());
+ }
+
+ if (groupHeader != null)
+ {
+ groupInstanceSection.addNode(groupHeader.getElement());
+ }
+
+ final Section groupBody = new Section();
+ groupBody.setNamespace(JFreeReportInfo.REPORT_NAMESPACE);
+ groupBody.setType("group-body");
+ groupInstanceSection.addNode(groupBody);
+ // XOR: Either the detail or the group section can be set ..
+ if (detailSection != null)
+ {
+ groupBody.addNode(detailSection.getElement());
+ }
+ else if (childGroup != null)
+ {
+ groupBody.addNode(childGroup.getElement());
+ }
+
+ if (groupFooter != null)
+ {
+ groupInstanceSection.addNode(groupFooter.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return group;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/GroupSectionReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/GroupSectionReadHandler.java
new file mode 100644
index 000000000..461cf6784
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/GroupSectionReadHandler.java
@@ -0,0 +1,29 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.pentaho.model.OfficeGroupSection;
+
+public class GroupSectionReadHandler extends RootTableReadHandler
+{
+
+ public GroupSectionReadHandler()
+ {
+ super(new OfficeGroupSection());
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ImageReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ImageReadHandler.java
new file mode 100644
index 000000000..86dd423d5
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ImageReadHandler.java
@@ -0,0 +1,134 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.ImageElement;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.xlink.XLinkReadHandler;
+
+import org.jfree.report.expressions.FormulaExpression;
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.IgnoreAnyChildReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * Deals with Image-content. There are two ways to specify the image;
+ * as formula or as static image data.
+ *
+ */
+public class ImageReadHandler extends ElementReadHandler
+{
+
+ private final ImageElement contentElement;
+ private XLinkReadHandler xLinkReadHandler;
+
+ public ImageReadHandler()
+ {
+ contentElement = new ImageElement();
+ }
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ super.startParsing(attrs);
+ final String formula = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "formula");
+ if (formula != null && formula.length() != 0)
+ {
+ // now, the evaluated content ends up in the 'content' attribute of the
+ // element.
+ final FormulaExpression valueExpression = new FormulaExpression();
+ valueExpression.setFormula(formula);
+ contentElement.setFormula(valueExpression);
+ }
+
+ contentElement.setNamespace(OfficeNamespaces.FORM_NS);
+ contentElement.setType(OfficeToken.IMAGE);
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.DRAWING_NS.equals(uri) && OfficeToken.IMAGE_DATA.equals(tagName))
+ {
+ xLinkReadHandler = new XLinkReadHandler();
+ return xLinkReadHandler;
+ }
+
+ if (OfficeNamespaces.OOREPORT_NS.equals(uri))
+ {
+ // expect a report control. The control will modify the current
+ // element (as we do not separate the elements that strictly...)
+ if ("report-control".equals(tagName))
+ {
+ return new IgnoreAnyChildReadHandler();
+ }
+ if ("report-element".equals(tagName))
+ {
+ return new ReportElementReadHandler(contentElement);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ // if we have static content (as well as or only), that one goes into the
+ // alternate-content attribute right now. It is part of the output target
+ // and style rules to deal with them properly.
+ if (xLinkReadHandler != null)
+ {
+ contentElement.setAttribute(OfficeNamespaces.OOREPORT_NS,
+ "alternate-content", xLinkReadHandler.getUri());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return contentElement;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/MasterDetailReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/MasterDetailReadHandler.java
new file mode 100644
index 000000000..da1eff8b7
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/MasterDetailReadHandler.java
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package org.libreoffice.report.pentaho.parser.rpt;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.ObjectOleElement;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class MasterDetailReadHandler extends ElementReadHandler
+{
+
+ private final ObjectOleElement element;
+ private final boolean parseMasterDetail;
+
+ public MasterDetailReadHandler(final ObjectOleElement element)
+ {
+ this.element = element;
+ parseMasterDetail = false;
+ }
+
+ private MasterDetailReadHandler(final ObjectOleElement element, final boolean parseMasterDetail)
+ {
+ this.element = element;
+ this.parseMasterDetail = parseMasterDetail;
+ }
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ super.startParsing(attrs);
+ if (parseMasterDetail)
+ {
+ final String master = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "master");
+ if (master != null && master.length() > 0)
+ {
+ final String detail = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "detail");
+ element.addMasterDetailFields(master, detail);
+ }
+ }
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.OOREPORT_NS.equals(uri) && "master-detail-field".equals(tagName))
+ {
+ // expect a report control. The control will modify the current
+ // element (as we do not separate the elements that strictly...)
+ return new MasterDetailReadHandler(element, true);
+ }
+
+ return null;
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ReportElementReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ReportElementReadHandler.java
new file mode 100644
index 000000000..6e032aaaa
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ReportElementReadHandler.java
@@ -0,0 +1,103 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.ReportElement;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.IgnoreAnyChildReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class ReportElementReadHandler extends ElementReadHandler
+{
+
+ private final ReportElement element;
+
+ public ReportElementReadHandler(final ReportElement element)
+ {
+ if (element == null)
+ {
+ throw new NullPointerException();
+ }
+
+ this.element = element;
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return element;
+ }
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs)
+ throws SAXException
+ {
+ super.startParsing(attrs);
+ final String printWhenGroupChange = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "print-when-group-change");
+ element.setPrintWhenGroupChange(OfficeToken.TRUE.equals(printWhenGroupChange));
+ final String printRepeatingValues = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "print-repeated-values");
+ element.setPrintRepeatedValues(printRepeatingValues == null || OfficeToken.TRUE.equals(printRepeatingValues));
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (!OfficeNamespaces.OOREPORT_NS.equals(uri))
+ {
+ return null;
+ }
+ if ("conditional-print-expression".equals(tagName))
+ {
+ return new ConditionalPrintExpressionReadHandler(element);
+ }
+ if ("format-condition".equals(tagName))
+ {
+ return new FormatConditionReadHandler(element);
+ }
+ if ("report-component".equals(tagName))
+ {
+ return new IgnoreAnyChildReadHandler();
+ }
+ return null;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ReportReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ReportReadHandler.java
new file mode 100644
index 000000000..55b413b5e
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/ReportReadHandler.java
@@ -0,0 +1,235 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.OfficeReport;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.chart.ChartReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.JFreeReportInfo;
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+public class ReportReadHandler extends ElementReadHandler
+{
+
+ private RootTableReadHandler pageHeader;
+ private RootTableReadHandler pageFooter;
+ private RootTableReadHandler reportHeader;
+ private RootTableReadHandler reportFooter;
+ private RootTableReadHandler detail;
+ private GroupReadHandler groups;
+ private final OfficeReport rootSection;
+ private final List<FunctionReadHandler> functionHandlers;
+ private final List<ElementReadHandler> preBodyHandlers;
+ private final List<ElementReadHandler> postBodyHandlers;
+ private boolean pre = true;
+
+ public ReportReadHandler()
+ {
+ rootSection = new OfficeReport();
+ rootSection.setAttribute(JFreeReportInfo.REPORT_NAMESPACE, "simple-report-structure", Boolean.TRUE);
+ functionHandlers = new ArrayList<FunctionReadHandler>();
+ preBodyHandlers = new ArrayList<ElementReadHandler>();
+ postBodyHandlers = new ArrayList<ElementReadHandler>();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ final XmlReadHandler erh;
+ if (OfficeNamespaces.CHART_NS.equals(uri))
+ {
+ ChartReadHandler crh = new ChartReadHandler(this);
+ if (pre)
+ {
+ preBodyHandlers.add(crh);
+ }
+ else
+ {
+ postBodyHandlers.add(crh);
+ }
+ erh = crh;
+ }
+ else if (OfficeNamespaces.OOREPORT_NS.equals(uri))
+ {
+ if ("function".equals(tagName))
+ {
+ FunctionReadHandler frh = new FunctionReadHandler();
+ functionHandlers.add(frh);
+ erh = frh;
+ }
+ else if ("page-header".equals(tagName))
+ {
+ pageHeader = new RootTableReadHandler();
+ erh = pageHeader;
+ }
+ else if ("report-header".equals(tagName))
+ {
+ reportHeader = new RootTableReadHandler();
+ erh = reportHeader;
+ }
+ else if ("report-footer".equals(tagName))
+ {
+ reportFooter = new RootTableReadHandler();
+ erh = reportFooter;
+ }
+ else if ("page-footer".equals(tagName))
+ {
+ pageFooter = new RootTableReadHandler();
+ erh = pageFooter;
+ }
+ else if ("detail".equals(tagName))
+ {
+ pre = false;
+ detail = new DetailRootTableReadHandler();
+ erh = detail;
+ }
+ else if ("group".equals(tagName))
+ {
+ groups = new GroupReadHandler(this);
+ erh = groups;
+ }
+ else
+ {
+ erh = null;
+ }
+ }
+ else
+ {
+ erh = null;
+ }
+ return erh;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ if (pageHeader != null)
+ {
+ rootSection.setPageHeader(pageHeader.getElement());
+ }
+ if (pageFooter != null)
+ {
+ rootSection.setPageFooter(pageFooter.getElement());
+ }
+ if (reportHeader != null)
+ {
+ rootSection.setReportHeader(reportHeader.getElement());
+ }
+
+ final Section preBody = createSection("report-pre-body", preBodyHandlers);
+ if (preBody != null)
+ {
+ rootSection.setPreBodySection(preBody);
+ }
+
+ final Section groupBody = new Section();
+ groupBody.setNamespace(JFreeReportInfo.REPORT_NAMESPACE);
+ groupBody.setType("report-body");
+ rootSection.setBodySection(groupBody);
+
+ // XOR: Either the detail or the group section can be set ..
+ if (groups != null)
+ {
+ groupBody.addNode(groups.getElement());
+ }
+ else if (detail != null)
+ {
+ groupBody.addNode(detail.getElement());
+ }
+
+ final Section postBody = createSection("report-post-body", postBodyHandlers);
+ if (postBody != null)
+ {
+ rootSection.setPostBodySection(postBody);
+ }
+
+ if (reportFooter != null)
+ {
+ rootSection.setReportFooter(reportFooter.getElement());
+ }
+
+ for (int i = 0; i < functionHandlers.size(); i++)
+ {
+ final FunctionReadHandler handler = functionHandlers.get(i);
+ rootSection.addExpression(handler.getExpression());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return rootSection;
+ }
+
+ private final Section createSection(final String name, final List<ElementReadHandler> handler)
+ {
+ if (!handler.isEmpty())
+ {
+ final Section section = new Section();
+ section.setNamespace(JFreeReportInfo.REPORT_NAMESPACE);
+ section.setType(name);
+
+ for (int i = 0; i < handler.size(); i++)
+ {
+ final ElementReadHandler erh = handler.get(i);
+ section.addNode(erh.getElement());
+ }
+ return section;
+ }
+ return null;
+ }
+
+ public void setDetail(final RootTableReadHandler detail)
+ {
+ this.detail = detail;
+ }
+
+ public final RootTableReadHandler getDetail()
+ {
+ return detail;
+ }
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/RootTableReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/RootTableReadHandler.java
new file mode 100644
index 000000000..c7d2aaf37
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/RootTableReadHandler.java
@@ -0,0 +1,99 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package org.libreoffice.report.pentaho.parser.rpt;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.table.TableReadHandler;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class RootTableReadHandler extends ElementReadHandler
+{
+
+ private TableReadHandler sectionTableReadHandler;
+ private final Section section;
+
+ public RootTableReadHandler()
+ {
+ section = new Section();
+ }
+
+ protected RootTableReadHandler(final Section section)
+ {
+ if (section == null)
+ {
+ throw new NullPointerException();
+ }
+ this.section = section;
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.TABLE_NS.equals(uri) && "table".equals(tagName))
+ {
+ sectionTableReadHandler = new TableReadHandler();
+ return sectionTableReadHandler;
+ }
+ if (OfficeNamespaces.OOREPORT_NS.equals(uri) && "conditional-print-expression".equals(tagName))
+ {
+ return new ConditionalPrintExpressionReadHandler(section);
+ }
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing()
+ throws SAXException
+ {
+ if (sectionTableReadHandler != null)
+ {
+ section.addNode(sectionTableReadHandler.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return section;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/SubDocumentReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/SubDocumentReadHandler.java
new file mode 100644
index 000000000..6706408be
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/rpt/SubDocumentReadHandler.java
@@ -0,0 +1,121 @@
+/*
+ * 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.parser.rpt;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.ObjectOleElement;
+import org.libreoffice.report.pentaho.parser.draw.ObjectOleReadHandler;
+import org.libreoffice.report.pentaho.parser.text.NoCDATATextContentReadHandler;
+
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.IgnoreAnyChildReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class SubDocumentReadHandler extends NoCDATATextContentReadHandler
+{
+
+ private final ObjectOleElement element;
+ private boolean ignore = false;
+
+ private SubDocumentReadHandler(final Section section, final ObjectOleElement element)
+ {
+ super(section);
+ this.element = element;
+ }
+
+ public SubDocumentReadHandler(final Section section)
+ {
+ this(section, new ObjectOleElement());
+ ignore = true;
+ }
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ if (!ignore)
+ {
+ super.startParsing(attrs);
+ }
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.OOREPORT_NS.equals(uri))
+ {
+ // expect a report control. The control will modify the current
+ // element (as we do not separate the elements that strictly...)
+ if ("report-control".equals(tagName))
+ {
+ return new IgnoreAnyChildReadHandler();
+ }
+ if ("report-element".equals(tagName))
+ {
+ return new ReportElementReadHandler(element);
+ }
+ if ("master-detail-fields".equals(tagName))
+ {
+ return new MasterDetailReadHandler(element);
+ }
+ }
+ if (OfficeNamespaces.DRAWING_NS.equals(uri))
+ {
+ final XmlReadHandler readHandler;
+ if (OfficeToken.OBJECT_OLE.equals(tagName))
+ {
+ readHandler = new ObjectOleReadHandler(element);
+ }
+ else if ("frame".equals(tagName))
+ {
+ readHandler = new SubDocumentReadHandler(new Section(), element);
+ }
+ else
+ {
+ readHandler = null;
+ }
+ if (readHandler != null)
+ {
+ getChildren().add(readHandler);
+ return readHandler;
+ }
+ }
+ return super.getHandlerForChild(uri, tagName, atts);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/FontFaceReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/FontFaceReadHandler.java
new file mode 100644
index 000000000..6430cf664
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/FontFaceReadHandler.java
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+package org.libreoffice.report.pentaho.parser.style;
+
+import org.libreoffice.report.pentaho.model.FontFaceElement;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import org.jfree.report.structure.Element;
+
+/**
+ * Reads a single font-face declaration. This is equal to the @font rule of
+ * the CSS standard. We do not interpret the attributes of the element in
+ * any way yet.
+ *
+ * @since 13.03.2007
+ */
+public class FontFaceReadHandler extends ElementReadHandler
+{
+
+ private final FontFaceElement fontFaceElement;
+
+ public FontFaceReadHandler()
+ {
+ this.fontFaceElement = new FontFaceElement();
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return fontFaceElement;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/MasterPageReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/MasterPageReadHandler.java
new file mode 100644
index 000000000..82438add7
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/MasterPageReadHandler.java
@@ -0,0 +1,98 @@
+/*
+ * 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.parser.style;
+
+import org.libreoffice.report.pentaho.model.OfficeMasterPage;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Todo: Document me!
+ *
+ * @since 13.03.2007
+ */
+public class MasterPageReadHandler extends ElementReadHandler
+{
+
+ private final OfficeMasterPage masterPage;
+ private final List<ElementReadHandler> otherHandlers;
+
+ public MasterPageReadHandler()
+ {
+ masterPage = new OfficeMasterPage();
+ this.otherHandlers = new ArrayList<ElementReadHandler>();
+ }
+
+ public OfficeMasterPage getMasterPage()
+ {
+ return masterPage;
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ final StyleDefinitionReadHandler readHandler =
+ new StyleDefinitionReadHandler();
+ otherHandlers.add(readHandler);
+ return readHandler;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing()
+ throws SAXException
+ {
+ for (int i = 0; i < otherHandlers.size(); i++)
+ {
+ final ElementReadHandler handler = otherHandlers.get(i);
+ masterPage.addNode(handler.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return masterPage;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/OfficeStyleReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/OfficeStyleReadHandler.java
new file mode 100644
index 000000000..0c4a7d20c
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/OfficeStyleReadHandler.java
@@ -0,0 +1,96 @@
+/*
+ * 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.parser.style;
+
+import org.libreoffice.report.pentaho.model.OfficeStyle;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * This class reads a single style rule. The resulting 'office-style' element
+ * is added to an 'office-styles' set.
+ */
+public class OfficeStyleReadHandler extends ElementReadHandler
+{
+
+ private final OfficeStyle officeStyle;
+ private final List<ElementReadHandler> children;
+
+ public OfficeStyleReadHandler()
+ {
+ this.officeStyle = new OfficeStyle();
+ this.children = new ArrayList<ElementReadHandler>();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ final StyleDefinitionReadHandler readHandler =
+ new StyleDefinitionReadHandler();
+ children.add(readHandler);
+ return readHandler;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < children.size(); i++)
+ {
+ final ElementReadHandler handler = children.get(i);
+ officeStyle.addNode(handler.getElement());
+ }
+ }
+
+ public OfficeStyle getOfficeStyle()
+ {
+ return officeStyle;
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return officeStyle;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/OfficeStylesReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/OfficeStylesReadHandler.java
new file mode 100644
index 000000000..4afd86768
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/OfficeStylesReadHandler.java
@@ -0,0 +1,133 @@
+/*
+ * 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.parser.style;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.OfficeStyles;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.data.DataStyleReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.modules.factories.report.flow.SectionReadHandler;
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class OfficeStylesReadHandler extends ElementReadHandler
+{
+
+ private final List<OfficeStyleReadHandler> textStyleChildren;
+ private final List<DataStyleReadHandler> dataStyleChildren;
+ private final List<SectionReadHandler> otherStyleChildren;
+ private final List<PageLayoutReadHandler> pageLayoutChildren;
+ private final OfficeStyles officeStyles;
+
+ public OfficeStylesReadHandler(final OfficeStyles officeStyles)
+ {
+ this.officeStyles = officeStyles;
+ this.pageLayoutChildren = new ArrayList<PageLayoutReadHandler>();
+ this.dataStyleChildren = new ArrayList<DataStyleReadHandler>();
+ this.textStyleChildren = new ArrayList<OfficeStyleReadHandler>();
+ this.otherStyleChildren = new ArrayList<SectionReadHandler>();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri, final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.STYLE_NS.equals(uri))
+ {
+ if ("style".equals(tagName))
+ {
+ final OfficeStyleReadHandler xrh = new OfficeStyleReadHandler();
+ textStyleChildren.add(xrh);
+ return xrh;
+ }
+ else if ("page-layout".equals(tagName))
+ {
+ final PageLayoutReadHandler prh = new PageLayoutReadHandler();
+ pageLayoutChildren.add(prh);
+ return prh;
+ }
+ }
+ else if (OfficeNamespaces.DATASTYLE_NS.equals(uri))
+ {
+ final DataStyleReadHandler xrh = new DataStyleReadHandler(false);
+ dataStyleChildren.add(xrh);
+ return xrh;
+ }
+
+ final SectionReadHandler genericReadHandler = new SectionReadHandler();
+ otherStyleChildren.add(genericReadHandler);
+ return genericReadHandler;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < textStyleChildren.size(); i++)
+ {
+ final OfficeStyleReadHandler handler = textStyleChildren.get(i);
+ officeStyles.addStyle(handler.getOfficeStyle());
+ }
+
+ for (int i = 0; i < pageLayoutChildren.size(); i++)
+ {
+ final PageLayoutReadHandler handler = pageLayoutChildren.get(i);
+ officeStyles.addPageStyle(handler.getPageLayout());
+ }
+
+ for (int i = 0; i < dataStyleChildren.size(); i++)
+ {
+ final DataStyleReadHandler handler = dataStyleChildren.get(i);
+ officeStyles.addDataStyle(handler.getDataStyle());
+ }
+
+ for (int i = 0; i < otherStyleChildren.size(); i++)
+ {
+ final SectionReadHandler handler = otherStyleChildren.get(i);
+ officeStyles.addOtherNode((Element) handler.getNode());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return officeStyles;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/PageLayoutReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/PageLayoutReadHandler.java
new file mode 100644
index 000000000..06346e6b0
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/PageLayoutReadHandler.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.parser.style;
+
+import org.libreoffice.report.pentaho.model.PageLayout;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Reads a page-layout element.
+ *
+ * @since 13.03.2007
+ */
+public class PageLayoutReadHandler extends ElementReadHandler
+{
+
+ private final PageLayout pageLayout;
+ private final List<ElementReadHandler> children;
+
+ public PageLayoutReadHandler()
+ {
+ this.pageLayout = new PageLayout();
+ this.children = new ArrayList<ElementReadHandler>();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ final StyleDefinitionReadHandler readHandler =
+ new StyleDefinitionReadHandler();
+ children.add(readHandler);
+ return readHandler;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < children.size(); i++)
+ {
+ final ElementReadHandler handler = children.get(i);
+ pageLayout.addNode(handler.getElement());
+ }
+ }
+
+ public PageLayout getPageLayout()
+ {
+ return pageLayout;
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return pageLayout;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/StyleDefinitionReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/StyleDefinitionReadHandler.java
new file mode 100644
index 000000000..667a4964a
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/style/StyleDefinitionReadHandler.java
@@ -0,0 +1,93 @@
+/*
+ * 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.parser.style;
+
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Reads all children of a style-definition. This simply copies everything that
+ * is contained in the source-file into a generic structure that can be
+ * written out later.
+ */
+public class StyleDefinitionReadHandler extends ElementReadHandler
+{
+
+ private final Section rawSection;
+ private final List<ElementReadHandler> children;
+
+ public StyleDefinitionReadHandler()
+ {
+ this.rawSection = new Section();
+ this.children = new ArrayList<ElementReadHandler>();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ final StyleDefinitionReadHandler readHandler =
+ new StyleDefinitionReadHandler();
+ children.add(readHandler);
+ return readHandler;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing()
+ throws SAXException
+ {
+ for (int i = 0; i < children.size(); i++)
+ {
+ final ElementReadHandler handler = children.get(i);
+ rawSection.addNode(handler.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return rawSection;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/CoveredCellReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/CoveredCellReadHandler.java
new file mode 100644
index 000000000..5adb6d596
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/CoveredCellReadHandler.java
@@ -0,0 +1,45 @@
+/*
+ * 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.parser.table;
+
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 14.03.2007
+ */
+public class CoveredCellReadHandler extends ElementReadHandler
+{
+
+ private final Element coveredCell;
+
+ public CoveredCellReadHandler()
+ {
+ coveredCell = new Section();
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return coveredCell;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableCellReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableCellReadHandler.java
new file mode 100644
index 000000000..f37ac00f7
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableCellReadHandler.java
@@ -0,0 +1,36 @@
+/*
+ * 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.parser.table;
+
+import org.libreoffice.report.pentaho.model.TableCellElement;
+import org.libreoffice.report.pentaho.parser.text.NoCDATATextContentReadHandler;
+
+/**
+ * A read handler for table-cell contents. This is basically a text-content
+ * read handler; we may extend this implementation later.
+ *
+ * @since 05.03.2007
+ */
+public class TableCellReadHandler extends NoCDATATextContentReadHandler
+{
+
+ public TableCellReadHandler()
+ {
+ super(new TableCellElement(), true);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableColumnReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableColumnReadHandler.java
new file mode 100644
index 000000000..adfc956da
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableColumnReadHandler.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.parser.table;
+
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+/**
+ * Creation-Date: 03.07.2006, 14:26:55
+ *
+ */
+public class TableColumnReadHandler extends ElementReadHandler
+{
+
+ private final Section tableColumn;
+
+ public TableColumnReadHandler()
+ {
+ tableColumn = new Section();
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return tableColumn;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableColumnsReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableColumnsReadHandler.java
new file mode 100644
index 000000000..35da849ce
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableColumnsReadHandler.java
@@ -0,0 +1,96 @@
+/*
+ * 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.parser.table;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Creation-Date: 03.07.2006, 13:50:41
+ *
+ */
+public class TableColumnsReadHandler extends ElementReadHandler
+{
+
+ private final List<TableColumnReadHandler> columns;
+ private final Section tableColumns;
+
+ public TableColumnsReadHandler()
+ {
+ columns = new ArrayList<TableColumnReadHandler>();
+ tableColumns = new Section();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.TABLE_NS.equals(uri) && OfficeToken.TABLE_COLUMN.equals(tagName))
+ {
+ final TableColumnReadHandler readHandler = new TableColumnReadHandler();
+ columns.add(readHandler);
+ return readHandler;
+ }
+
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < columns.size(); i++)
+ {
+ final TableColumnReadHandler handler = columns.get(i);
+ tableColumns.addNode(handler.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return tableColumns;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableReadHandler.java
new file mode 100644
index 000000000..3c8e90f20
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableReadHandler.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.parser.table;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.model.OfficeTableSection;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.rpt.ConditionalPrintExpressionReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Creation-Date: 03.07.2006, 13:47:47
+ *
+ */
+public class TableReadHandler extends ElementReadHandler
+{
+
+ private final List<ElementReadHandler> children;
+ private final Section table;
+
+ public TableReadHandler()
+ {
+ children = new ArrayList<ElementReadHandler>();
+ table = new OfficeTableSection();
+ }
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs)
+ throws SAXException
+ {
+ super.startParsing(attrs);
+ final String enabled = attrs.getValue(OfficeNamespaces.OOREPORT_NS, "visible");
+ if (enabled == null || OfficeToken.TRUE.equals(enabled))
+ {
+ table.setEnabled(true);
+ }
+ else
+ {
+ table.setEnabled(false);
+ }
+
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.OOREPORT_NS.equals(uri) && "conditional-print-expression".equals(tagName))
+ {
+ return new ConditionalPrintExpressionReadHandler(table);
+ }
+ else if (OfficeNamespaces.TABLE_NS.equals(uri))
+ {
+ if (OfficeToken.TABLE_COLUMNS.equals(tagName) || OfficeToken.TABLE_HEADER_COLUMNS.equals(tagName))
+ {
+ final TableColumnsReadHandler columns = new TableColumnsReadHandler();
+ children.add(columns);
+ return columns;
+ }
+ else if (OfficeToken.TABLE_ROW.equals(tagName))
+ {
+ final TableRowReadHandler rowHandler = new TableRowReadHandler();
+ children.add(rowHandler);
+ return rowHandler;
+ }
+ else if (OfficeToken.TABLE_ROWS.equals(tagName) || OfficeToken.TABLE_HEADER_ROWS.equals(tagName))
+ {
+ final TableRowsReadHandler rowsHandler = new TableRowsReadHandler();
+ children.add(rowsHandler);
+ return rowsHandler;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < children.size(); i++)
+ {
+ final ElementReadHandler handler = children.get(i);
+ table.addNode(handler.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return table;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableRowReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableRowReadHandler.java
new file mode 100644
index 000000000..2f4bad5a4
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableRowReadHandler.java
@@ -0,0 +1,119 @@
+/*
+ * 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.parser.table;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Creation-Date: 03.07.2006, 13:51:47
+ *
+ */
+public class TableRowReadHandler extends ElementReadHandler
+{
+
+ private final List<ElementReadHandler> tableCells;
+ private final Section tableRow;
+
+ public TableRowReadHandler()
+ {
+ tableCells = new ArrayList<ElementReadHandler>();
+ tableRow = new Section();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ final ElementReadHandler rh;
+ if (OfficeNamespaces.TABLE_NS.equals(uri))
+ {
+ if (OfficeToken.TABLE_CELL.equals(tagName))
+ {
+ rh = new TableCellReadHandler();
+ }
+ else if (OfficeToken.COVERED_TABLE_CELL.equals(tagName))
+ {
+ rh = new CoveredCellReadHandler();
+ }
+ else
+ {
+ rh = null;
+ }
+ if (rh != null)
+ {
+ tableCells.add(rh);
+ }
+ }
+ else
+ {
+ rh = null;
+ }
+ return rh;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < tableCells.size(); i++)
+ {
+ final ElementReadHandler handler = tableCells.get(i);
+ tableRow.addNode(handler.getElement());
+ }
+ }
+
+ /**
+ * Returns the object for this element or null, if this element does not
+ * create an object.
+ *
+ * @return the object.
+ */
+ @Override
+ public Element getElement()
+ {
+ return tableRow;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableRowsReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableRowsReadHandler.java
new file mode 100644
index 000000000..33e253f24
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/table/TableRowsReadHandler.java
@@ -0,0 +1,92 @@
+/*
+ * 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.parser.table;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+public class TableRowsReadHandler extends ElementReadHandler
+{
+
+ private final List<TableRowReadHandler> rows;
+ private final Section tableRows;
+
+ public TableRowsReadHandler()
+ {
+ rows = new ArrayList<TableRowReadHandler>();
+ tableRows = new Section();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.TABLE_NS.equals(uri) && OfficeToken.TABLE_ROW.equals(tagName))
+ {
+ final TableRowReadHandler readHandler = new TableRowReadHandler();
+ rows.add(readHandler);
+ return readHandler;
+ }
+
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < rows.size(); i++)
+ {
+ final TableRowReadHandler handler = rows.get(i);
+ tableRows.addNode(handler.getElement());
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return tableRows;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/text/NoCDATATextContentReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/text/NoCDATATextContentReadHandler.java
new file mode 100644
index 000000000..83ab022a1
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/text/NoCDATATextContentReadHandler.java
@@ -0,0 +1,185 @@
+/*
+ * 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.parser.text;
+
+import org.libreoffice.report.OfficeToken;
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+import org.libreoffice.report.pentaho.parser.ElementReadHandler;
+import org.libreoffice.report.pentaho.parser.rpt.FixedContentReadHandler;
+import org.libreoffice.report.pentaho.parser.rpt.FormattedTextReadHandler;
+import org.libreoffice.report.pentaho.parser.rpt.ImageReadHandler;
+import org.libreoffice.report.pentaho.parser.rpt.SubDocumentReadHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.jfree.report.structure.Element;
+import org.jfree.report.structure.Section;
+import org.jfree.report.structure.StaticText;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * This is a generic implementation that accepts all input and adds special
+ * handlers for the report-elements.
+ *
+ */
+public class NoCDATATextContentReadHandler extends ElementReadHandler
+{
+
+ private Section section;
+ private List<Object> children;
+ private boolean copyType;
+
+ public NoCDATATextContentReadHandler(final Section section,
+ final boolean copyType)
+ {
+ this.children = new ArrayList<Object>();
+ this.section = section;
+ this.copyType = copyType;
+ }
+
+ public NoCDATATextContentReadHandler(final Section section)
+ {
+ this(section, false);
+ }
+
+ public NoCDATATextContentReadHandler()
+ {
+ this(new Section(), true);
+ }
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ super.startParsing(attrs);
+ final Element element = getElement();
+ if (copyType)
+ {
+ copyElementType(element);
+ }
+ copyAttributes(attrs, element);
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (OfficeNamespaces.OOREPORT_NS.equals(uri))
+ {
+ if ("fixed-content".equals(tagName))
+ {
+ final FixedContentReadHandler fixedContentReadHandler = new FixedContentReadHandler();
+ children.add(fixedContentReadHandler);
+ return fixedContentReadHandler;
+ }
+ if ("formatted-text".equals(tagName))
+ {
+ final FormattedTextReadHandler formattedTextReadHandler = new FormattedTextReadHandler();
+ children.add(formattedTextReadHandler);
+ return formattedTextReadHandler;
+ }
+ if (OfficeToken.IMAGE.equals(tagName))
+ {
+ final ImageReadHandler imageReadHandler = new ImageReadHandler();
+ children.add(imageReadHandler);
+ return imageReadHandler;
+ }
+ if ("sub-document".equals(tagName))
+ {
+ final SubDocumentReadHandler subDocReadHandler = new SubDocumentReadHandler(section);
+ return subDocReadHandler;
+ }
+ }
+ if (OfficeNamespaces.DRAWING_NS.equals(uri))
+ {
+ final XmlReadHandler readHandler;
+ if (OfficeToken.IMAGE.equals(tagName))
+ {
+ readHandler = new ImageReadHandler();
+ }
+ else
+ {
+ readHandler = new NoCDATATextContentReadHandler();
+ }
+ children.add(readHandler);
+ return readHandler;
+ }
+ else
+ {
+ final TextContentReadHandler readHandler = new TextContentReadHandler();
+ children.add(readHandler);
+ return readHandler;
+ }
+ }
+
+ public List<Object> getChildren()
+ {
+ return children;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing() throws SAXException
+ {
+ for (int i = 0; i < children.size(); i++)
+ {
+ final Object o = children.get(i);
+ if (o instanceof ElementReadHandler)
+ {
+ final ElementReadHandler handler = (ElementReadHandler) o;
+ section.addNode(handler.getElement());
+ }
+ else if (o instanceof StaticText)
+ {
+ section.addNode((StaticText) o);
+ }
+ }
+ }
+
+ @Override
+ public Element getElement()
+ {
+ return section;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/text/TextContentReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/text/TextContentReadHandler.java
new file mode 100644
index 000000000..fc0b1481e
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/text/TextContentReadHandler.java
@@ -0,0 +1,56 @@
+/*
+ * 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.parser.text;
+
+import org.jfree.report.structure.Section;
+import org.jfree.report.structure.StaticText;
+
+import org.xml.sax.SAXException;
+
+/**
+ * This is a generic implementation that accepts all input and adds special
+ * handlers for the report-elements.
+ *
+ */
+public class TextContentReadHandler extends NoCDATATextContentReadHandler
+{
+
+ public TextContentReadHandler(final Section section)
+ {
+ super(section);
+ }
+
+ public TextContentReadHandler()
+ {
+ }
+
+ /**
+ * This method is called to process the character data between element tags.
+ *
+ * @param ch the character buffer.
+ * @param start the start index.
+ * @param length the length.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ public void characters(final char[] ch, final int start, final int length)
+ throws SAXException
+ {
+ getChildren().add(new StaticText(new String(ch, start, length)));
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/parser/xlink/XLinkReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/parser/xlink/XLinkReadHandler.java
new file mode 100644
index 000000000..cadf200c0
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/parser/xlink/XLinkReadHandler.java
@@ -0,0 +1,65 @@
+/*
+ * 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.parser.xlink;
+
+import org.libreoffice.report.pentaho.OfficeNamespaces;
+
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * An image reference.
+ *
+ */
+public class XLinkReadHandler extends AbstractXmlReadHandler
+{
+
+ private String uri;
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs) throws SAXException
+ {
+ uri = attrs.getValue(OfficeNamespaces.XLINK_NS, "uri");
+ }
+
+ /**
+ * Returns the object for this element or null, if this element does not
+ * create an object.
+ *
+ * @return the object.
+ */
+ public Object getObject() throws SAXException
+ {
+ return uri;
+ }
+
+ @Override
+ public String getUri()
+ {
+ return uri;
+ }
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/smil.css b/reportbuilder/java/org/libreoffice/report/pentaho/smil.css
new file mode 100644
index 000000000..debe5cda7
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/smil.css
@@ -0,0 +1,5 @@
+@namespace url("urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0");
+
+/**
+ * All default styles for formatting-objects elements (if there are any).
+*/
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/star-office.css b/reportbuilder/java/org/libreoffice/report/pentaho/star-office.css
new file mode 100644
index 000000000..22d57ca05
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/star-office.css
@@ -0,0 +1,5 @@
+@namespace url("http://openoffice.org/2004/office");
+
+/**
+ * All default styles for office elements.
+*/
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/star-report.css b/reportbuilder/java/org/libreoffice/report/pentaho/star-report.css
new file mode 100644
index 000000000..b063d3563
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/star-report.css
@@ -0,0 +1,91 @@
+/*
+ * 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 .
+ */
+
+@namespace table url("urn:oasis:names:tc:opendocument:xmlns:table:1.0");
+@namespace text url("urn:oasis:names:tc:opendocument:xmlns:text:1.0");
+@namespace report url("http://openoffice.org/2005/report");
+
+table|table {
+ display: table;
+}
+
+table|table-columns {
+ display: table-column-group;
+}
+
+table|table-column {
+ display: table-column;
+}
+
+table|table-row {
+ display: table-row;
+}
+
+table|table-cell {
+ display: table-cell;
+}
+
+table|table-cell[number-columns-spanned],
+table|table-cell[number-columns-spanned],
+table|table-columns[number-columns-spanned],
+table|table-column[number-columns-spanned] {
+ -x-liblayout-colspan: attr("table|number-columns-spanned");
+}
+
+table|table-cell[number-rows-spanned],
+table|table-cell[number-rows-spanned] {
+ -x-liblayout-rowspan: attr("table|number-rows-spanned");
+}
+
+
+/**
+ * Style definitions for star report.
+*/
+* {
+ vertical-align: baseline;
+}
+
+/**
+ * A standard number format declaration. The number of decimal places
+ * and whether there is grouping is defined by the format string.
+ *
+ * The position and content of embedded text is also derived directly from
+ * the given format string text.
+
+ number
+ scientific
+ text
+ boolean
+ date
+ currency
+ percentage
+ fraction
+
+*/
+@format number myname {
+ -x-liblayout-decimal-replacement: "-";
+ -x-liblayout-display-factor: 1000;
+ content: "'Prefix'#,##0.00'postfix'";
+}
+
+@format scientific anothername {
+ /* to be filled */
+}
+
+
+
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/star-rpt.css b/reportbuilder/java/org/libreoffice/report/pentaho/star-rpt.css
new file mode 100644
index 000000000..47b6aca74
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/star-rpt.css
@@ -0,0 +1,5 @@
+@namespace url("http://openoffice.org/2005/report");
+
+/**
+ * All default styles for report elements.
+*/
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/LengthCalculator.java b/reportbuilder/java/org/libreoffice/report/pentaho/styles/LengthCalculator.java
new file mode 100644
index 000000000..bfc34a8fc
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/LengthCalculator.java
@@ -0,0 +1,95 @@
+/*
+ * 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.styles;
+
+import org.jfree.layouting.input.style.values.CSSNumericType;
+import org.jfree.layouting.input.style.values.CSSNumericValue;
+
+/**
+ * A helper class that sums up various CSS-length. The various unit types are
+ * kept separate until the final result is computed to minimize the computation
+ * inaccuracy.
+ *
+ * @since 15.03.2007
+ */
+public class LengthCalculator
+{
+ // and centimeter (x10)
+
+ private double millimeter;
+ // and pica (x12) and inch(x72). Px is assumed to be in 96dpi.
+ private double point;
+ private double pixel;
+
+ public void add(final CSSNumericValue value)
+ {
+ if (value == null)
+ {
+ return;
+ }
+
+ final CSSNumericType numericType = value.getType();
+ if (numericType == CSSNumericType.CM)
+ {
+ millimeter += value.getValue() * 10;
+ }
+ else if (numericType == CSSNumericType.MM)
+ {
+ millimeter += value.getValue();
+ }
+ else if (numericType == CSSNumericType.PT)
+ {
+ point += value.getValue();
+ }
+ else if (numericType == CSSNumericType.PC)
+ {
+ point += 12 * value.getValue();
+ }
+ else if (numericType == CSSNumericType.INCH)
+ {
+ point += 72 * value.getValue();
+ }
+ else if (numericType == CSSNumericType.PX)
+ {
+ pixel += value.getValue();
+ }
+ }
+
+ public CSSNumericValue getResult()
+ {
+ if (pixel == 0 && point == 0)
+ {
+ return CSSNumericValue.createValue(CSSNumericType.MM, millimeter);
+ }
+ if (pixel == 0 && millimeter == 0)
+ {
+ return CSSNumericValue.createValue(CSSNumericType.PT, point);
+ }
+ if (point == 0 && millimeter == 0)
+ {
+ return CSSNumericValue.createValue(CSSNumericType.PX, pixel);
+ }
+ // else convert it.
+
+ double result = point;
+ result += (millimeter * 10 * 72 / 254);
+ result += pixel * 72 / 96;
+
+ return CSSNumericValue.createValue(CSSNumericType.PT, result);
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapper.java b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapper.java
new file mode 100644
index 000000000..d65e85176
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapper.java
@@ -0,0 +1,86 @@
+/*
+ * 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.styles;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.pentaho.reporting.libraries.resourceloader.Resource;
+import org.pentaho.reporting.libraries.resourceloader.ResourceException;
+import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
+
+
+/**
+ * The style-mapper holds all information about the OpenOffice style mapping
+ * mechanism. OpenOffice references styles by their name and context, a style
+ * has a style-family assigned. The style family is determined by the element
+ * referencing the style, and there is no easily accessible information
+ * available on that.
+ *
+ * <p>Therefore this mapper acts as gatekeeper for this information. The style
+ * mapping information is read from an external definition file and can be
+ * maintained externally.</p>
+ *
+ * @since 11.03.2007
+ */
+public class StyleMapper
+{
+
+ private final Map<StyleMapperKey,StyleMappingRule> backend;
+
+ public StyleMapper()
+ {
+ this.backend = new HashMap<StyleMapperKey,StyleMappingRule>();
+ }
+
+ public void addMapping(final StyleMappingRule rule)
+ {
+ backend.put(rule.getKey(), rule);
+ }
+
+ public boolean isListOfStyles(final String elementNamespace,
+ final String elementTagName,
+ final String attributeNamespace,
+ final String attributeName)
+ {
+ final StyleMapperKey key = new StyleMapperKey(elementNamespace, elementTagName, attributeNamespace, attributeName);
+ final StyleMappingRule rule = backend.get(key);
+ return rule != null && rule.isListOfValues();
+ }
+
+ public String getStyleFamilyFor(final String elementNamespace,
+ final String elementTagName,
+ final String attributeNamespace,
+ final String attributeName)
+ {
+ final StyleMapperKey key = new StyleMapperKey(elementNamespace, elementTagName, attributeNamespace, attributeName);
+ final StyleMappingRule rule = backend.get(key);
+ if (rule == null)
+ {
+ return null;
+ }
+ return rule.getFamily();
+ }
+
+ public static StyleMapper loadInstance(final ResourceManager resourceManager)
+ throws ResourceException
+ {
+ final Resource resource = resourceManager.createDirectly("res://org/libreoffice/report/pentaho/styles/stylemapper.xml", StyleMapper.class);
+ return (StyleMapper) resource.getResource();
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperKey.java b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperKey.java
new file mode 100644
index 000000000..edf6cb7c8
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperKey.java
@@ -0,0 +1,90 @@
+/*
+ * 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.styles;
+
+/**
+ * A hash key for the stylemapper.
+ *
+ * @since 12.03.2007
+ */
+public final class StyleMapperKey
+{
+
+ private final String elementNamespace;
+ private final String elementName;
+ private final String attributeNamespace;
+ private final String attributeName;
+ private final int hashCode;
+
+ public StyleMapperKey(final String elementNamespace,
+ final String elementName,
+ final String attributeNamespace,
+ final String attributeName)
+ {
+ if (elementNamespace == null)
+ {
+ throw new NullPointerException();
+ }
+ if (elementName == null)
+ {
+ throw new NullPointerException();
+ }
+
+ this.elementNamespace = elementNamespace;
+ this.elementName = elementName;
+ this.attributeNamespace = attributeNamespace;
+ this.attributeName = attributeName;
+ this.hashCode = computeHashCode();
+ }
+
+ @Override
+ public boolean equals(final Object o)
+ {
+ if (this != o)
+ {
+ if (o == null || getClass() != o.getClass())
+ {
+ return false;
+ }
+
+ final StyleMapperKey that = (StyleMapperKey) o;
+
+ if ((attributeName != null ? !attributeName.equals(that.attributeName) : that.attributeName != null) || (attributeNamespace != null ? !attributeNamespace.equals(that.attributeNamespace) : that.attributeNamespace != null) || !elementName.equals(that.elementName) || !elementNamespace.equals(that.elementNamespace))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private int computeHashCode()
+ {
+ int result = elementNamespace.hashCode();
+ result = 31 * result + elementName.hashCode();
+ result = 31 * result + (attributeNamespace != null ? attributeNamespace.hashCode() : 0);
+ result = 31 * result + (attributeName != null ? attributeName.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return hashCode;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperXmlFactoryModule.java b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperXmlFactoryModule.java
new file mode 100644
index 000000000..af1b2b8fc
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperXmlFactoryModule.java
@@ -0,0 +1,57 @@
+/*
+ * 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.styles;
+
+import org.pentaho.reporting.libraries.xmlns.parser.XmlDocumentInfo;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlFactoryModule;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+/**
+ * An XML-FactoryModule that load the style-mapper contents.
+ *
+ * @since 12.03.2007
+ */
+@SuppressWarnings("ucd")
+public class StyleMapperXmlFactoryModule implements XmlFactoryModule
+{
+
+ public static final String NAMESPACE =
+ "http://jfreereport.sourceforge.net/namespaces/engine/openoffice/stylemapper";
+
+ public XmlReadHandler createReadHandler(final XmlDocumentInfo documentInfo)
+ {
+ return new StyleMappingDocumentReadHandler();
+ }
+
+ public int getDocumentSupport(final XmlDocumentInfo documentInfo)
+ {
+ final String rootNamespace = documentInfo.getRootElementNameSpace();
+ if (StyleMapperXmlFactoryModule.NAMESPACE.equals(rootNamespace) && "style-mapper-definition".equals(documentInfo.getRootElement()))
+ {
+
+ return XmlFactoryModule.RECOGNIZED_BY_NAMESPACE;
+ }
+ return XmlFactoryModule.NOT_RECOGNIZED;
+ }
+
+ public String getDefaultNamespace(final XmlDocumentInfo documentInfo)
+ {
+ return null;
+ }
+}
+
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperXmlResourceFactory.java b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperXmlResourceFactory.java
new file mode 100644
index 000000000..426e2ff61
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMapperXmlResourceFactory.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.styles;
+
+import org.jfree.report.JFreeReportBoot;
+
+import org.pentaho.reporting.libraries.base.config.Configuration;
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlResourceFactory;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 12.03.2007
+ */
+@SuppressWarnings("ucd")
+public class StyleMapperXmlResourceFactory extends AbstractXmlResourceFactory
+{
+
+ @Override
+ protected Configuration getConfiguration()
+ {
+ return JFreeReportBoot.getInstance().getGlobalConfig();
+ }
+
+ public Class getFactoryType()
+ {
+ return StyleMapper.class;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingDocumentReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingDocumentReadHandler.java
new file mode 100644
index 000000000..a7ba49b04
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingDocumentReadHandler.java
@@ -0,0 +1,98 @@
+/*
+ * 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.styles;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.XmlReadHandler;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+
+/**
+ * Todo: Document me!
+ *
+ * @since 12.03.2007
+ */
+public class StyleMappingDocumentReadHandler extends AbstractXmlReadHandler
+{
+
+ private final StyleMapper styleMapper;
+ private final List<StyleMappingReadHandler> mappings;
+
+ public StyleMappingDocumentReadHandler()
+ {
+ this.mappings = new ArrayList<StyleMappingReadHandler>();
+ this.styleMapper = new StyleMapper();
+ }
+
+ /**
+ * Returns the handler for a child element.
+ *
+ * @param tagName the tag name.
+ * @param atts the attributes.
+ * @return the handler or null, if the tagname is invalid.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected XmlReadHandler getHandlerForChild(final String uri,
+ final String tagName,
+ final Attributes atts)
+ throws SAXException
+ {
+ if (isSameNamespace(uri) && "mapping".equals(tagName))
+ {
+ final StyleMappingReadHandler smr = new StyleMappingReadHandler();
+ mappings.add(smr);
+ return smr;
+ }
+ return null;
+ }
+
+ /**
+ * Done parsing.
+ *
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void doneParsing()
+ throws SAXException
+ {
+ for (int i = 0; i < mappings.size(); i++)
+ {
+ final StyleMappingReadHandler handler = mappings.get(i);
+ styleMapper.addMapping(handler.getRule());
+ }
+ }
+
+ /**
+ * Returns the object for this element or null, if this element does not
+ * create an object.
+ *
+ * @return the object.
+ */
+ public StyleMapper getObject()
+ throws SAXException
+ {
+ return styleMapper;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingReadHandler.java b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingReadHandler.java
new file mode 100644
index 000000000..3360f61e1
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingReadHandler.java
@@ -0,0 +1,88 @@
+/*
+ * 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.styles;
+
+import org.pentaho.reporting.libraries.xmlns.parser.AbstractXmlReadHandler;
+import org.pentaho.reporting.libraries.xmlns.parser.ParseException;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 12.03.2007
+ */
+public class StyleMappingReadHandler extends AbstractXmlReadHandler
+{
+
+ private StyleMappingRule rule;
+
+ /**
+ * Starts parsing.
+ *
+ * @param attrs the attributes.
+ * @throws org.xml.sax.SAXException if there is a parsing error.
+ */
+ @Override
+ protected void startParsing(final Attributes attrs)
+ throws SAXException
+ {
+ final String elementNamespace = attrs.getValue(getUri(),
+ "element-namespace");
+ if (elementNamespace == null)
+ {
+ throw new ParseException("Required attribute 'element-namespace' is missing", getLocator());
+ }
+
+ final String elementName = attrs.getValue(getUri(), "element-name");
+
+ if (elementName == null)
+ {
+ throw new ParseException("Required attribute 'element-name' is missing", getLocator());
+ }
+
+ final String attributeNamespace = attrs.getValue(getUri(),
+ "attribute-namespace");
+ final String attributeName = attrs.getValue(getUri(), "attribute-name");
+
+ final boolean listOfValues =
+ "styleNameRefs".equals(attrs.getValue(getUri(), "type"));
+
+ final String family = attrs.getValue(getUri(), "style-family");
+ final StyleMapperKey key = new StyleMapperKey(elementNamespace, elementName, attributeNamespace, attributeName);
+ rule = new StyleMappingRule(key, family, listOfValues);
+ }
+
+ public StyleMappingRule getRule()
+ {
+ return rule;
+ }
+
+ /**
+ * Returns the object for this element or null, if this element does not
+ * create an object.
+ *
+ * @return the object.
+ */
+ public Object getObject()
+ throws SAXException
+ {
+ return rule;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingRule.java b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingRule.java
new file mode 100644
index 000000000..6e5e7512a
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/StyleMappingRule.java
@@ -0,0 +1,54 @@
+/*
+ * 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.styles;
+
+/**
+ * Todo: Document me!
+ *
+ * @since 12.03.2007
+ */
+public class StyleMappingRule
+{
+
+ private final StyleMapperKey key;
+ private final String family;
+ private final boolean listOfValues;
+
+ public StyleMappingRule(final StyleMapperKey key, final String family,
+ final boolean listOfValues)
+ {
+ this.key = key;
+ this.family = family;
+ this.listOfValues = listOfValues;
+ }
+
+ public StyleMapperKey getKey()
+ {
+ return key;
+ }
+
+ public String getFamily()
+ {
+ return family;
+ }
+
+ public boolean isListOfValues()
+ {
+ return listOfValues;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/stylemapper.xml b/reportbuilder/java/org/libreoffice/report/pentaho/styles/stylemapper.xml
new file mode 100644
index 000000000..8e5e5bc49
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/stylemapper.xml
@@ -0,0 +1,763 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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 .
+-->
+<style-mapper-definition
+ xmlns="http://jfreereport.sourceforge.net/namespaces/engine/openoffice/stylemapper">
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="a"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="text"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="alphabetical-index"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="section"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="alphabetical-index-entry-template"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="bibliography"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="section"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="bibliography-entry-template"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="h"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="illustration-index"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="section"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="illustration-index-entry-template"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-entry-bibliography"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-entry-chapter"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-entry-link-end"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-entry-link-start"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-entry-page-number"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-entry-span"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-entry-tab-stop"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-entry-text"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-source-style"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-title"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="section"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="index-title-template"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="linenumbering-configuration"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="text"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="list"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="list"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="list-level-style-bullet"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="text"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="list-level-style-number"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="numbered-paragraph"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="list"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="object-index"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="section"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="object-index-entry-template"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="outline-level-style"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="character"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="p"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="p"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="class-names"
+ style-family="paragraph"
+ type="styleNameRefs"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="ruby"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="ruby"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="ruby-text"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="section"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="section"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="span"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="text"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="span"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="class-names"
+ style-family="text"
+ type="styleNameRefs"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="table-index"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="section"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="table-index-entry-template"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="table-of-content"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="section"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="table-of-content-entry-template"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="user-index"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="section"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ element-name="user-index-entry-template"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+ attribute-name="style-name"
+ style-family="paragraph"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="table"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="background"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="body"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="covered-table-cell"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="even-columns"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="even-rows"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="first-column"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="first-row"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="last-column"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="last-row"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="odd-columns"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="odd-rows"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="table-cell"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-cell"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="table-column"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-column"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ element-name="table-row"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+ attribute-name="style-name"
+ style-family="table-row"
+ type="styleNameRef"/>
+
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="cube"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="extrude"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="rotate"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="scene"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="sphere"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="caption"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="circle"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="connector"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="control"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="custom-shape"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="ellipse"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="frame"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="g"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="line"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="measure"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="page"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="page-thumbnail"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="path"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="polygon"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="polyline"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="rect"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="regular-polygon"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ element-name="annotation"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ element-name="notes"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+ element-name="handout-master"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+ element-name="master-page"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="graphic"
+ type="styleNameRef"/>
+
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="cube"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="extrude"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="rotate"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="scene"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+ element-name="sphere"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="caption"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="circle"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="connector"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="custom-shape"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="ellipse"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="frame"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="g"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="line"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="measure"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="page-thumbnail"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="path"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="polygon"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="polyline"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="rect"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+ element-name="regular-polygon"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ element-name="annotation"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
+ attribute-name="style-name"
+ style-family="presentation"
+ type="styleNameRef"/>
+
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="axis"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="chart"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="data-label"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="data-point"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="equation"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="error-indicator"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="floor"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="footer"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="grid"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="legend"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="mean-value"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="plot-area"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="regression-curve"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="series"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="stock-gain-marker"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="stock-loss-marker"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="stock-range-line"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="subtitle"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="title"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ element-name="wall"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+ attribute-name="style-name"
+ style-family="chart"
+ type="styleNameRef"/>
+ <mapping element-namespace="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+ element-name="drop-cap"
+ attribute-namespace="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+ attribute-name="style-name"
+ style-family="text"
+ type="styleNameRef"/>
+</style-mapper-definition>
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/styles/stylemapper.xsd b/reportbuilder/java/org/libreoffice/report/pentaho/styles/stylemapper.xsd
new file mode 100644
index 000000000..feb7234e8
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/styles/stylemapper.xsd
@@ -0,0 +1,81 @@
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<xsd:schema version="0.9"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns="http://jfreereport.sourceforge.net/namespaces/engine/openoffice/stylemapper"
+ targetNamespace="http://jfreereport.sourceforge.net/namespaces/engine/openoffice/stylemapper"
+ attributeFormDefault="unqualified">
+ <xsd:annotation>
+ <xsd:documentation>
+ This schema describes the format of the stylemapper definition file.
+ The stylemapper declares what style-families are referenced by an element.
+ </xsd:documentation>
+ </xsd:annotation>
+
+ <xsd:simpleType name="styleNameRefType">
+ <xsd:restriction base="xsd:NMTOKEN">
+ <xsd:enumeration value="styleNameRef"/>
+ <xsd:enumeration value="styleNameRefs"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="styleFamilyType">
+ <xsd:restriction base="xsd:NMTOKEN">
+ <xsd:enumeration value="paragraph"/>
+ <xsd:enumeration value="text"/>
+ <xsd:enumeration value="section"/>
+ <xsd:enumeration value="table"/>
+ <xsd:enumeration value="table-column"/>
+ <xsd:enumeration value="table-row"/>
+ <xsd:enumeration value="table-cell"/>
+ <xsd:enumeration value="table-page"/>
+ <xsd:enumeration value="chart"/>
+ <xsd:enumeration value="default"/>
+ <xsd:enumeration value="drawing-page"/>
+ <xsd:enumeration value="graphic"/>
+ <xsd:enumeration value="presentation"/>
+ <xsd:enumeration value="control"/>
+ <xsd:enumeration value="ruby"/>
+ <xsd:enumeration value="custom-shape"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:element name="mapping">
+ <xsd:complexType>
+ <xsd:attribute name="element-namespace" use="required" type="xsd:anyURI"/>
+ <xsd:attribute name="element-name" use="required" type="xsd:NCName"/>
+ <xsd:attribute name="attribute-namespace" use="required" type="xsd:anyURI"/>
+ <xsd:attribute name="attribute-name" use="required" type="xsd:NCName"/>
+ <xsd:attribute name="type" use="required" type="styleNameRefType"/>
+ <xsd:attribute name="style-family" use="required" type="styleFamilyType"/>
+ </xsd:complexType>
+ </xsd:element>
+
+ <xsd:element name="style-mapper-definition">
+ <xsd:complexType>
+ <xsd:complexContent>
+ <xsd:restriction base="xsd:anyType">
+ <xsd:sequence>
+ <xsd:element ref="mapping" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ </xsd:restriction>
+ </xsd:complexContent>
+ </xsd:complexType>
+ </xsd:element>
+
+</xsd:schema>
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/svg.css b/reportbuilder/java/org/libreoffice/report/pentaho/svg.css
new file mode 100644
index 000000000..e4bdcf01e
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/svg.css
@@ -0,0 +1,5 @@
+@namespace url("urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0");
+
+/**
+ * All default styles for formatting-objects elements (if there are any).
+*/
diff --git a/reportbuilder/java/org/libreoffice/report/pentaho/xsl-fo.css b/reportbuilder/java/org/libreoffice/report/pentaho/xsl-fo.css
new file mode 100644
index 000000000..9cb08acea
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/pentaho/xsl-fo.css
@@ -0,0 +1,5 @@
+@namespace url("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0");
+
+/**
+ * All default styles for formatting-objects elements (if there are any).
+*/
diff --git a/reportbuilder/java/org/libreoffice/report/util/DefaultJobProperties.java b/reportbuilder/java/org/libreoffice/report/util/DefaultJobProperties.java
new file mode 100644
index 000000000..ce0ea8dce
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/util/DefaultJobProperties.java
@@ -0,0 +1,71 @@
+/*
+ * 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.util;
+
+import org.libreoffice.report.JobDefinitionException;
+import org.libreoffice.report.JobProperties;
+import org.libreoffice.report.ReportEngineMetaData;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class DefaultJobProperties implements JobProperties
+{
+
+ private final ReportEngineMetaData metaData;
+ private final Map<String,Object> properties;
+
+ public DefaultJobProperties(final ReportEngineMetaData metaData)
+ {
+ if (metaData == null)
+ {
+ throw new NullPointerException();
+ }
+ this.properties = new HashMap<String,Object>();
+ this.metaData = metaData;
+ }
+
+ public Object getProperty(final String key)
+ {
+ return properties.get(key);
+ }
+
+ public void setProperty(final String key, final Object value)
+ throws JobDefinitionException
+ {
+ final Class type = metaData.getParameterType(key);
+ if (type == null)
+ {
+ throw new JobDefinitionException("The parameter name is not known: " + key);
+ }
+ if (!type.isInstance(value))
+ {
+ throw new JobDefinitionException("The parameter value is not understood");
+ }
+
+ this.properties.put(key, value);
+ }
+
+ public JobProperties copy()
+ {
+ final DefaultJobProperties props = new DefaultJobProperties(metaData);
+ props.properties.putAll(properties);
+ return props;
+ }
+}
diff --git a/reportbuilder/java/org/libreoffice/report/util/DefaultParameterMap.java b/reportbuilder/java/org/libreoffice/report/util/DefaultParameterMap.java
new file mode 100644
index 000000000..b1cd76343
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/util/DefaultParameterMap.java
@@ -0,0 +1,57 @@
+/*
+ * 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.util;
+
+import org.libreoffice.report.ParameterMap;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class DefaultParameterMap implements ParameterMap
+{
+
+ private final Map<String,Object> backend;
+
+ public DefaultParameterMap()
+ {
+ backend = new HashMap<String,Object>();
+ }
+
+ /**
+ * Retrieves the value stored for a key in this properties collection.
+ *
+ * @param key the property key.
+ * @return The stored value, or <code>null</code> if the key does not exist in this
+ * collection.
+ */
+ public Object get(final String key)
+ {
+ if (key == null)
+ {
+ throw new NullPointerException("DefaultParameterMap.get (..): Parameter 'key' must not be null");
+ }
+ return backend.get(key);
+ }
+
+ public String[] keys()
+ {
+ return this.backend.keySet().toArray(new String[backend.size()]);
+ }
+
+}
diff --git a/reportbuilder/java/org/libreoffice/report/util/DefaultReportJobDefinition.java b/reportbuilder/java/org/libreoffice/report/util/DefaultReportJobDefinition.java
new file mode 100644
index 000000000..b3e2e96c6
--- /dev/null
+++ b/reportbuilder/java/org/libreoffice/report/util/DefaultReportJobDefinition.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util;
+
+import org.libreoffice.report.JobProperties;
+import org.libreoffice.report.ParameterMap;
+import org.libreoffice.report.ReportEngineMetaData;
+import org.libreoffice.report.ReportJobDefinition;
+
+public class DefaultReportJobDefinition implements ReportJobDefinition
+{
+
+
+ private final DefaultParameterMap parameters;
+ private final DefaultJobProperties properties;
+
+ public DefaultReportJobDefinition(final ReportEngineMetaData metaData)
+ {
+ this.parameters = new DefaultParameterMap();
+ this.properties = new DefaultJobProperties(metaData);
+ }
+
+ /**
+ * The parameters of the root report definition. The parameters for the subreports are
+ * defined using mappings, it would not make sense to define them here.
+ *
+ * @return a map container for query parameters.
+ */
+ public ParameterMap getQueryParameters()
+ {
+ return parameters;
+ }
+
+ public JobProperties getProcessingParameters()
+ {
+ return properties;
+ }
+}
diff --git a/reportbuilder/java/reportbuilder.component b/reportbuilder/java/reportbuilder.component
new file mode 100644
index 000000000..75cdee4e0
--- /dev/null
+++ b/reportbuilder/java/reportbuilder.component
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!--
+ * 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/.
+ *
+-->
+<component loader="com.sun.star.loader.Java2"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="org.libreoffice.report.pentaho.SOFormulaParser">
+ <service name="com.sun.star.report.meta.FormulaParser"/>
+ </implementation>
+ <implementation name="org.libreoffice.report.pentaho.SOFunctionManager">
+ <service name="com.sun.star.report.meta.FunctionManager"/>
+ </implementation>
+ <implementation name="org.libreoffice.report.pentaho.SOReportJobFactory$_SOReportJobFactory">
+ <service name="org.libreoffice.report.pentaho.SOReportJobFactory"/>
+ </implementation>
+</component>