/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core;
import org.pentaho.reporting.engine.classic.core.designtime.DesignTimeUtil;
import org.pentaho.reporting.engine.classic.core.designtime.SubReportParameterChange;
import org.pentaho.reporting.engine.classic.core.filter.types.bands.SubReportType;
import org.pentaho.reporting.engine.classic.core.function.Expression;
import org.pentaho.reporting.engine.classic.core.util.InstanceID;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
import java.awt.print.PageFormat;
import java.util.LinkedHashMap;
/**
* A subreport element. A subreport can be attached to a root-level band and will be printed afterwards. Subreports have
* their own tablemodel (queried with the sub-reports's defined query and the master report's data-factory).
* <p/>
* A sub-report that has been added to a root-level band will always be printed below the root-level band.
* <p/>
* Sub-reports can have import and export parameters. The parameter mapping can be defined freely, so a subreport is not
* required to use the same column names as the parent report.
* <p/>
* If a global import or export is defined (by adding the parameter mapping "*" => "*") the other defined parameter
* mappings will be ignored.
*
* @author Thomas Morgner
*/
public class SubReport extends AbstractReportDefinition {
/**
* A mapping of export parameters.
*/
private LinkedHashMap<String, String> exportParameters;
/**
* A mapping of import parameters.
*/
private LinkedHashMap<String, String> inputParameters;
private DataFactory dataFactory;
/**
* Creates a new subreport instance.
*/
public SubReport() {
setElementType( new SubReportType() );
exportParameters = new LinkedHashMap<String, String>();
inputParameters = new LinkedHashMap<String, String>();
}
public SubReport( final InstanceID id ) {
super( id );
setElementType( new SubReportType() );
exportParameters = new LinkedHashMap<String, String>();
inputParameters = new LinkedHashMap<String, String>();
}
/**
* Returns the page definition assigned to the report definition. The page definition defines the report area and how
* the report is subdivided by the child pages.
*
* @return null, as subreports have no page-definition at all.
*/
public PageDefinition getPageDefinition() {
ReportElement parent = getParentSection();
while ( parent != null ) {
if ( parent instanceof MasterReport ) {
final MasterReport masterReport = (MasterReport) parent;
return masterReport.getPageDefinition();
}
parent = parent.getParentSection();
}
return new SimplePageDefinition( new PageFormat() );
}
/**
* Clones the report.
*
* @return the clone.
*/
public SubReport derive( final boolean preserveElementInstanceIds ) {
final SubReport o = (SubReport) super.derive( preserveElementInstanceIds );
o.exportParameters = (LinkedHashMap<String, String>) exportParameters.clone();
o.inputParameters = (LinkedHashMap<String, String>) inputParameters.clone();
if ( dataFactory != null ) {
o.dataFactory = dataFactory.derive();
}
return o;
}
public void reconnectParent( final Section parentSection ) {
parentSection.registerAsChild( this );
}
/**
* Clones the report.
*
* @return the clone.
*/
public SubReport clone() {
final SubReport o = (SubReport) super.clone();
o.exportParameters = (LinkedHashMap<String, String>) exportParameters.clone();
o.inputParameters = (LinkedHashMap<String, String>) inputParameters.clone();
if ( dataFactory != null ) {
o.dataFactory = dataFactory.derive();
}
return o;
}
/**
* Adds an export-parameter mapping to the subreport. The parameter specified by 'sourceColumn' will be made available
* with the name 'outerName' in the parent report.
*
* @param outerName
* the name the parameter will get in the master report.
* @param sourceColumn
* the source-column in the sub-report.
*/
public void addExportParameter( final String outerName, final String sourceColumn ) {
if ( outerName == null ) {
throw new NullPointerException();
}
if ( sourceColumn == null ) {
throw new NullPointerException();
}
final ParameterMapping[] oldMappings = getExportMappings();
exportParameters.put( outerName, sourceColumn );
notifyNodePropertiesChanged( new SubReportParameterChange( SubReportParameterChange.Type.EXPORT, oldMappings,
getExportMappings() ) );
}
/**
* Removes the export parameter from the mapping.
*
* @param outerName
* the name of the parameter as it is known in the master report.
*/
public void removeExportParameter( final String outerName ) {
if ( outerName == null ) {
throw new NullPointerException();
}
final ParameterMapping[] oldMappings = getExportMappings();
exportParameters.remove( outerName );
notifyNodePropertiesChanged( new SubReportParameterChange( SubReportParameterChange.Type.EXPORT, oldMappings,
getExportMappings() ) );
}
/**
* Returns the parameter mappings for the subreport. The parameter mappings define how columns of the sub-report get
* mapped into the master report.
*
* @return the parameter mappings array.
*/
public ParameterMapping[] getExportMappings() {
final int length = exportParameters.size();
final String[] keys = exportParameters.keySet().toArray( new String[length] );
final ParameterMapping[] mapping = new ParameterMapping[length];
for ( int i = 0; i < length; i++ ) {
final String name = keys[i];
final String alias = exportParameters.get( name );
mapping[i] = new ParameterMapping( name, alias );
}
return mapping;
}
public void setExportMappings( final ParameterMapping[] mappings ) {
if ( mappings == null ) {
throw new NullPointerException();
}
final ParameterMapping[] oldMappings = getExportMappings();
exportParameters.clear();
for ( int i = 0; i < mappings.length; i++ ) {
final ParameterMapping mapping = mappings[i];
exportParameters.put( mapping.getName(), mapping.getAlias() );
}
notifyNodePropertiesChanged( new SubReportParameterChange( SubReportParameterChange.Type.EXPORT, oldMappings,
getExportMappings() ) );
}
/**
* Adds an input-parameter mapping to the subreport. Input parameters define how columns that exist in the parent
* report get mapped into the subreport.
* <p/>
* Input parameter mapping happens only once, so after the report has been started, changes to the parameters will not
* pass through to the subreport.
*
* @param outerName
* the name of the parent report's column that provides the data.
* @param sourceColumn
* the name under which the parameter will be available in the subreport.
*/
public void addInputParameter( final String outerName, final String sourceColumn ) {
if ( outerName == null ) {
throw new NullPointerException();
}
if ( sourceColumn == null ) {
throw new NullPointerException();
}
final ParameterMapping[] oldMappings = getInputMappings();
inputParameters.put( sourceColumn, outerName );
notifyNodePropertiesChanged( new SubReportParameterChange( SubReportParameterChange.Type.INPUT, oldMappings,
getInputMappings() ) );
}
/**
* Removes the input parameter from the parameter mapping.
*
* @param sourceColumn
* the name of the column of the subreport report that acts as source for the input parameter.
*/
public void removeInputParameter( final String sourceColumn ) {
if ( sourceColumn == null ) {
throw new NullPointerException();
}
final ParameterMapping[] oldMappings = getInputMappings();
inputParameters.remove( sourceColumn );
notifyNodePropertiesChanged( new SubReportParameterChange( SubReportParameterChange.Type.INPUT, oldMappings,
getInputMappings() ) );
}
public void clearInputParameters() {
final ParameterMapping[] oldMappings = getInputMappings();
inputParameters.clear();
notifyNodePropertiesChanged( new SubReportParameterChange( SubReportParameterChange.Type.INPUT, oldMappings,
getInputMappings() ) );
}
public void clearExportParameters() {
final ParameterMapping[] oldMappings = getExportMappings();
exportParameters.clear();
notifyNodePropertiesChanged();
notifyNodePropertiesChanged( new SubReportParameterChange( SubReportParameterChange.Type.EXPORT, oldMappings,
getExportMappings() ) );
}
/**
* Returns the input mappings defined for this subreport.
*
* @return the input mappings, never null.
*/
public ParameterMapping[] getInputMappings() {
final int length = inputParameters.size();
final String[] keys = inputParameters.keySet().toArray( new String[length] );
final ParameterMapping[] mapping = new ParameterMapping[length];
for ( int i = 0; i < length; i++ ) {
final String alias = keys[i];
final String name = inputParameters.get( alias );
mapping[i] = new ParameterMapping( name, alias );
}
return mapping;
}
public void setInputMappings( final ParameterMapping[] mappings ) {
if ( mappings == null ) {
throw new NullPointerException();
}
final ParameterMapping[] oldMappings = getInputMappings();
inputParameters.clear();
for ( int i = 0; i < mappings.length; i++ ) {
final ParameterMapping mapping = mappings[i];
inputParameters.put( mapping.getAlias(), mapping.getName() );
}
notifyNodePropertiesChanged( new SubReportParameterChange( SubReportParameterChange.Type.INPUT, oldMappings,
getInputMappings() ) );
}
/**
* Checks whether a global import is defined. A global import effectly overrides all other imports.
*
* @return true, if there is a global import defined, false otherwise.
*/
public boolean isGlobalImport() {
return "*".equals( inputParameters.get( "*" ) );
}
/**
* Checks whether a global export is defined. A global export effectly overrides all other export mappings.
*
* @return true, if there is a global export defined, false otherwise.
*/
public boolean isGlobalExport() {
return "*".equals( exportParameters.get( "*" ) );
}
public DataFactory getDataFactory() {
return dataFactory;
}
/**
* The (optional) data-factory for the subreport. If no datafactory is defined here, the subreport will use the master
* report's data-factory.
*
* @param dataFactory
*/
public void setDataFactory( final DataFactory dataFactory ) {
final DataFactory old = this.dataFactory;
this.dataFactory = dataFactory;
if ( old != null ) {
notifyNodeChildRemoved( old );
}
if ( dataFactory != null ) {
notifyNodeChildAdded( dataFactory );
}
}
public Expression getActivationExpression() {
return getAttributeExpression( AttributeNames.Core.NAMESPACE, AttributeNames.Core.SUBREPORT_ACTIVE );
}
public void setActivationExpression( final Expression activationExpression ) {
setAttributeExpression( AttributeNames.Core.NAMESPACE, AttributeNames.Core.SUBREPORT_ACTIVE, activationExpression );
}
protected void updateChangedFlagInternal( final ReportElement element, final int type, final Object parameter ) {
// also notify all local listeners on all changes.
super.fireModelLayoutChanged( element, type, parameter );
super.updateChangedFlagInternal( element, type, parameter );
}
@Deprecated
public ResourceManager getResourceManager() {
return DesignTimeUtil.getResourceManager( this );
}
@Deprecated
public ResourceBundleFactory getResourceBundleFactory() {
return super.getResourceBundleFactory();
}
}