/*! * 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.designer.core.editor.report.layouting; import org.pentaho.reporting.designer.core.editor.ReportRenderContext; import org.pentaho.reporting.designer.core.util.BreakPositionsList; import org.pentaho.reporting.designer.core.util.exceptions.UncaughtExceptionsModel; import org.pentaho.reporting.engine.classic.core.Element; import org.pentaho.reporting.engine.classic.core.IncompatibleFeatureException; import org.pentaho.reporting.engine.classic.core.MasterReport; import org.pentaho.reporting.engine.classic.core.ReportProcessingException; import org.pentaho.reporting.engine.classic.core.Section; import org.pentaho.reporting.engine.classic.core.layout.model.LogicalPageBox; import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorMetaData; import org.pentaho.reporting.engine.classic.core.modules.output.table.base.SheetLayout; import org.pentaho.reporting.engine.classic.core.modules.output.table.base.TableLayoutProducer; import org.pentaho.reporting.engine.classic.core.util.InstanceID; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; import java.awt.geom.Rectangle2D; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * @author Thomas Morgner */ public class SharedElementRenderer { private final ReportLayouter reportLayouter; private final MasterReport masterReport; private long minimumVersionNeeded; private EventListenerList listenerList; private LogicalPageBox pageBox; private TransferGlobalLayoutProcessStep transferGlobalLayoutProcessor; private TransferLayoutProcessStep transferLayoutProcessor; private Map<InstanceID, Set<InstanceID>> conflicts; private long layoutAge; private boolean lastResult; private boolean warnMigration; private TableLayoutProducer tableLayoutProducer; private DesignerTableContentProducer tableContentProducer; public SharedElementRenderer( final ReportRenderContext reportRenderContext ) { if ( reportRenderContext == null ) { throw new NullPointerException(); } this.masterReport = reportRenderContext.getMasterReportElement(); if ( this.masterReport == null ) { throw new NullPointerException(); } this.warnMigration = true; this.reportLayouter = new ReportLayouter( reportRenderContext ); this.listenerList = new EventListenerList(); this.transferGlobalLayoutProcessor = new TransferGlobalLayoutProcessStep(); this.transferLayoutProcessor = new TransferLayoutProcessStep(); this.conflicts = new HashMap<InstanceID, Set<InstanceID>>(); this.minimumVersionNeeded = -1; } public void addChangeListener( final ChangeListener changeListener ) { listenerList.add( ChangeListener.class, changeListener ); } public void removeChangeListener( final ChangeListener changeListener ) { listenerList.remove( ChangeListener.class, changeListener ); } public void fireChangeEvent() { final ChangeEvent ce = new ChangeEvent( this ); final ChangeListener[] changeListeners = listenerList.getListeners( ChangeListener.class ); for ( int i = 0; i < changeListeners.length; i++ ) { final ChangeListener listener = changeListeners[ i ]; listener.stateChanged( ce ); } } protected OutputProcessorMetaData getOutputProcessorMetaData() { return reportLayouter.getOutputProcessorMetaData(); } public boolean isLayoutValid() { return ( this.layoutAge == masterReport.getChangeTracker() ); } public boolean performLayouting() { if ( this.isLayoutValid() ) { return lastResult; } try { this.pageBox = reportLayouter.layout(); } catch ( final Exception e ) { //noinspection ThrowableInstanceNeverThrown UncaughtExceptionsModel.getInstance().addException( new ReportProcessingException ( "Fatal Layouter Error: This report cannot be processed due to a unrecoverable error in the reporting-engine. " + "Please file a bug-report.", e ) ); if ( warnMigration ) { @SuppressWarnings( "ThrowableResultOfMethodCallIgnored" ) final IncompatibleFeatureException ife = extractIncompatibleFeatureException( e ); if ( ife != null ) { minimumVersionNeeded = ife.getMinimumVersionNeeded(); } warnMigration = false; } pageBox = null; } transferGlobalLayoutProcessor.reset(); try { if ( pageBox != null ) { final OutputProcessorMetaData outputProcessorMetaData = getOutputProcessorMetaData(); if ( tableLayoutProducer == null ) { tableLayoutProducer = new TableLayoutProducer( outputProcessorMetaData ); tableLayoutProducer.setProcessWatermark( false ); } else { tableLayoutProducer.clear(); } // we need to work on a copy here, as the layout computation marks boxes as finished to keep track // of the progress. tableLayoutProducer.update( pageBox, false ); if ( tableContentProducer == null ) { tableContentProducer = new DesignerTableContentProducer( tableLayoutProducer.getLayout(), outputProcessorMetaData ); } else { tableContentProducer.reset( tableLayoutProducer.getLayout() ); } conflicts.clear(); conflicts = tableContentProducer.computeConflicts( pageBox, conflicts ); // watermark needs extra pass, or it will produce bogus warnings. tableLayoutProducer.computeDesigntimeConflicts( pageBox.getWatermarkArea() ); final SheetLayout watermarkLayout = tableLayoutProducer.getLayout(); tableContentProducer.reset( watermarkLayout ); conflicts = tableContentProducer.computeWatermarkConflics( pageBox, conflicts ); transferGlobalLayoutProcessor.performTransfer( pageBox, conflicts, masterReport ); } lastResult = true; layoutAge = masterReport.getChangeTracker(); fireChangeEvent(); return true; } catch ( Exception e ) { UncaughtExceptionsModel.getInstance().addException( e ); lastResult = false; layoutAge = masterReport.getChangeTracker(); fireChangeEvent(); return false; } } public long getMinimumVersionNeeded() { return minimumVersionNeeded; } public boolean isMigrationError() { return minimumVersionNeeded != -1; } public void clearMigrationError() { minimumVersionNeeded = -1; } private IncompatibleFeatureException extractIncompatibleFeatureException( Throwable e ) { while ( e != null ) { if ( e instanceof IncompatibleFeatureException ) { return (IncompatibleFeatureException) e; } if ( e == e.getCause() ) { return null; } e = e.getCause(); } return null; } public void transferLocalLayout( final Section section, final Map<InstanceID, Element> elementsById, final BreakPositionsList verticalEdgePositions ) { elementsById.clear(); verticalEdgePositions.clear(); if ( pageBox != null ) { transferLayoutProcessor.performTransfer( section, pageBox, elementsById, verticalEdgePositions ); } } public Map<InstanceID, Element> getElementsById() { return transferGlobalLayoutProcessor.getElementsById(); } public Map<InstanceID, Set<InstanceID>> getConflicts() { return conflicts; } public BreakPositionsList getHorizontalEdgePositions() { return transferGlobalLayoutProcessor.getHorizontalEdgePositions(); } public ReportLayouter getLayouter() { return reportLayouter; } public LogicalPageBox getPageBox() { return pageBox; } public Rectangle2D getFallbackBounds() { return new Rectangle2D.Float( 0, 0, masterReport.getPageDefinition().getWidth(), 0 ); } }