/*! * 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; } }