/*
* 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.states;
import org.pentaho.reporting.engine.classic.core.CrosstabCellBody;
import org.pentaho.reporting.engine.classic.core.DetailsFooter;
import org.pentaho.reporting.engine.classic.core.DetailsHeader;
import org.pentaho.reporting.engine.classic.core.Element;
import org.pentaho.reporting.engine.classic.core.Group;
import org.pentaho.reporting.engine.classic.core.GroupBody;
import org.pentaho.reporting.engine.classic.core.GroupDataBody;
import org.pentaho.reporting.engine.classic.core.ItemBand;
import org.pentaho.reporting.engine.classic.core.MasterReport;
import org.pentaho.reporting.engine.classic.core.NoDataBand;
import org.pentaho.reporting.engine.classic.core.PageDefinition;
import org.pentaho.reporting.engine.classic.core.PageFooter;
import org.pentaho.reporting.engine.classic.core.PageHeader;
import org.pentaho.reporting.engine.classic.core.ReportDefinition;
import org.pentaho.reporting.engine.classic.core.ReportElement;
import org.pentaho.reporting.engine.classic.core.ReportFooter;
import org.pentaho.reporting.engine.classic.core.ReportHeader;
import org.pentaho.reporting.engine.classic.core.ReportProcessingException;
import org.pentaho.reporting.engine.classic.core.Section;
import org.pentaho.reporting.engine.classic.core.SubReport;
import org.pentaho.reporting.engine.classic.core.Watermark;
import org.pentaho.reporting.engine.classic.core.filter.types.bands.MasterReportType;
import org.pentaho.reporting.engine.classic.core.function.Expression;
import org.pentaho.reporting.engine.classic.core.style.StyleKey;
import java.util.Map;
import java.util.Set;
/**
* A report definition. This the working copy of the JFreeReport object. This object is not serializable, as it is used
* internally. This implementation is not intended to be known outside. Whatever you planned to do with it - dont do it!
* <p/>
* Its only pupose is to be used and manipulated in the report states, there is no reason to do it outside.
*
* @author Thomas Morgner.
*/
public class ReportDefinitionImpl extends Section implements ReportDefinition {
/**
* The report header band (if not null, printed once at the start of the report).
*/
private ReportHeader reportHeader;
/**
* The report footer band (if not null, printed once at the end of the report).
*/
private ReportFooter reportFooter;
/**
* The page header band (if not null, printed at the start of every page).
*/
private PageHeader pageHeader;
/**
* The page footer band (if not null, printed at the end of every page).
*/
private PageFooter pageFooter;
/**
* The watermark acts a global page background.
*/
private Watermark watermark;
/**
* The page definition defines the output area.
*/
private PageDefinition pageDefinition;
private String query;
private Group rootGroup;
private int queryLimit;
private int queryTimeout;
/**
* Creates a report definition from a report object.
*
* @param report
* the report.
* @param pageDefinition
* the current page definition.
* @throws ReportProcessingException
* if there is a problem cloning.
*/
public ReportDefinitionImpl( final MasterReport report, final PageDefinition pageDefinition )
throws ReportProcessingException {
super( report.getObjectID() );
copyReport( report, pageDefinition );
}
public ReportDefinitionImpl( final SubReport report, final PageDefinition pageDefinition, final Section parentSection )
throws ReportProcessingException {
super( report.getObjectID() );
copyReport( report, pageDefinition );
setParent( parentSection );
}
private void copyReport( final ReportDefinition report, final PageDefinition pageDefinition ) {
if ( pageDefinition == null ) {
throw new NullPointerException();
}
this.rootGroup = (Group) report.getRootGroup().derive( true );
this.reportFooter = (ReportFooter) report.getReportFooter().derive( true );
this.reportHeader = (ReportHeader) report.getReportHeader().derive( true );
this.pageFooter = (PageFooter) report.getPageFooter().derive( true );
this.pageHeader = (PageHeader) report.getPageHeader().derive( true );
this.watermark = (Watermark) report.getWatermark().derive( true );
this.pageDefinition = pageDefinition;
this.query = report.getQuery();
copyAttributes( report.getAttributes() );
final String[] attrExprNamespaces = report.getAttributeExpressionNamespaces();
for ( int i = 0; i < attrExprNamespaces.length; i++ ) {
final String namespace = attrExprNamespaces[i];
final String[] attributeNames = report.getAttributeExpressionNames( namespace );
for ( int j = 0; j < attributeNames.length; j++ ) {
final String name = attributeNames[j];
setAttributeExpression( namespace, name, report.getAttributeExpression( namespace, name ) );
}
}
getStyle().copyFrom( report.getStyle() );
final Set<Map.Entry<StyleKey, Expression>> styleExpressionEntries = report.getStyleExpressions().entrySet();
for ( final Map.Entry<StyleKey, Expression> entry : styleExpressionEntries ) {
setStyleExpression( entry.getKey(), entry.getValue() );
}
registerAsChild( rootGroup );
registerAsChild( reportHeader );
registerAsChild( reportFooter );
registerAsChild( pageHeader );
registerAsChild( pageFooter );
registerAsChild( watermark );
this.queryLimit = report.getQueryLimit();
this.queryTimeout = report.getQueryTimeout();
setName( report.getName() );
setChangeTracker( report.getChangeTracker() );
}
public int getQueryLimit() {
return queryLimit;
}
public int getQueryTimeout() {
return queryTimeout;
}
public String getQuery() {
return query;
}
/**
* Returns the report header.
*
* @return The report header.
*/
public ReportHeader getReportHeader() {
return reportHeader;
}
/**
* Returns the report footer.
*
* @return The report footer.
*/
public ReportFooter getReportFooter() {
return reportFooter;
}
/**
* Returns the page header.
*
* @return The page header.
*/
public PageHeader getPageHeader() {
return pageHeader;
}
/**
* Returns the page footer.
*
* @return The page footer.
*/
public PageFooter getPageFooter() {
return pageFooter;
}
/**
* Returns the item band.
*
* @return The item band.
*/
public ItemBand getItemBand() {
final Group group = getInnerMostGroup();
final GroupBody body = group.getBody();
if ( body instanceof GroupDataBody ) {
final GroupDataBody dataBody = (GroupDataBody) body;
return dataBody.getItemBand();
}
return null;
}
public CrosstabCellBody getCrosstabCellBody() {
final Group group = getInnerMostGroup();
final GroupBody body = group.getBody();
if ( body instanceof CrosstabCellBody ) {
return (CrosstabCellBody) body;
}
return null;
}
/**
* Returns the details header band.
*
* @return The details header band.
*/
public DetailsHeader getDetailsHeader() {
final Group group = getInnerMostGroup();
final GroupBody body = group.getBody();
if ( body instanceof GroupDataBody ) {
final GroupDataBody dataBody = (GroupDataBody) body;
return dataBody.getDetailsHeader();
}
return null;
}
/**
* Returns the details header band.
*
* @return The details header band.
*/
public DetailsFooter getDetailsFooter() {
final Group group = getInnerMostGroup();
final GroupBody body = group.getBody();
if ( body instanceof GroupDataBody ) {
final GroupDataBody dataBody = (GroupDataBody) body;
return dataBody.getDetailsFooter();
}
return null;
}
public Group getRootGroup() {
return rootGroup;
}
private Group getInnerMostGroup() {
Group existingGroup = rootGroup;
GroupBody gb = existingGroup.getBody();
while ( gb != null ) {
final int count = gb.getElementCount();
GroupBody locatedBody = null;
for ( int i = 0; i < count; i++ ) {
final ReportElement element = gb.getElement( i );
if ( element instanceof Group ) {
existingGroup = (Group) element;
locatedBody = existingGroup.getBody();
break;
}
}
if ( locatedBody == null ) {
gb = null;
} else {
gb = locatedBody;
}
}
return existingGroup;
}
/**
* Returns the "no-data" band, which is displayed if there is no data available.
*
* @return The no-data band.
*/
public NoDataBand getNoDataBand() {
final Group group = getInnerMostGroup();
final GroupBody body = group.getBody();
if ( body instanceof GroupDataBody ) {
final GroupDataBody dataBody = (GroupDataBody) body;
return dataBody.getNoDataBand();
}
return null;
}
/**
* Returns the number of groups in this report.
* <P>
* Every report has at least one group defined.
*
* @return the group count.
*/
public int getGroupCount() {
int result = 1; // we always have at least a default-group.
Group existingGroup = rootGroup;
GroupBody gb = existingGroup.getBody();
while ( gb != null ) {
final int count = gb.getElementCount();
boolean found = false;
for ( int i = 0; i < count; i++ ) {
final ReportElement element = gb.getElement( i );
if ( element instanceof Group ) {
existingGroup = (Group) element;
result += 1;
gb = existingGroup.getBody();
found = true;
break;
}
}
if ( found == false ) {
gb = null;
}
}
return result;
}
/**
* Returns the group at the specified index or null, if there is no such group.
*
* @param groupIndex
* the group index.
* @return the requested group.
* @throws IllegalArgumentException
* if the count is negative.
* @throws IndexOutOfBoundsException
* if the count is greater than the number of defined groups.
*/
public Group getGroup( final int groupIndex ) {
if ( groupIndex < 0 ) {
throw new IllegalArgumentException( "GroupCount must not be negative" );
}
if ( groupIndex == 0 ) {
return rootGroup;
}
int result = 0; // we always have at least a default-group.
Group existingGroup = rootGroup;
GroupBody gb = existingGroup.getBody();
while ( gb != null ) {
final int count = gb.getElementCount();
boolean found = false;
for ( int i = 0; i < count; i++ ) {
final ReportElement element = gb.getElement( i );
if ( element instanceof Group ) {
existingGroup = (Group) element;
result += 1;
if ( result == groupIndex ) {
return existingGroup;
}
gb = existingGroup.getBody();
found = true;
break;
}
}
if ( found == false ) {
gb = null;
}
}
throw new IndexOutOfBoundsException( "No group defined at the given index " + groupIndex + " . Max-index=" + result );
}
/**
* Creates and returns a copy of this object.
*
* @return a clone of this instance.
* @throws CloneNotSupportedException
* if the object's class does not support the <code>Cloneable</code> interface. Subclasses that override the
* <code>clone</code> method can also throw this exception to indicate that an instance cannot be cloned.
* @see java.lang.Cloneable
*/
public ReportDefinitionImpl clone() {
final ReportDefinitionImpl report = (ReportDefinitionImpl) super.clone();
report.rootGroup = (Group) rootGroup.clone();
report.pageFooter = (PageFooter) pageFooter.clone();
report.pageHeader = (PageHeader) pageHeader.clone();
report.reportFooter = (ReportFooter) reportFooter.clone();
report.reportHeader = (ReportHeader) reportHeader.clone();
report.watermark = (Watermark) watermark.clone();
// pagedefinition is not! cloned ...
report.pageDefinition = pageDefinition;
report.setParent( getParentSection() );
report.registerAsChild( report.rootGroup );
report.registerAsChild( report.reportHeader );
report.registerAsChild( report.reportFooter );
report.registerAsChild( report.pageHeader );
report.registerAsChild( report.pageFooter );
report.registerAsChild( report.watermark );
return report;
}
public ReportDefinitionImpl derive( final boolean preserveElementInstanceIds ) {
final ReportDefinitionImpl report = (ReportDefinitionImpl) super.derive( preserveElementInstanceIds );
report.rootGroup = (Group) rootGroup.derive( preserveElementInstanceIds );
report.pageFooter = (PageFooter) pageFooter.derive( preserveElementInstanceIds );
report.pageHeader = (PageHeader) pageHeader.derive( preserveElementInstanceIds );
report.reportFooter = (ReportFooter) reportFooter.derive( preserveElementInstanceIds );
report.reportHeader = (ReportHeader) reportHeader.derive( preserveElementInstanceIds );
report.watermark = (Watermark) watermark.derive( preserveElementInstanceIds );
// pagedefinition is not! cloned ...
report.pageDefinition = pageDefinition;
report.setParent( getParentSection() );
report.registerAsChild( report.rootGroup );
report.registerAsChild( report.reportHeader );
report.registerAsChild( report.reportFooter );
report.registerAsChild( report.pageHeader );
report.registerAsChild( report.pageFooter );
report.registerAsChild( report.watermark );
return report;
}
public Watermark getWatermark() {
return watermark;
}
public PageDefinition getPageDefinition() {
return pageDefinition;
}
/**
* Returns the currently assigned report definition.
*
* @return the report definition or null, if no report has been assigned.
*/
public ReportDefinition getReportDefinition() {
return this;
}
public ReportDefinition getMasterReport() {
if ( getElementType() instanceof MasterReportType ) {
return this;
}
return super.getMasterReport();
}
protected void removeElement( final Element element ) {
throw new UnsupportedOperationException(
"Method 'removeElement' is not supported in the read-only report-definition." );
}
public void setElementAt( final int position, final Element element ) {
throw new UnsupportedOperationException(
"Method 'removeElement' is not supported in the read-only report-definition." );
}
public int getElementCount() {
return 6;
}
public Element getElement( final int index ) {
switch ( index ) {
case 0:
return pageHeader;
case 1:
return reportHeader;
case 2:
return rootGroup;
case 3:
return reportFooter;
case 4:
return pageFooter;
case 5:
return watermark;
default:
throw new IndexOutOfBoundsException();
}
}
}