net.sf.jasperreports.engine.fill.JRFillFrame Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jasperreports Show documentation
Show all versions of jasperreports Show documentation
Free Java Reporting Library
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2022 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see .
*/
package net.sf.jasperreports.engine.fill;
import java.awt.Color;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.jasperreports.engine.JRChild;
import net.sf.jasperreports.engine.JRElement;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpressionCollector;
import net.sf.jasperreports.engine.JRFrame;
import net.sf.jasperreports.engine.JRLineBox;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRStyle;
import net.sf.jasperreports.engine.JRVisitor;
import net.sf.jasperreports.engine.base.JRBaseElementGroup;
import net.sf.jasperreports.engine.type.BorderSplitType;
import net.sf.jasperreports.engine.type.ModeEnum;
import net.sf.jasperreports.engine.util.ElementsVisitorUtils;
import net.sf.jasperreports.engine.util.JRBoxUtil;
import net.sf.jasperreports.engine.util.StyleUtil;
/**
* Fill time implementation of a frame element.
*
* @author Lucian Chirita ([email protected])
*/
public class JRFillFrame extends JRFillElement implements JRFrame
{
protected final JRFrame parentFrame;
protected final JRLineBox lineBox;
protected final BorderSplitType borderSplitType;
protected final boolean widthStretchEnabled;
/**
* Element container used for filling.
*/
private JRFillFrameElements frameContainer;
/**
* Template frame without the bottom border.
*/
private Map bottomTemplateFrames;
/**
* Template frame without the top border
*/
private Map topTemplateFrames;
/**
* Template frame without the top and bottom borders
*/
private Map topBottomTemplateFrames;
private boolean fillTopBorder;
private boolean fillBottomBorder;
/**
* Whether the frame has started filling and not ended.
*/
private boolean filling;
private JRLineBox styleLineBox;
public JRFillFrame(JRBaseFiller filler, JRFrame frame, JRFillObjectFactory factory)
{
super(filler, frame, factory);
parentFrame = frame;
lineBox = frame.getLineBox().clone(this);
borderSplitType = initBorderSplitType(filler, frame);
widthStretchEnabled = initWidthStretchEnabled(filler, frame);
frameContainer = new JRFillFrameElements(factory);
bottomTemplateFrames = new HashMap<>();
topTemplateFrames = new HashMap<>();
topBottomTemplateFrames = new HashMap<>();
setShrinkable(true);
}
protected JRFillFrame(JRFillFrame frame, JRFillCloneFactory factory)
{
super(frame, factory);
parentFrame = frame.parentFrame;
lineBox = frame.getLineBox().clone(this);
borderSplitType = frame.borderSplitType;
widthStretchEnabled = frame.widthStretchEnabled;
frameContainer = new JRFillFrameElements(frame.frameContainer, factory);
bottomTemplateFrames = frame.bottomTemplateFrames;
topTemplateFrames = frame.topTemplateFrames;
topBottomTemplateFrames = frame.topBottomTemplateFrames;
}
private BorderSplitType initBorderSplitType(JRBaseFiller filler, JRFrame frame)
{
BorderSplitType splitType = frame.getBorderSplitType();
if (splitType == null)
{
String splitTypeProp = filler.getPropertiesUtil().getProperty(filler.getJasperReport(), PROPERTY_BORDER_SPLIT_TYPE); // property expression does not work,
// but even if we would call filler.getMainDataset(), it would be too early as it is null here for frame elements placed in group bands
if (splitTypeProp != null)
{
splitType = BorderSplitType.byName(splitTypeProp);
}
}
return splitType;
}
private boolean initWidthStretchEnabled(JRBaseFiller filler, JRFrame frame)
{
boolean stretchDisabled = filler.getPropertiesUtil().getBooleanProperty(
PROPERTY_FRAME_WIDTH_STRETCH_DISABLED, false,
frame, filler.getJasperReport());
return !stretchDisabled;
}
@Override
public ModeEnum getModeValue()
{
return getStyleResolver().getMode(this, ModeEnum.TRANSPARENT);
}
@Override
public Color getDefaultLineColor()
{
return getForecolor();
}
@Override
protected void evaluate(byte evaluation) throws JRException
{
reset();
evaluatePrintWhenExpression(evaluation);
if (isPrintWhenExpressionNull() || isPrintWhenTrue())
{
evaluateProperties(evaluation);
evaluateStyle(evaluation);
frameContainer.evaluate(evaluation);
boolean repeating = true;
JRFillElement[] elements = (JRFillElement[]) getElements();
for (int i = 0; repeating && i < elements.length; i++)
{
repeating &= elements[i].isValueRepeating();
}
setValueRepeating(repeating);
}
filling = false;
}
@Override
protected void evaluateStyle(byte evaluation) throws JRException
{
super.evaluateStyle(evaluation);
styleLineBox = null;
if (providerStyle != null)
{
styleLineBox = lineBox.clone(this);
StyleUtil.appendBox(styleLineBox, providerStyle.getLineBox());
}
}
@Override
protected void rewind() throws JRException
{
frameContainer.rewind();
filling = false;
}
protected boolean drawTopBorderOnSplit()
{
return borderSplitType == BorderSplitType.DRAW_BORDERS;
}
protected boolean drawBotomBorderOnSplit()
{
return borderSplitType == BorderSplitType.DRAW_BORDERS;
}
@Override
protected boolean prepare(int availableHeight, boolean isOverflow) throws JRException
{
super.prepare(availableHeight, isOverflow);
if (!isToPrint())
{
return false;
}
// whether the current frame chunk is the first one.
boolean first = !isOverflow || !filling;
int topPadding = getLineBox().getTopPadding();
int bottomPadding = getLineBox().getBottomPadding();
if (availableHeight < getRelativeY() + getHeight() - topPadding - bottomPadding)
{
setToPrint(false);
return true;
}
if (!filling && !isPrintRepeatedValues() && isValueRepeating() &&
(!isPrintInFirstWholeBand() || !getBand().isFirstWholeOnPageColumn()) &&
(getPrintWhenGroupChanges() == null || !getBand().isNewGroup(getPrintWhenGroupChanges())) &&
(!isOverflow || !isPrintWhenDetailOverflows())
)
{
setToPrint(false);
return false;
}
// FIXME reprinted when isAlreadyPrinted() || !isPrintRepeatedValues()?
if (!filling && isOverflow && isAlreadyPrinted())
{
if (isPrintWhenDetailOverflows())
{
rewind();
setReprinted(true);
}
else
{
setToPrint(false);
return false;
}
}
frameContainer.initFill();
frameContainer.resetElements();
frameContainer.prepareElements(availableHeight - getRelativeY() - topPadding - bottomPadding, true);
boolean willOverflow = frameContainer.willOverflow();
fillTopBorder = first || drawTopBorderOnSplit();
fillBottomBorder = !willOverflow || drawBotomBorderOnSplit();
if (willOverflow)
{
setPrepareHeight(availableHeight - getRelativeY());
}
else
{
int neededStretch = frameContainer.getStretchHeight() - frameContainer.getFirstY() + topPadding + bottomPadding;
if (neededStretch <= availableHeight - getRelativeY())
{
setPrepareHeight(neededStretch);
}
else
{
//FIXME is this case possible?
setPrepareHeight(availableHeight - getRelativeY());
}
}
filling = willOverflow;
return willOverflow;
}
@Override
protected void setStretchHeight(int stretchHeight)
{
super.setStretchHeight(stretchHeight);
int topPadding = getLineBox().getTopPadding();
int bottomPadding = getLineBox().getBottomPadding();
frameContainer.setStretchHeight(stretchHeight + frameContainer.getFirstY() - topPadding - bottomPadding);
}
/**
* @deprecated To be removed.
*/
@Override
protected void stretchHeightFinal()
{
// only do this if the frame is printing
if (isToPrint())
{
frameContainer.stretchElements();
frameContainer.moveBandBottomElements();
frameContainer.removeBlankElements();
int topPadding = getLineBox().getTopPadding();
int bottomPadding = getLineBox().getBottomPadding();
super.setStretchHeight(frameContainer.getStretchHeight() - frameContainer.getFirstY() + topPadding + bottomPadding);
}
}
@Override
protected boolean stretchElementToHeight(int stretchHeight)
{
boolean applied = super.stretchElementToHeight(stretchHeight);
if (applied)
{
frameContainer.stretchElementsToContainer();
frameContainer.moveBandBottomElements();
}
return applied;
}
@Override
protected JRPrintElement fill() throws JRException
{
JRTemplatePrintFrame printFrame = new JRTemplatePrintFrame(getTemplate(), printElementOriginator);
printFrame.setUUID(getUUID());
printFrame.setX(getX());
printFrame.setY(getRelativeY());
VirtualizableFrame virtualizableFrame = new VirtualizableFrame(printFrame,
filler.getVirtualizationContext(), filler.getCurrentPage());
frameContainer.fillElements(virtualizableFrame);
virtualizableFrame.fill();
int width = getWidth();
if (widthStretchEnabled)
{
JRLineBox printBox = printFrame.getLineBox();
int padding = (printBox.getLeftPadding() == null ? 0 : printBox.getLeftPadding())
+ (printBox.getRightPadding() == null ? 0 : printBox.getRightPadding());
if (virtualizableFrame.getContentsWidth() + padding > width)
{
width = virtualizableFrame.getContentsWidth() + padding;
}
}
printFrame.setWidth(width);
printFrame.setHeight(getStretchHeight());
transferProperties(printFrame);
return printFrame;
}
protected JRTemplateFrame getTemplate()
{
JRStyle style = getStyle();
Map templatesMap;
if (fillTopBorder)
{
if (fillBottomBorder)
{
templatesMap = templates;
}
else //remove the bottom border
{
templatesMap = bottomTemplateFrames;
}
}
else
{
if (fillBottomBorder) //remove the top border
{
templatesMap = topTemplateFrames;
}
else //remove the top and bottom borders
{
templatesMap = topBottomTemplateFrames;
}
}
JRTemplateFrame boxTemplate = (JRTemplateFrame) templatesMap.get(style);
if (boxTemplate == null)
{
boxTemplate = createFrameTemplate();
transferProperties(boxTemplate);
//FIXME up to revision 2006 (Dec 5 2007) we were resetting both the border and the padding.
// now we are only resetting the border and not the padding, prepare() assumes that the top and bottom paddings are always used.
if (fillTopBorder)
{
if (!fillBottomBorder) //remove the bottom border
{
boxTemplate.copyBox(getLineBox());
JRBoxUtil.reset(boxTemplate.getLineBox(), false, false, false, true);
}
}
else
{
if (fillBottomBorder) //remove the top border
{
boxTemplate.copyBox(getLineBox());
JRBoxUtil.reset(boxTemplate.getLineBox(), false, false, true, false);
}
else //remove the top and bottom borders
{
boxTemplate.copyBox(getLineBox());
JRBoxUtil.reset(boxTemplate.getLineBox(), false, false, true, true);
}
}
boxTemplate = filler.fillContext.deduplicate(boxTemplate);
templatesMap.put(style, boxTemplate);
}
return boxTemplate;
}
protected JRTemplateFrame createFrameTemplate()
{
return new JRTemplateFrame(getElementOrigin(),
filler.getJasperPrint().getDefaultStyleProvider(), this);
}
@Override
protected JRTemplateElement createElementTemplate()
{
return createFrameTemplate();
}
@Override
protected void resolveElement(JRPrintElement element, byte evaluation)
{
// nothing
}
@Override
public JRElement[] getElements()
{
return frameContainer.getElements();
}
@Override
public List getChildren()
{
return frameContainer.getChildren();
}
@Override
public void collectExpressions(JRExpressionCollector collector)
{
collector.collect(this);
}
@Override
public JRLineBox getLineBox()
{
return styleLineBox == null ? lineBox : styleLineBox;
}
@Override
public BorderSplitType getBorderSplitType()
{
return borderSplitType;
}
@Override
public void visit(JRVisitor visitor)
{
visitor.visitFrame(this);
if (ElementsVisitorUtils.visitDeepElements(visitor))
{
ElementsVisitorUtils.visitElements(visitor, getChildren());
}
}
@Override
public JRElement getElementByKey(String key)
{
return JRBaseElementGroup.getElementByKey(getElements(), key);
}
@Override
public JRFillCloneable createClone(JRFillCloneFactory factory)
{
return new JRFillFrame(this, factory);
}
/**
* Frame element container filler.
*/
protected class JRFillFrameElements extends JRFillElementContainer
{
JRFillFrameElements(JRFillObjectFactory factory)
{
super(JRFillFrame.this.filler, parentFrame, factory);
initElements();
}
JRFillFrameElements(JRFillFrameElements frameElements, JRFillCloneFactory factory)
{
super(frameElements, factory);
initElements();
}
@Override
protected int getContainerHeight()
{
return JRFillFrame.this.getHeight() - getLineBox().getTopPadding() - getLineBox().getBottomPadding();
}
@Override
protected int getActualContainerHeight()
{
int containerHeight = JRFillFrame.this.getHeight() - getLineBox().getTopPadding() - getLineBox().getBottomPadding();
if (JRFillFrame.this.frameContainer.bottomElementInGroup != null)
{
if (
getLineBox().getTopPadding()
+ JRFillFrame.this.frameContainer.bottomElementInGroup.getY()
+ JRFillFrame.this.frameContainer.bottomElementInGroup.getHeight() > JRFillFrame.this.getHeight()
)
{
containerHeight =
JRFillFrame.this.frameContainer.bottomElementInGroup.getY()
+ JRFillFrame.this.frameContainer.bottomElementInGroup.getHeight();
}
}
return containerHeight;
}
@Override
public boolean isSplitTypePreventInhibited(boolean isTopLevelCall)
{
//not actually called because fillContainerContext in the children is actually the band
return JRFillFrame.this.fillContainerContext.isSplitTypePreventInhibited(isTopLevelCall);
}
}
}