/*
* 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) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.layout.model;
import org.pentaho.reporting.engine.classic.core.InvalidReportStateException;
import org.pentaho.reporting.engine.classic.core.ReportAttributeMap;
import org.pentaho.reporting.engine.classic.core.filter.types.AutoLayoutBoxType;
import org.pentaho.reporting.engine.classic.core.layout.model.context.BoxDefinition;
import org.pentaho.reporting.engine.classic.core.layout.model.context.StaticBoxLayoutProperties;
import org.pentaho.reporting.engine.classic.core.layout.process.CountBoxesStep;
import org.pentaho.reporting.engine.classic.core.layout.text.ExtendedBaselineInfo;
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.ElementStyleKeys;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.util.InstanceID;
/**
* Creation-Date: 03.04.2007, 13:17:47
*
* @author Thomas Morgner
*/
public abstract class RenderBox extends RenderNode {
public enum BreakIndicator {
NO_MANUAL_BREAK, DIRECT_MANUAL_BREAK, INDIRECT_MANUAL_BREAK
}
public enum RestrictFinishClearOut {
UNRESTRICTED, RESTRICTED, LEAF
}
protected static final int FLAG_BOX_TABLE_SECTION_RESERVED2 = 0x1000000;
protected static final int FLAG_BOX_TABLE_SECTION_RESERVED3 = 0x2000000;
protected static final int FLAG_BOX_TABLE_SECTION_RESERVED4 = 0x4000000;
protected static final int FLAG_BOX_TABLE_SECTION_RESERVED5 = 0x8000000;
protected static final int FLAG_BOX_INVALID_WIDOW_ORPHAN_NODE = 0x10000000;
protected static final int FLAG_BOX_CONTAINS_PRESERVED_CONTENT = 0x20000000;
private static final int FLAG_BOX_PREVENT_PAGINATION = 0x40000000;
private static final int FLAG_BOX_OPEN = 0x10000;
private static final int FLAG_BOX_MARKED_OPEN = 0x20000;
private static final int FLAG_BOX_APPLIED_OPEN = 0x40000;
protected static final int FLAG_BOX_TABLE_SECTION_RESERVED = 0x80000;
private static final int FLAG_BOX_MARKED_SEEN = 0x100000;
private static final int FLAG_BOX_APPLIED_SEEN = 0x200000;
private static final int FLAG_BOX_DEEP_FINISHED = 0x400000;
private static final int FLAG_BOX_CONTENT_REF_HOLDER = 0x800000;
private int contentRefCount;
private int tableRefCount;
private int descendantCount;
private int markedContentRefCount;
private int appliedContentRefCount;
private int orphanLeafCount;
private int widowLeafCount;
private BoxDefinition boxDefinition;
private StaticBoxLayoutProperties staticBoxLayoutProperties;
private RenderNode firstChildNode;
private RenderNode lastChildNode;
private Object rawValue;
private ExtendedBaselineInfo baselineInfo;
private String name;
private BreakIndicator breakIndicator;
private ReportStateKey stateKey;
private RenderBox textEllipseBox;
private Object tableExportState;
private Boolean contentBox;
private long staticBoxPropertiesAge;
private long tableValidationAge;
private long pinned;
private long appliedPinPosition;
private long markedPinPosition;
private long contentAreaX1;
private long contentAreaX2;
private long contentAge;
private long overflowAreaWidth;
private long overflowAreaHeight;
private long processKeyStepAge;
private ReportStateKey processKeyCached;
private boolean processKeyFinish;
private int processKeyContentRefCount;
/**
* Is the amount of space reserved for orphans beginning at the y-position of the box.
*/
private long orphanConstraintSize;
/**
* The amount of space reserved for widows, starting at the y2-positions of the box. If zero, the constraint points to
* y2.
*/
private long widowConstraintSize;
private long widowConstraintSizeWithKeepTogether;
private RestrictFinishClearOut restrictFinishClearOut;
private int parentWidowContexts;
protected RenderBox( final int majorAxis, final int minorAxis, final StyleSheet styleSheet,
final InstanceID instanceId, final BoxDefinition boxDefinition, final ElementType elementType,
final ReportAttributeMap attributes, final ReportStateKey stateKey ) {
super( majorAxis, minorAxis, styleSheet, instanceId, elementType, attributes );
if ( boxDefinition == null ) {
throw new NullPointerException();
}
if ( boxDefinition.isLocked() == false ) {
throw new InvalidReportStateException( "BoxDefinition must be read-only" );
}
this.pinned = -1;
this.tableValidationAge = -1;
this.boxDefinition = boxDefinition;
this.setOpen( true );
this.staticBoxLayoutProperties = new StaticBoxLayoutProperties();
this.staticBoxPropertiesAge = -1;
this.staticBoxLayoutProperties.setBreakAfter( getStyleSheet().getBooleanStyleProperty(
BandStyleKeys.PAGEBREAK_AFTER ) );
this.stateKey = stateKey;
this.descendantCount = 1;
this.restrictFinishClearOut = RestrictFinishClearOut.UNRESTRICTED;
this.breakIndicator = BreakIndicator.NO_MANUAL_BREAK;
}
public RenderBox create( final StyleSheet styleSheet ) {
final RenderBox b = (RenderBox) derive( false );
b.reinit( styleSheet, AutoLayoutBoxType.INSTANCE, ReportAttributeMap.EMPTY_MAP, new InstanceID() );
b.boxDefinition = BoxDefinition.EMPTY;
b.staticBoxLayoutProperties = new StaticBoxLayoutProperties();
b.staticBoxPropertiesAge = -1;
b.stateKey = null;
b.setOpen( true );
b.setMarkedOpen( false );
b.setMarkedSeen( false );
b.markedContentRefCount = 0;
b.setAppliedOpen( false );
b.setAppliedSeen( false );
b.appliedContentRefCount = 0;
b.contentAge = 0;
b.contentRefCount = 0;
b.breakIndicator = BreakIndicator.NO_MANUAL_BREAK;
b.staticBoxPropertiesAge = -1;
b.pinned = -1;
b.tableExportState = null;
b.setDeepFinished( false );
b.contentAreaX1 = 0;
b.contentAreaX2 = 0;
b.setContentRefHolder( false );
b.descendantCount = 1;
b.tableValidationAge = -1;
b.orphanConstraintSize = 0;
b.widowConstraintSize = 0;
b.widowConstraintSizeWithKeepTogether = 0;
b.restrictFinishClearOut = RestrictFinishClearOut.UNRESTRICTED;
b.parentWidowContexts = 0;
return b;
}
public void setParentWidowContexts( final int parentWidowContexts ) {
this.parentWidowContexts = parentWidowContexts;
}
public int getParentWidowContexts() {
return parentWidowContexts;
}
public int getDescendantCount() {
return descendantCount;
}
public boolean isContentRefHolder() {
return isFlag( FLAG_BOX_CONTENT_REF_HOLDER );
}
private void setContentRefHolder( final boolean flag ) {
setFlag( FLAG_BOX_CONTENT_REF_HOLDER, flag );
}
public void markAsContentRefHolder() {
if ( isContentRefHolder() ) {
throw new IllegalStateException();
}
setContentRefHolder( true );
increaseContentReferenceCount( 1, this );
}
public Object getRawValue() {
return rawValue;
}
public void setRawValue( final Object rawValue ) {
this.rawValue = rawValue;
}
public boolean isSizeSpecifiesBorderBox() {
return boxDefinition.isSizeSpecifiesBorderBox();
}
public RenderBox getTextEllipseBox() {
return textEllipseBox;
}
public void setTextEllipseBox( final RenderBox textEllipseBox ) {
this.textEllipseBox = textEllipseBox;
}
public ReportStateKey getStateKey() {
return stateKey;
}
protected void setStateKey( final ReportStateKey stateKey ) {
this.stateKey = stateKey;
}
public BreakIndicator getManualBreakIndicator() {
return breakIndicator;
}
public void setManualBreakIndicator( final BreakIndicator manualBreakIndicator ) {
this.breakIndicator = manualBreakIndicator;
}
public BoxDefinition getBoxDefinition() {
return boxDefinition;
}
public long getInsetsLeft() {
return staticBoxLayoutProperties.getBorderLeft() + boxDefinition.getPaddingLeft();
}
public long getInsetsRight() {
return staticBoxLayoutProperties.getBorderRight() + boxDefinition.getPaddingRight();
}
public long getEffectiveMinimumChunkSize() {
return getMinimumChunkWidth() + getInsets();
}
public long getInsets() {
return staticBoxLayoutProperties.getBorderLeft() + staticBoxLayoutProperties.getBorderRight()
+ boxDefinition.getPaddingLeft() + boxDefinition.getPaddingRight();
}
public RenderNode getFirstChild() {
return firstChildNode;
}
protected void setFirstChild( final RenderNode firstChild ) {
this.firstChildNode = firstChild;
if ( isParanoidModelChecks() && firstChild != null ) {
if ( firstChild.getPrev() != null ) {
throw new NullPointerException();
}
}
}
public RenderNode getLastChild() {
return lastChildNode;
}
protected void setLastChild( final RenderNode lastChild ) {
this.lastChildNode = lastChild;
if ( isParanoidModelChecks() && lastChild != null ) {
if ( lastChild.getNext() != null ) {
throw new NullPointerException();
}
}
}
public void addGeneratedChild( final RenderNode child ) {
if ( child == null ) {
throw new NullPointerException( "Child to be added must not be null." );
}
final RenderNode oldLastChild = getLastChild();
setLastChild( child );
if ( oldLastChild != null ) {
oldLastChild.setNext( child );
}
child.setParent( this );
child.setPrev( oldLastChild );
child.setNext( null );
final RenderNode oldFirstChild = getFirstChild();
if ( oldFirstChild == null ) {
setFirstChild( child );
}
if ( isFrozen() ) {
child.freeze();
}
child.updateChangeTracker();
onChildAdded( child );
validateDescendantCounter();
}
private void validateDescendantCounter() {
if ( isParanoidModelChecks() == false ) {
return;
}
final CountBoxesStep step = new CountBoxesStep();
final int count = step.countChildren( this );
if ( count != descendantCount ) {
throw new InvalidReportStateException( getClass().getSimpleName() + "(" + getName() + "): Counted boxes of "
+ count + " but claimed to have " + descendantCount );
}
}
public void addChild( final RenderNode child ) {
if ( child == null ) {
throw new NullPointerException( "Child to be added must not be null." );
}
if ( isOpen() == false ) {
throw new IllegalStateException( "Adding content to an already closed element: " + this );
}
if ( isParanoidModelChecks() ) {
if ( ( getLayoutNodeType() & LayoutNodeTypes.MASK_BOX_BLOCK ) == LayoutNodeTypes.MASK_BOX_BLOCK ) {
if ( ( child.getLayoutNodeType() & LayoutNodeTypes.MASK_BOX_INLINE ) == LayoutNodeTypes.MASK_BOX_INLINE ) {
throw new IllegalStateException(
"Paranoid Check: A block box cannot contain a inline box directly. They must be wrapped into a "
+ "paragraph." );
}
}
}
final RenderNode oldLastChild = getLastChild();
setLastChild( child );
if ( oldLastChild != null ) {
oldLastChild.setNext( child );
}
child.setParent( this );
child.setPrev( oldLastChild );
child.setNext( null );
final RenderNode oldFirstChild = getFirstChild();
if ( oldFirstChild == null ) {
setFirstChild( child );
}
if ( isFrozen() ) {
child.freeze();
}
child.updateChangeTracker();
onChildAdded( child );
validateDescendantCounter();
}
/**
* The content-ref-count counts inline-subreports or delayed-construction areas like crosstab-header.
*/
protected void increaseContentReferenceCount( final int count, final RenderNode source ) {
if ( count < 0 ) {
throw new IndexOutOfBoundsException();
}
if ( count == 0 ) {
return;
}
contentRefCount += count;
final RenderBox renderBox = getParent();
if ( renderBox != null ) {
renderBox.increaseContentReferenceCount( count, this );
}
}
/**
* The content-ref-count counts tables.
*/
protected void increaseTableReferenceCount( final int count, final RenderNode source ) {
if ( count < 0 ) {
throw new IndexOutOfBoundsException();
}
if ( count == 0 ) {
return;
}
tableRefCount += count;
final RenderBox renderBox = getParent();
if ( renderBox != null ) {
renderBox.increaseTableReferenceCount( count, this );
}
}
/**
* The content-ref-count counts inline-subreports.
*/
protected void increaseDescendantCount( final int count, final RenderNode source ) {
if ( count < 0 ) {
throw new IndexOutOfBoundsException();
}
if ( count == 0 ) {
return;
}
descendantCount += count;
final RenderBox renderBox = getParent();
if ( renderBox != null ) {
renderBox.increaseDescendantCount( count, this );
}
}
/**
* The content-ref-count counts inline-subreports.
*/
protected void decreaseContentReferenceCount( final int count, final RenderNode source ) {
if ( count < 0 ) {
throw new IndexOutOfBoundsException();
}
if ( count == 0 ) {
return;
}
if ( ( contentRefCount - count ) < 0 ) {
throw new IndexOutOfBoundsException( "New ContentRefCount would be negative" );
}
contentRefCount -= count;
final RenderBox renderBox = getParent();
if ( renderBox != null ) {
renderBox.decreaseContentReferenceCount( count, this );
}
}
/**
* The content-ref-count counts table-render-boxes.
*/
protected void decreaseTableReferenceCount( final int count, final RenderNode source ) {
if ( count < 0 ) {
throw new IndexOutOfBoundsException();
}
if ( count == 0 ) {
return;
}
if ( ( tableRefCount - count ) < 0 ) {
throw new IndexOutOfBoundsException( "New TableRefCount would be negative" );
}
tableRefCount -= count;
final RenderBox renderBox = getParent();
if ( renderBox != null ) {
renderBox.decreaseTableReferenceCount( count, this );
}
}
/**
* The content-ref-count counts table-render-boxes.
*/
protected void decreaseDescendantCount( final int count, final RenderNode source ) {
if ( count < 0 ) {
throw new IndexOutOfBoundsException();
}
if ( count == 0 ) {
return;
}
if ( ( descendantCount - count ) < 1 ) {
throw new IndexOutOfBoundsException( "New Descendant-Count would be negative. " + descendantCount + " - " + count );
}
descendantCount -= count;
final RenderBox renderBox = getParent();
if ( renderBox != null ) {
renderBox.decreaseDescendantCount( count, this );
}
}
/**
* The content-ref-count counts inline-subreports.
*/
public int getContentRefCount() {
return contentRefCount;
}
public int getTableRefCount() {
return tableRefCount;
}
public void replaceChild( final RenderNode old, final RenderNode replacement ) {
if ( old.getParent() != this ) {
throw new IllegalArgumentException( "None of my childs." );
}
if ( old == replacement ) {
// nothing to do ...
return;
}
final RenderNode oldFirstChild = getFirstChild();
if ( old == oldFirstChild ) {
setFirstChild( replacement );
}
final RenderNode oldLastChild = getLastChild();
if ( old == oldLastChild ) {
setLastChild( replacement );
}
final RenderNode prev = old.getPrev();
final RenderNode next = old.getNext();
replacement.setParent( this );
replacement.setPrev( prev );
replacement.setNext( next );
if ( prev != null ) {
prev.setNext( replacement );
}
if ( next != null ) {
next.setPrev( replacement );
}
old.setNext( null );
old.setPrev( null );
old.setParent( null );
old.updateChangeTracker();
onChildRemoved( old );
replacement.updateChangeTracker();
onChildAdded( replacement );
validateDescendantCounter();
if ( isParanoidModelChecks() ) {
if ( replacement.getNext() == null ) {
if ( getLastChild() != replacement ) {
throw new IllegalStateException();
}
}
}
}
public void replaceChilds( final RenderNode old, final RenderNode[] replacement ) {
if ( old.getParent() != this ) {
throw new IllegalArgumentException( "None of my childs." );
}
final int replacementCount = replacement.length;
if ( replacementCount == 0 ) {
throw new IndexOutOfBoundsException( "Array is empty .." );
}
if ( old == replacement[0] ) {
if ( replacementCount == 1 ) {
// nothing to do ...
return;
}
// throw new IllegalArgumentException
// ("Thou shall not use the replace method to insert new elements!");
}
final RenderNode oldPrev = old.getPrev();
final RenderNode oldNext = old.getNext();
old.setNext( null );
old.setPrev( null );
old.setParent( null );
// first, connect all replacements ...
RenderNode first = null;
RenderNode last = null;
for ( int i = 0; i < replacementCount; i++ ) {
if ( last == null ) {
last = replacement[i];
if ( last != null ) {
first = last;
first.setParent( this );
}
continue;
}
final RenderNode node = replacement[i];
last.setNextUnchecked( node );
node.setPrevUnchecked( last );
node.setParent( this );
last = node;
}
if ( first == null ) {
throw new IndexOutOfBoundsException( "Array is empty (NullValues stripped).." );
}
if ( old == getFirstChild() ) {
setFirstChild( first );
}
if ( old == getLastChild() ) {
setLastChild( last );
}
// Something inbetween ...
first.setPrev( oldPrev );
last.setNext( oldNext );
if ( oldPrev != null ) {
oldPrev.setNext( first );
}
if ( oldNext != null ) {
oldNext.setPrev( last );
}
old.updateChangeTracker();
onChildRemoved( old );
for ( int i = 0; i < replacementCount; i++ ) {
final RenderNode renderNode = replacement[i];
renderNode.updateChangeTracker();
onChildAdded( renderNode );
}
validateDescendantCounter();
}
private void onChildAdded( final RenderNode child ) {
increaseContentReferenceCount( child.getContentRefCount(), child );
increaseTableReferenceCount( child.getTableRefCount(), child );
increaseDescendantCount( child.getDescendantCount(), child );
}
private void onChildRemoved( final RenderNode old ) {
decreaseContentReferenceCount( old.getContentRefCount(), old );
decreaseTableReferenceCount( old.getTableRefCount(), old );
decreaseDescendantCount( old.getDescendantCount(), old );
}
/**
* Derive creates a disconnected node that shares all the properties of the original node. The derived node will no
* longer have any parent, sibling, child or any other relationships with other nodes.
*
* @return
*/
public RenderNode derive( final boolean deepDerive ) {
final RenderBox box = (RenderBox) super.derive( deepDerive );
if ( deepDerive ) {
RenderNode node = getFirstChild();
RenderNode currentNode = null;
while ( node != null ) {
final RenderNode previous = currentNode;
currentNode = node.derive( true );
currentNode.setParent( box );
if ( previous == null ) {
if ( isParanoidModelChecks() && currentNode.getPrev() != null ) {
throw new IllegalStateException();
}
box.setFirstChild( currentNode );
} else {
previous.setNext( currentNode );
currentNode.setPrev( previous );
}
node = node.getNext();
}
box.setLastChild( currentNode );
validateDescendantCounter();
if ( isParanoidModelChecks() && currentNode != null ) {
if ( currentNode.getNext() != null ) {
throw new IllegalStateException();
}
}
} else {
box.setLastChild( null );
box.setFirstChild( null );
box.contentRefCount = 0;
box.descendantCount = 1;
box.tableRefCount = 0;
}
return box;
}
/**
* Derive creates a disconnected node that shares all the properties of the original node. The derived node will no
* longer have any parent, silbling, child or any other relationships with other nodes.
*
* @return
*/
public RenderNode deriveFrozen( final boolean deepDerive ) {
final RenderBox box = (RenderBox) super.deriveFrozen( deepDerive );
if ( deepDerive ) {
RenderNode node = getFirstChild();
RenderNode currentNode = null;
while ( node != null ) {
final RenderNode previous = currentNode;
currentNode = node.deriveFrozen( true );
currentNode.setParent( box );
if ( previous == null ) {
if ( isParanoidModelChecks() && currentNode.getPrev() != null ) {
throw new IllegalStateException();
}
box.setFirstChild( currentNode );
} else {
previous.setNext( currentNode );
currentNode.setPrev( previous );
}
node = node.getNext();
}
box.setLastChild( currentNode );
validateDescendantCounter();
if ( isParanoidModelChecks() && currentNode != null ) {
if ( currentNode.getNext() != null ) {
throw new IllegalStateException();
}
}
} else {
box.setLastChild( null );
box.setFirstChild( null );
box.descendantCount = 1;
box.contentRefCount = 0;
box.tableRefCount = 0;
}
return box;
}
public void addChilds( final RenderNode[] nodes ) {
final int length = nodes.length;
for ( int i = 0; i < length; i++ ) {
addChild( nodes[i] );
}
}
public void addGeneratedChilds( final RenderNode[] nodes ) {
final int nodeLength = nodes.length;
for ( int i = 0; i < nodeLength; i++ ) {
addGeneratedChild( nodes[i] );
}
}
public RenderNode findNodeById( final InstanceID instanceId ) {
if ( instanceId == getInstanceId() ) {
return this;
}
RenderNode child = getLastChild();
while ( child != null ) {
final RenderNode nodeById = child.findNodeById( instanceId );
if ( nodeById != null ) {
return nodeById;
}
child = child.getPrev();
}
return null;
}
public boolean isAppendable() {
return isOpen();
}
/**
* Removes all children.
*/
public void clear() {
RenderNode child = getFirstChild();
while ( child != null ) {
final RenderNode nextChild = child.getNext();
child.setPrev( null );
child.setNext( null );
child.setParent( null );
onChildRemoved( child );
child = nextChild;
}
setFirstChild( null );
setLastChild( null );
updateChangeTracker();
validateDescendantCounter();
}
protected void updateChangeTracker() {
tableExportState = null;
super.updateChangeTracker();
}
private RenderNode getFirstNonEmpty() {
RenderNode firstChild = getFirstChild();
while ( firstChild != null ) {
if ( firstChild.isEmpty() == false ) {
return firstChild;
}
firstChild = firstChild.getNext();
}
return null;
}
public boolean isEmpty() {
if ( getBoxDefinition().isEmpty() == false ) {
return false;
}
final RenderNode node = getFirstNonEmpty();
if ( node != null ) {
return false;
}
// Ok, the childs were not able to tell us some truth ..
// lets try something else.
return true;
}
public boolean isDiscardable() {
if ( getBoxDefinition().isEmpty() == false ) {
return false;
}
if ( getStyleSheet().getStyleProperty( ElementStyleKeys.BACKGROUND_COLOR ) != null ) {
return false;
}
RenderNode node = getFirstChild();
while ( node != null ) {
if ( node.isDiscardable() == false ) {
return false;
}
node = node.getNext();
}
return true;
}
public void close() {
if ( isOpen() == false ) {
throw new IllegalStateException( "Double close.." );
}
this.setOpen( false );
if ( isContentRefHolder() ) {
decreaseContentReferenceCount( 1, this );
}
}
public void remove( final RenderNode child ) {
final RenderBox parent = child.getParent();
if ( parent != this ) {
throw new IllegalArgumentException( "None of my childs" );
}
final RenderNode prev = child.getPrev();
final RenderNode next = child.getNext();
if ( prev != null ) {
prev.setNext( next );
}
if ( next != null ) {
next.setPrev( prev );
}
child.setNext( null );
child.setPrev( null );
child.setParent( null );
onChildRemoved( child );
if ( getFirstChild() == child ) {
setFirstChild( next );
}
if ( getLastChild() == child ) {
setLastChild( prev );
}
child.updateChangeTracker();
updateChangeTracker();
validateDescendantCounter();
}
public boolean isOpen() {
return isFlag( FLAG_BOX_OPEN ) || contentRefCount > 0;
}
protected void setOpen( final boolean open ) {
if ( isOpen() == open ) {
return;
}
updateChangeTracker();
setFlag( FLAG_BOX_OPEN, open );
}
public void freeze() {
if ( isFrozen() ) {
return;
}
super.freeze();
RenderNode node = getFirstChild();
while ( node != null ) {
node.freeze();
node = node.getNext();
}
}
/**
* Performs a simple split. This box will be altered to form the left/top side of the split, and a derived empty box
* will be returned, which makes up the right/bottom side.
* <p/>
* A split will only happen on inline-boxes during the line-break-step. In the ordinary layouting, splitting is not
* necesary.
*
* @param axis
* @return
*/
public RenderBox split( final int axis ) {
final RenderBox otherBox = (RenderBox) derive( false );
if ( boxDefinition.isEmpty() == false ) {
final BoxDefinition[] boxDefinitions = boxDefinition.split( axis );
boxDefinition = boxDefinitions[0];
otherBox.boxDefinition = boxDefinitions[1];
}
return otherBox;
}
public long getContentAreaX1() {
return contentAreaX1;
}
public void setContentAreaX1( final long contentAreaX1 ) {
this.contentAreaX1 = contentAreaX1;
}
public long getContentAreaX2() {
return contentAreaX2;
}
public void setContentAreaX2( final long contentAreaX2 ) {
this.contentAreaX2 = contentAreaX2;
}
public StaticBoxLayoutProperties getStaticBoxLayoutProperties() {
return staticBoxLayoutProperties;
}
public ExtendedBaselineInfo getBaselineInfo() {
return baselineInfo;
}
public void setBaselineInfo( final ExtendedBaselineInfo baselineInfo ) {
this.baselineInfo = baselineInfo;
}
public String getName() {
return name;
}
public void setName( final String name ) {
this.name = name;
}
public boolean isBreakAfter() {
return staticBoxLayoutProperties.isBreakAfter();
}
public long getStaticBoxPropertiesAge() {
return staticBoxPropertiesAge;
}
public void setStaticBoxPropertiesAge( final long staticBoxPropertiesAge ) {
if ( staticBoxLayoutProperties.getNominalBaselineInfo() == null ) {
throw new IllegalStateException(
"Assertation: Cannot declare static-properties finished without a nominal baseline info" );
}
this.staticBoxPropertiesAge = staticBoxPropertiesAge;
}
public String toString() {
return getClass().getName() + '{' + "name='" + name + '\'' + ", x='" + getX() + '\'' + ", y='" + getY() + '\''
+ ", width='" + getWidth() + '\'' + ", height='" + getHeight() + '\'' + ", elementType='" + getElementType()
+ '\'' + ", finishedPaginate='" + isFinishedPaginate() + '\'' + ", finishedTable='" + isFinishedTable() + '\''
+ ", committed='" + isCommited() + '\'' + '}';
}
public void commit() {
appliedPinPosition = markedPinPosition;
appliedContentRefCount = markedContentRefCount;
setAppliedOpen( isMarkedOpen() );
setAppliedSeen( isMarkedSeen() );
validateDescendantCounter();
}
public int getAppliedContentRefCount() {
return appliedContentRefCount;
}
public boolean isAppliedOpen() {
return isFlag( FLAG_BOX_APPLIED_OPEN );
}
private void setAppliedOpen( final boolean flag ) {
setFlag( FLAG_BOX_APPLIED_OPEN, flag );
}
public boolean isAppliedSeen() {
return isFlag( FLAG_BOX_APPLIED_SEEN );
}
private void setAppliedSeen( final boolean flag ) {
setFlag( FLAG_BOX_APPLIED_SEEN, flag );
}
public boolean isMarkedOpen() {
return isFlag( FLAG_BOX_MARKED_OPEN );
}
private void setMarkedOpen( final boolean flag ) {
setFlag( FLAG_BOX_MARKED_OPEN, flag );
}
public boolean isMarkedSeen() {
return isFlag( FLAG_BOX_MARKED_SEEN );
}
private void setMarkedSeen( final boolean flag ) {
setFlag( FLAG_BOX_MARKED_SEEN, flag );
}
public void markBoxSeen() {
setMarkedOpen( isOpen() );
markedContentRefCount = contentRefCount;
setMarkedSeen( true );
markedPinPosition = pinned;
validateDescendantCounter();
}
public boolean isCommited() {
return isAppliedOpen() == false && isAppliedSeen() == true && appliedContentRefCount == 0;
}
public void rollback( final boolean deepDirty ) {
setOpen( isAppliedOpen() );
this.contentRefCount = appliedContentRefCount;
setMarkedOpen( isAppliedOpen() );
this.markedContentRefCount = appliedContentRefCount;
this.markedPinPosition = appliedPinPosition;
this.overflowAreaHeight = getCachedHeight();
this.overflowAreaWidth = 0;
// todo PRD-4606
resetCacheState( false );
validateDescendantCounter();
}
public void resetCacheState( final boolean deepDirty ) {
resetValidateModelResult();
setLinebreakAge( -1 );
setCachedAge( -1 );
if ( deepDirty ) {
updateCacheState( CACHE_DEEP_DIRTY );
} else {
updateCacheState( CACHE_DIRTY );
}
updateChangeTracker();
}
public boolean isDeepFinishedTable() {
return isFlag( FLAG_BOX_DEEP_FINISHED );
}
public void setDeepFinished( final boolean deepFinished ) {
setFlag( FLAG_BOX_DEEP_FINISHED, deepFinished );
}
public long getContentAge() {
return contentAge;
}
public void setContentAge( final long contentAge ) {
this.contentAge = contentAge;
}
public Boolean getContentBox() {
return contentBox;
}
public void setContentBox( final Boolean contentBox ) {
this.contentBox = contentBox;
}
public Object getTableExportState() {
return tableExportState;
}
public void setTableExportState( final Object tableExportState ) {
this.tableExportState = tableExportState;
}
public void markPinned( final long pinPosition ) {
if ( isPinned() ) {
return;
}
pinned = pinPosition;
final RenderBox renderBox = getParent();
if ( renderBox != null ) {
// Mark this box pinned at its currently layouted position.
renderBox.markPinned( renderBox.getY() );
}
}
public boolean isPinned() {
return pinned != -1;
}
public long getPinned() {
return pinned;
}
public void setMinimumChunkWidth( final long minimumChunkWidth ) {
super.setMinimumChunkWidth( minimumChunkWidth );
}
public boolean isBoxOverflowX() {
return staticBoxLayoutProperties.isOverflowX();
}
public boolean isBoxOverflowY() {
return staticBoxLayoutProperties.isOverflowY();
}
public boolean isEmptyNodesHaveSignificance() {
return getNodeLayoutProperties().getStyleSheet()
.getBooleanStyleProperty( ElementStyleKeys.INVISIBLE_CONSUMES_SPACE );
}
public boolean isAcceptInlineBoxes() {
return false;
}
public long getTableValidationAge() {
return tableValidationAge;
}
public void setTableValidationAge( final long tableValidationAge ) {
this.tableValidationAge = tableValidationAge;
}
public boolean useMinimumChunkWidth() {
return getStyleSheet().getBooleanStyleProperty( ElementStyleKeys.USE_MIN_CHUNKWIDTH );
}
public long getOverflowAreaHeight() {
return overflowAreaHeight;
}
public void setOverflowAreaHeight( final long overflowAreaHeight ) {
this.overflowAreaHeight = overflowAreaHeight;
}
public long getOverflowAreaWidth() {
return Math.max( getWidth(), overflowAreaWidth );
}
public void setOverflowAreaWidth( final long overflowAreaWidth ) {
this.overflowAreaWidth = overflowAreaWidth;
}
public void addOverflowArea( final long width, final long height ) {
if ( width > overflowAreaWidth ) {
setOverflowAreaWidth( width );
}
if ( height > overflowAreaHeight ) {
setOverflowAreaHeight( height );
}
}
public void apply() {
super.apply();
this.overflowAreaHeight = getCachedHeight();
this.staticBoxPropertiesAge = getChangeTracker();
this.tableValidationAge = getChangeTracker();
}
/**
* Notifies a box that one of its childs has extended its height. The child's height property already contains the new
* height. The <code>amount</code> given is the offset from the old height to the new height, and is always a positive
* number.
*
* @param child
* @param heightOffset
*/
public long extendHeight( final RenderNode child, final long heightOffset ) {
return extendHeightInBlockMode( child, heightOffset );
}
protected long extendHeightInBlockMode( final RenderNode child, final long heightOffset ) {
setHeight( getHeight() + heightOffset );
setOverflowAreaHeight( getOverflowAreaHeight() + heightOffset );
// updateCacheState(CACHE_DIRTY);
return heightOffset;
}
/**
* Match the y2 of the child with the y2 of the parent. If the box extends over the y2 of the parent, then extend the
* parent. If the parent has overflow-y, then we must not extend by more than heightOffset.
*
* @param child
* @param heightOffset
*/
protected long extendHeightInRowMode( final RenderNode child, final long heightOffset ) {
final long parentY2 = getY() + getHeight();
final long childY2 = child.getY() + child.getHeight();
final long deltaToBase = childY2 - parentY2;
if ( deltaToBase <= 0 ) {
// child expands without expanding this parent band. There was enough space available to contain the
// child inside the parent box.
return 0;
}
final long delta = Math.min( deltaToBase, heightOffset );
setHeight( getHeight() + delta );
setOverflowAreaHeight( getOverflowAreaHeight() + delta );
// updateCacheState(CACHE_DIRTY);
return delta;
}
public int getChildCount() {
int count = 0;
RenderNode next = firstChildNode;
while ( next != null ) {
count += 1;
next = next.getNext();
}
return count;
}
public long getOrphanConstraintSize() {
return orphanConstraintSize;
}
public void setOrphanConstraintSize( final long orphanConstraintSize ) {
this.orphanConstraintSize = orphanConstraintSize;
}
public long getWidowConstraintSize() {
return widowConstraintSize;
}
public void setWidowConstraintSize( final long widowConstraintSize ) {
this.widowConstraintSize = widowConstraintSize;
}
public long getWidowConstraintSizeWithKeepTogether() {
return widowConstraintSizeWithKeepTogether;
}
public void setWidowConstraintSizeWithKeepTogether( final long widowConstraintSizeWithKeepTogether ) {
this.widowConstraintSizeWithKeepTogether = widowConstraintSizeWithKeepTogether;
}
public boolean isInvalidWidowOrphanNode() {
return isFlag( FLAG_BOX_INVALID_WIDOW_ORPHAN_NODE );
}
public void setInvalidWidowOrphanNode( final boolean invalidWidowOrphanNode ) {
setFlag( FLAG_BOX_INVALID_WIDOW_ORPHAN_NODE, invalidWidowOrphanNode );
}
public RestrictFinishClearOut getRestrictFinishedClearOut() {
return restrictFinishClearOut;
}
public void setRestrictFinishedClearOut( final RestrictFinishClearOut restrictFinishedClearOut ) {
if ( this.restrictFinishClearOut == restrictFinishedClearOut ) {
return;
}
this.restrictFinishClearOut = restrictFinishedClearOut;
final RenderBox parent = getParent();
// only propagate across block-elements. Canvas, Inline or row-elements do not carry
// the pagebreak-restrictions upwards.
if ( parent != null && parent.isBlockForPagebreakPurpose()
&& restrictFinishedClearOut != RestrictFinishClearOut.UNRESTRICTED ) {
parent.setRestrictFinishedClearOut( RestrictFinishClearOut.RESTRICTED );
}
}
protected boolean isBlockForPagebreakPurpose() {
return false;
}
public boolean isOrphanLeaf() {
return this.restrictFinishClearOut == RestrictFinishClearOut.LEAF;
}
public long getVerticalInsets() {
final long insetBottom = staticBoxLayoutProperties.getBorderBottom() + boxDefinition.getPaddingBottom();
final long insetTop = staticBoxLayoutProperties.getBorderTop() + boxDefinition.getPaddingTop();
return insetBottom + insetTop;
}
public boolean isContainsReservedContent() {
return isFlag( FLAG_BOX_CONTAINS_PRESERVED_CONTENT );
}
public void setContainsReservedContent( final boolean containsReservedContent ) {
setFlag( FLAG_BOX_CONTAINS_PRESERVED_CONTENT, containsReservedContent );
}
public boolean isPreventPagination() {
return isFlag( FLAG_BOX_PREVENT_PAGINATION );
}
public void setPreventPagination( final boolean preventPagination ) {
setFlag( FLAG_BOX_PREVENT_PAGINATION, preventPagination );
updateChangeTracker();
}
public boolean isRenderBox() {
return true;
}
public void setProcessKeyCached( final ReportStateKey processKeyCached ) {
this.processKeyStepAge = getChangeTracker();
this.processKeyCached = processKeyCached;
this.processKeyFinish = isFinishedPaginate();
this.processKeyContentRefCount = getDescendantCount();
}
public long getProcessKeyStepAge() {
return processKeyStepAge;
}
public ReportStateKey getProcessKeyCached() {
return processKeyCached;
}
public boolean isProcessKeyFinish() {
return processKeyFinish;
}
public boolean isProcessKeyCacheValid() {
if ( processKeyCached == null ) {
return false;
}
if ( getContentRefCount() != 0 ) {
// subreport content cannot be cached ..
return false;
}
return ( getProcessKeyStepAge() == getChangeTracker() && isProcessKeyFinish() == isFinishedPaginate() && this.processKeyContentRefCount == getDescendantCount() );
}
public int getOrphanLeafCount() {
return orphanLeafCount;
}
public void setOrphanLeafCount( final int orphanLeafCount ) {
this.orphanLeafCount = orphanLeafCount;
}
public int getWidowLeafCount() {
return widowLeafCount;
}
public void setWidowLeafCount( final int widowLeafCount ) {
this.widowLeafCount = widowLeafCount;
}
}