diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /reportbuilder/java | |
parent | Initial commit. (diff) | |
download | libreoffice-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')
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> |