/*! * 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.modules.output.table.base; import org.pentaho.reporting.engine.classic.core.layout.AbstractRenderer; import org.pentaho.reporting.engine.classic.core.layout.model.LogicalPageBox; import org.pentaho.reporting.engine.classic.core.layout.model.PageBreakPositionList; import org.pentaho.reporting.engine.classic.core.layout.output.ContentProcessingException; import org.pentaho.reporting.engine.classic.core.layout.output.IterativeOutputProcessor; import org.pentaho.reporting.engine.classic.core.layout.output.LayoutPagebreakHandler; import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessor; import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorFeature; import org.pentaho.reporting.engine.classic.core.layout.process.ApplyAutoCommitPageHeaderStep; import org.pentaho.reporting.engine.classic.core.layout.process.CleanPaginatedBoxesStep; import org.pentaho.reporting.engine.classic.core.layout.process.FillFlowPagesStep; import org.pentaho.reporting.engine.classic.core.layout.process.FlowPaginationStep; import org.pentaho.reporting.engine.classic.core.layout.process.util.PaginationResult; /** * This class exists only for driving the table-validation testcases. It is not a valid renderer and exhibits major * flaws if used elsewhere. You better do not use this outside the test-environment or evil aliens will kidnap you an * explain you in very detailed words what "Stay away from this class" really means. * * @author Thomas Morgner */ public class TableDebugRenderer extends AbstractRenderer { private FlowPaginationStep paginationStep; private FillFlowPagesStep fillPhysicalPagesStep; private CleanPaginatedBoxesStep cleanPaginatedBoxesStep; private ApplyAutoCommitPageHeaderStep applyAutoCommitPageHeaderStep; private int flowCount; private boolean pageStartPending; public TableDebugRenderer( final OutputProcessor outputProcessor ) { super( outputProcessor ); this.paginationStep = new FlowPaginationStep(); this.fillPhysicalPagesStep = new FillFlowPagesStep(); this.cleanPaginatedBoxesStep = new CleanPaginatedBoxesStep(); this.applyAutoCommitPageHeaderStep = new ApplyAutoCommitPageHeaderStep(); initialize(); } public int getPageCount() { return 0; } protected boolean isPageFinished() { final LogicalPageBox pageBox = getPageBox(); final PaginationResult pageBreak = paginationStep.performPagebreak( pageBox ); if ( pageBreak.isOverflow() || pageBox.isOpen() == false ) { setLastStateKey( pageBreak.getLastVisibleState() ); return true; } return false; } public void processIncrementalUpdate( final boolean performOutput ) throws ContentProcessingException { if ( isDirty() == false ) { return; } clearDirty(); final OutputProcessor outputProcessor = getOutputProcessor(); if ( outputProcessor instanceof IterativeOutputProcessor == false || outputProcessor.getMetaData().isFeatureSupported( OutputProcessorFeature.ITERATIVE_RENDERING ) == false ) { return; } final LogicalPageBox pageBox = getPageBox(); pageBox.setPageEnd( pageBox.getHeight() ); if ( pageBox.isOpen() ) { final IterativeOutputProcessor io = (IterativeOutputProcessor) outputProcessor; if ( applyAutoCommitPageHeaderStep.compute( pageBox ) ) { io.processIterativeContent( pageBox, performOutput ); } } } protected boolean performPagination( final LayoutPagebreakHandler layoutPagebreakHandler, final boolean performOutput ) throws ContentProcessingException { final OutputProcessor outputProcessor = getOutputProcessor(); // next: perform pagination. final LogicalPageBox pageBox = getPageBox(); final PaginationResult pageBreak = paginationStep.performPagebreak( pageBox ); if ( pageBreak.isOverflow() || pageBox.isOpen() == false ) { setLastStateKey( pageBreak.getLastVisibleState() ); setPagebreaks( getPagebreaks() + 1 ); pageBox.setAllVerticalBreaks( pageBreak.getAllBreaks() ); flowCount += 1; debugPrint( pageBox ); // A new page has been started. Recover the page-grid, then restart // everything from scratch. (We have to recompute, as the pages may // be different now, due to changed margins or page definitions) final long nextOffset = pageBox.computePageEnd(); pageBox.setPageEnd( nextOffset ); final long pageOffset = pageBox.getPageOffset(); if ( performOutput ) { if ( outputProcessor.isNeedAlignedPage() ) { final LogicalPageBox box = fillPhysicalPagesStep.compute( pageBox, pageOffset, nextOffset ); outputProcessor.processContent( box ); } else { outputProcessor.processContent( pageBox ); } } else { outputProcessor.processRecomputedContent( pageBox ); } // Now fire the pagebreak. This goes through all layers and informs all // components, that a pagebreak has been encountered and possibly a // new page has been set. It does not save the state or perform other // expensive operations. However, it updates the 'isPagebreakEncountered' // flag, which will be active until the input-feed received a new event. final boolean repeat = pageBox.isOpen() || pageBreak.isOverflow(); if ( repeat ) { // pageBox.setAllVerticalBreaks(pageBreak.getAllBreaks()); // First clean all boxes that have been marked as finished. This reduces the overall complexity of the // pagebox and improves performance on huge reports. cleanPaginatedBoxesStep.compute( pageBox ); pageBox.setPageOffset( nextOffset ); if ( pageBreak.isNextPageContainsContent() ) { if ( layoutPagebreakHandler != null ) { layoutPagebreakHandler.pageStarted(); } return true; } // No need to try again, we know that the result will not change, as the next page is // empty. (We already tested it.) pageStartPending = true; return false; } else { outputProcessor.processingFinished(); pageBox.setPageOffset( nextOffset ); return false; } } else if ( outputProcessor instanceof IterativeOutputProcessor && outputProcessor.getMetaData().isFeatureSupported( OutputProcessorFeature.ITERATIVE_RENDERING ) ) { processIncrementalUpdate( performOutput ); } return false; } public int getFlowCount() { return flowCount; } public boolean isCurrentPageEmpty() { // todo: Invent a test that checks whether the page is currently empty. final LogicalPageBox logicalPageBox = getPageBox(); final PageBreakPositionList breakPositionList = logicalPageBox.getAllVerticalBreaks(); final long masterBreak = breakPositionList.getLastMasterBreak(); final boolean nextPageContainsContent = ( logicalPageBox.getHeight() > masterBreak ); return nextPageContainsContent == false; } public boolean clearPendingPageStart( final LayoutPagebreakHandler layoutPagebreakHandler ) { if ( pageStartPending == false ) { return false; } if ( layoutPagebreakHandler != null ) { layoutPagebreakHandler.pageStarted(); } pageStartPending = false; return true; } public boolean isPageStartPending() { return pageStartPending; } }