package org.pentaho.reporting.engine.classic.core.layout.process; import org.pentaho.reporting.engine.classic.core.layout.model.BlockRenderBox; import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox; import org.pentaho.reporting.engine.classic.core.layout.model.RenderNode; 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.model.table.rows.TableRowModel; import org.pentaho.reporting.engine.classic.core.layout.process.util.CacheBoxShifter; import org.pentaho.reporting.engine.classic.core.layout.process.util.StackedObjectPool; public class TableRowHeightApplyStep extends IterateStructuralProcessStep { private static class BoxContext { private BoxContextPool pool; private BoxContext parent; private long boxContextStart; private long boxCursor; private BoxContext() { } public void reuse( final BoxContextPool pool, final BoxContext parent, final RenderBox box ) { this.pool = pool; this.parent = parent; this.boxContextStart = box.getCachedY(); this.boxCursor = boxContextStart; } public BoxContext pop() { if ( parent != null ) { parent.boxCursor = boxCursor; } pool.free( this ); return parent; } public long getBoxCursor() { return boxCursor; } public void addBoxCursor( final long height ) { this.boxCursor += height; } } private class BoxContextPool extends StackedObjectPool<BoxContext> { private BoxContextPool() { } protected BoxContext create() { return new BoxContext(); } public BoxContext get( final BoxContext parent, final RenderBox box ) { BoxContext boxContext = super.get(); boxContext.reuse( this, parent, box ); return boxContext; } } private BoxContextPool pool; private BoxContext context; private TableRowModel rowModel; public TableRowHeightApplyStep() { pool = new BoxContextPool(); } public long start( TableSectionRenderBox section ) { try { context = pool.get( null, section ); rowModel = section.getRowModel(); processBoxChilds( section ); long usedTableBodyHeight = context.getBoxCursor() - context.boxContextStart; section.setCachedHeight( usedTableBodyHeight ); return usedTableBodyHeight; } finally { context = context.pop(); rowModel = null; } } protected void processOtherNode( final RenderNode node ) { node.setCachedY( context.getBoxCursor() ); context.addBoxCursor( node.getCachedHeight() ); } private void shiftBox( final RenderBox box ) { final long oldPosition = box.getCachedY(); final long position = context.getBoxCursor(); final long shift = position - oldPosition; if ( shift < 0 ) { throw new IllegalStateException( String.format( "Shift-back is not allowed: shift=%d: old=%d -> new=%d (%s)", shift, oldPosition, position, box ) ); } CacheBoxShifter.shiftBox( box, shift ); } protected boolean startTableRowBox( final TableRowRenderBox box ) { shiftBox( box ); context = pool.get( context, box ); return false; } protected void finishTableRowBox( final TableRowRenderBox box ) { final long validatedRowHeight = rowModel.getValidatedRowSize( box.getRowIndex() ); box.setCachedHeight( validatedRowHeight ); context.addBoxCursor( validatedRowHeight ); context = context.pop(); } protected boolean startTableSectionBox( final TableSectionRenderBox box ) { shiftBox( box ); context = pool.get( context, box ); return true; } protected void finishTableSectionBox( final TableSectionRenderBox box ) { context = context.pop(); } protected boolean startBlockBox( final BlockRenderBox box ) { shiftBox( box ); context = pool.get( context, box ); return true; } protected void finishBlockBox( final BlockRenderBox box ) { context = context.pop(); } protected boolean startAutoBox( final RenderBox box ) { shiftBox( box ); context = pool.get( context, box ); return true; } protected void finishAutoBox( final RenderBox box ) { RenderNode firstChild = box.getFirstChild(); if ( firstChild != null ) { RenderNode lastChild = box.getLastChild(); long height = lastChild.getCachedY2() - firstChild.getCachedY(); box.setCachedHeight( height ); } context = context.pop(); } protected boolean startOtherBox( final RenderBox box ) { return false; } protected void finishOtherBox( final RenderBox box ) { RenderNode firstChild = box.getFirstChild(); if ( firstChild != null ) { RenderNode lastChild = box.getLastChild(); long height = lastChild.getCachedY2() - firstChild.getCachedY(); box.setCachedHeight( height ); } } }