/*!
* 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) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.layout.build;
import org.pentaho.reporting.engine.classic.core.Band;
import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot;
import org.pentaho.reporting.engine.classic.core.IncompatibleFeatureException;
import org.pentaho.reporting.engine.classic.core.ReportAttributeMap;
import org.pentaho.reporting.engine.classic.core.ReportDefinition;
import org.pentaho.reporting.engine.classic.core.ReportElement;
import org.pentaho.reporting.engine.classic.core.filter.types.AutoLayoutBoxType;
import org.pentaho.reporting.engine.classic.core.layout.model.AutoRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.BlockRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.BreakMarkerRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.CanvasRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.InlineRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.LogicalPageBox;
import org.pentaho.reporting.engine.classic.core.layout.model.ParagraphRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderableReplacedContent;
import org.pentaho.reporting.engine.classic.core.layout.model.RenderableReplacedContentBox;
import org.pentaho.reporting.engine.classic.core.layout.model.RowRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.SectionRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.context.BoxDefinition;
import org.pentaho.reporting.engine.classic.core.layout.model.context.BoxDefinitionFactory;
import org.pentaho.reporting.engine.classic.core.layout.model.context.StaticBoxLayoutProperties;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableCellRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableColumnGroupNode;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableColumnNode;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableRowRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableSectionRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorFeature;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorMetaData;
import org.pentaho.reporting.engine.classic.core.layout.style.DefaultStyleCache;
import org.pentaho.reporting.engine.classic.core.layout.style.ManualBreakIndicatorStyleSheet;
import org.pentaho.reporting.engine.classic.core.layout.style.NonPaddingStyleCache;
import org.pentaho.reporting.engine.classic.core.layout.style.ParagraphPoolboxStyleSheet;
import org.pentaho.reporting.engine.classic.core.layout.style.SectionKeepTogetherStyleSheet;
import org.pentaho.reporting.engine.classic.core.layout.style.SimpleStyleSheet;
import org.pentaho.reporting.engine.classic.core.layout.style.StyleCache;
import org.pentaho.reporting.engine.classic.core.layout.style.UseMinChunkWidthStyleSheet;
import org.pentaho.reporting.engine.classic.core.metadata.ElementType;
import org.pentaho.reporting.engine.classic.core.states.ReportStateKey;
import org.pentaho.reporting.engine.classic.core.style.BandStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.util.InstanceID;
import org.pentaho.reporting.libraries.resourceloader.ResourceKey;
public class DefaultRenderNodeFactory implements RenderNodeFactory {
public static final String LAYOUT_PARAGRAPH_LINEBOX = "::paragraph-linebox";
private static StyleSheet SECTION_DEFAULT_STYLE = new SimpleStyleSheet( new UseMinChunkWidthStyleSheet( true ) );
private SimpleStyleSheet bandWithoutKeepTogetherStyle;
private BoxDefinitionFactory boxDefinitionFactory;
private StyleCache bandCache;
private SimpleStyleSheet manualBreakBoxStyle;
private boolean strictCompatibilityMode;
private OutputProcessorMetaData metaData;
public DefaultRenderNodeFactory() {
this.boxDefinitionFactory = new BoxDefinitionFactory();
this.bandWithoutKeepTogetherStyle = new SimpleStyleSheet( new SectionKeepTogetherStyleSheet( false ) );
}
public void initialize( final OutputProcessorMetaData metaData ) {
this.metaData = metaData;
this.bandCache = new DefaultStyleCache( "rnf" );
final boolean paddingsDisabled = metaData.isFeatureSupported( OutputProcessorFeature.DISABLE_PADDING );
if ( paddingsDisabled ) {
this.bandCache = new NonPaddingStyleCache( bandCache );
}
this.strictCompatibilityMode = metaData.isFeatureSupported( OutputProcessorFeature.STRICT_COMPATIBILITY );
}
public LogicalPageBox createPage( final ReportDefinition report, final StyleSheet style ) {
if ( report == null ) {
throw new NullPointerException();
}
final SimpleStyleSheet reportStyle = bandCache.getStyleSheet( style );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( reportStyle );
return new LogicalPageBox( report, reportStyle, boxDefinition );
}
public RenderBox produceSectionBox( final String layoutType, final ReportStateKey stateKey ) {
if ( strictCompatibilityMode ) {
final BoxDefinition boxDefinition = BoxDefinition.EMPTY;
return new SectionRenderBox( bandWithoutKeepTogetherStyle, new InstanceID(), boxDefinition,
AutoLayoutBoxType.INSTANCE, ReportAttributeMap.emptyMap(), stateKey );
}
final RenderBox renderBox =
createBox( layoutType, stateKey, SECTION_DEFAULT_STYLE, AutoLayoutBoxType.INSTANCE, ReportAttributeMap
.emptyMap(), new InstanceID() );
renderBox.getStaticBoxLayoutProperties().setPlaceholderBox( StaticBoxLayoutProperties.PlaceholderType.SECTION );
renderBox.getStaticBoxLayoutProperties().setSectionContext( true );
return renderBox;
}
public RenderBox produceRenderBox( final ReportElement band, final StyleSheet style, final String layoutType,
final ReportStateKey stateKey ) {
final ElementType elementType = band.getElementType();
final RenderBox box =
createBox( layoutType, stateKey, style, elementType, band.getAttributes(), band.getObjectID() );
// for the sake of debugging ..
final String name = band.getName();
if ( name != null && name.length() != 0 && name.startsWith( Band.ANONYMOUS_BAND_PREFIX ) == false ) {
box.setName( name );
}
return box;
}
private RenderBox createBox( final String layoutType, final ReportStateKey stateKey,
final StyleSheet elementStyleSheet, final ElementType elementType, final ReportAttributeMap attributes,
final InstanceID objectID ) {
if ( BandStyleKeys.LAYOUT_AUTO.equals( layoutType ) ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
return new AutoRenderBox( objectID, stateKey, styleSheet, attributes, elementType );
}
if ( BandStyleKeys.LAYOUT_BLOCK.equals( layoutType ) ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new BlockRenderBox( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
}
if ( LAYOUT_PARAGRAPH_LINEBOX.equals( layoutType ) ) {
// The non-inheritable styles will be applied to the auto-generated paragraph box. The inlinebox itself
// only receives the inheritable styles so that it can inherit it to its next child ..
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( new ParagraphPoolboxStyleSheet( elementStyleSheet ) );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new InlineRenderBox( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
} else if ( BandStyleKeys.LAYOUT_INLINE.equals( layoutType ) ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new InlineRenderBox( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
}
if ( BandStyleKeys.LAYOUT_ROW.equals( layoutType ) ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new RowRenderBox( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
}
if ( BandStyleKeys.LAYOUT_TABLE.equals( layoutType ) ) {
if ( strictCompatibilityMode ) {
throw new IncompatibleFeatureException( "A report with a legacy mode of pre-4.0 cannot handle table layouts. "
+ "Migrate your report to version 4.0 or higher.", ClassicEngineBoot.computeVersionId( 4, 0, 0 ) );
}
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new TableRenderBox( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
}
if ( BandStyleKeys.LAYOUT_TABLE_BODY.equals( layoutType ) || BandStyleKeys.LAYOUT_TABLE_HEADER.equals( layoutType )
|| BandStyleKeys.LAYOUT_TABLE_FOOTER.equals( layoutType ) ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new TableSectionRenderBox( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
}
if ( BandStyleKeys.LAYOUT_TABLE_ROW.equals( layoutType ) ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new TableRowRenderBox( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
}
if ( BandStyleKeys.LAYOUT_TABLE_CELL.equals( layoutType ) ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new TableCellRenderBox( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
}
if ( BandStyleKeys.LAYOUT_TABLE_COL.equals( layoutType ) ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new TableColumnNode( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
}
if ( BandStyleKeys.LAYOUT_TABLE_COL_GROUP.equals( layoutType ) ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
return new TableColumnGroupNode( styleSheet, attributes );
}
// assume 'Canvas' by default ..
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( elementStyleSheet );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
return new CanvasRenderBox( styleSheet, objectID, boxDefinition, elementType, attributes, stateKey );
}
@Deprecated
public RenderBox createAutoParagraph( final ReportStateKey stateKey ) {
return new ParagraphRenderBox( SimpleStyleSheet.EMPTY_STYLE, new InstanceID(), BoxDefinition.EMPTY,
AutoLayoutBoxType.INSTANCE, ReportAttributeMap.EMPTY_MAP, stateKey );
}
public RenderBox createAutoParagraph( final ReportElement band, final StyleSheet bandStyle,
final ReportStateKey stateKey ) {
final SimpleStyleSheet styleSheet = bandCache.getStyleSheet( bandStyle );
final BoxDefinition boxDefinition = boxDefinitionFactory.getBoxDefinition( styleSheet );
final ParagraphRenderBox paragraphBox =
new ParagraphRenderBox( styleSheet, band.getObjectID(), boxDefinition, band.getElementType(), band
.getAttributes(), stateKey );
paragraphBox.setName( band.getName() );
return paragraphBox;
}
public RenderBox produceSubReportPlaceholder( final ReportElement report, final StyleSheet style,
final ReportStateKey stateKey ) {
String layout;
if ( metaData.isFeatureSupported( OutputProcessorFeature.STRICT_COMPATIBILITY ) ) {
layout = BandStyleKeys.LAYOUT_BLOCK;
} else {
layout = (String) style.getStyleProperty( BandStyleKeys.LAYOUT, BandStyleKeys.LAYOUT_BLOCK );
// Todo: PRD-5172: Filter out inline subreports
if ( BandStyleKeys.LAYOUT_INLINE.equals( layout ) ) {
layout = BandStyleKeys.LAYOUT_BLOCK;
}
}
final RenderBox box =
createBox( layout, stateKey, style, report.getElementType(), report.getAttributes(), report.getObjectID() );
box.getStaticBoxLayoutProperties().setPlaceholderBox( StaticBoxLayoutProperties.PlaceholderType.COMPLEX );
box.markAsContentRefHolder();
// for the sake of debugging ..
final String name = report.getName();
if ( name != null && name.startsWith( Band.ANONYMOUS_BAND_PREFIX ) == false ) {
box.setName( name );
}
return box;
}
public BoxDefinition getBoxDefinition( final StyleSheet style ) {
return boxDefinitionFactory.getBoxDefinition( style );
}
public Object clone() {
try {
return super.clone();
} catch ( CloneNotSupportedException e ) {
throw new IllegalStateException( e );
}
}
public StyleSheet createAutoGeneratedSectionStyleSheet( final StyleSheet style ) {
return bandWithoutKeepTogetherStyle;
}
public RenderBox createPageBreakIndicatorBox( final ReportStateKey stateKey, final long range ) {
if ( this.manualBreakBoxStyle == null ) {
final ManualBreakIndicatorStyleSheet mbis = new ManualBreakIndicatorStyleSheet();
this.manualBreakBoxStyle = new SimpleStyleSheet( mbis );
}
final RenderBox sectionBox =
new BreakMarkerRenderBox( manualBreakBoxStyle, new InstanceID(), BoxDefinition.EMPTY,
AutoLayoutBoxType.INSTANCE, ReportAttributeMap.EMPTY_MAP, stateKey, range );
sectionBox.setName( "pagebreak" );
sectionBox.close();
return sectionBox;
}
public StyleSheet createStyle( final StyleSheet style ) {
return bandCache.getStyleSheet( style );
}
public void close() {
bandCache.printPerformanceStats();
}
public RenderableReplacedContentBox createReplacedContent( final ReportElement element, final StyleSheet style,
final Object value, final Object rawValue, final ReportStateKey stateKey ) {
final ResourceKey rawKey;
if ( rawValue instanceof ResourceKey ) {
rawKey = (ResourceKey) rawValue;
} else {
rawKey = null;
}
final SimpleStyleSheet elementStyle = bandCache.getStyleSheet( style );
final RenderableReplacedContent content = new RenderableReplacedContent( elementStyle, value, rawKey, metaData );
final BoxDefinition boxDefinition = getBoxDefinition( elementStyle );
final RenderableReplacedContentBox child =
new RenderableReplacedContentBox( elementStyle, element.getObjectID(), boxDefinition, element.getElementType(),
element.getAttributes(), stateKey, content );
child.setName( element.getName() );
return child;
}
}