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