/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2009 Jaspersoft Corporation. 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 <http://www.gnu.org/licenses/>.
*/
package net.sf.jasperreports.engine.fill;
import java.awt.Color;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.sf.jasperreports.crosstabs.JRCellContents;
import net.sf.jasperreports.crosstabs.fill.JRFillCrosstabObjectFactory;
import net.sf.jasperreports.crosstabs.type.CrosstabColumnPositionEnum;
import net.sf.jasperreports.crosstabs.type.CrosstabRowPositionEnum;
import net.sf.jasperreports.engine.JRBox;
import net.sf.jasperreports.engine.JRDefaultStyleProvider;
import net.sf.jasperreports.engine.JRElement;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRFrame;
import net.sf.jasperreports.engine.JRLineBox;
import net.sf.jasperreports.engine.JROrigin;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPrintFrame;
import net.sf.jasperreports.engine.JRStyle;
import net.sf.jasperreports.engine.JRStyleSetter;
import net.sf.jasperreports.engine.type.ModeEnum;
import net.sf.jasperreports.engine.util.LineBoxWrapper;
import org.apache.commons.collections.ReferenceMap;
/**
* Crosstab cell contents filler.
*
* @author Lucian Chirita (lucianc@users.sourceforge.net)
* @version $Id: JRFillCellContents.java 3768 2010-04-26 11:54:22Z lucianc $
*/
public class JRFillCellContents extends JRFillElementContainer implements JRCellContents, JRStyleSetter
{
private final Map transformedContentsCache;
private final Map boxContentsCache;
private final JRClonePool clonePool;
private final JROriginProvider originProvider;
private JRFillCellContents original;
private final JRCellContents parentCell;
private String cellType;
private JRLineBox lineBox;
private int height;
private int width;
private int x;
private int y;
private int verticalSpan;
private CrosstabRowPositionEnum verticalPositionType = CrosstabRowPositionEnum.TOP;
private int horizontalSpan;
private Map templateFrames;
private JRDefaultStyleProvider defaultStyleProvider;
private JRStyle initStyle;
private int prepareStretchHeight;
public JRFillCellContents(JRBaseFiller filler, JRCellContents cell, String cellType,
JRFillCrosstabObjectFactory factory)
{
super(filler, cell, factory);
defaultStyleProvider = factory.getDefaultStyleProvider();
parentCell = cell;
this.cellType = cellType;
lineBox = cell.getLineBox().clone(this);
width = cell.getWidth();
height = cell.getHeight();
factory.registerDelayedStyleSetter(this, parentCell);
initElements();
initConditionalStyles();
initTemplatesMap();
this.originProvider = factory.getParentOriginProvider();
setElementOriginProvider(this.originProvider);
transformedContentsCache = new ReferenceMap();
boxContentsCache = new HashMap();
clonePool = new JRClonePool(this, true, true);
}
private void initTemplatesMap()
{
templateFrames = new HashMap();
}
protected JRFillCellContents(JRFillCellContents cellContents, JRFillCloneFactory factory)
{
super(cellContents, factory);
defaultStyleProvider = cellContents.defaultStyleProvider;
parentCell = cellContents.parentCell;
cellType = cellContents.cellType;
lineBox = cellContents.getLineBox().clone(this);
width = cellContents.width;
height = cellContents.height;
initStyle = cellContents.initStyle;
initElements();
initConditionalStyles();
this.templateFrames = cellContents.templateFrames;
this.originProvider = cellContents.originProvider;
transformedContentsCache = new ReferenceMap();
boxContentsCache = new HashMap();
clonePool = new JRClonePool(this, true, true);
verticalPositionType = cellContents.verticalPositionType;
}
public Color getBackcolor()
{
return parentCell.getBackcolor();
}
/**
* @deprecated Replaced by {@link #getLineBox()}
*/
public JRBox getBox()
{
return new LineBoxWrapper(getLineBox());
}
/**
*
*/
public JRLineBox getLineBox()
{
return lineBox;
}
/**
*
*/
protected void setBox(JRLineBox box)
{
this.lineBox = box;
initTemplatesMap();
}
public int getHeight()
{
return height;
}
public int getWidth()
{
return width;
}
protected void setHeight(int height)
{
this.height = height;
}
protected void setWidth(int width)
{
this.width = width;
}
public JRFillCellContents getBoxContents(boolean left, boolean right, boolean top)
{
if (lineBox == null)
{
return this;
}
boolean copyLeft = left && lineBox.getLeftPen().getLineWidth().floatValue() <= 0f && lineBox.getRightPen().getLineWidth().floatValue() > 0f;
boolean copyRight = right && lineBox.getRightPen().getLineWidth().floatValue() <= 0f && lineBox.getLeftPen().getLineWidth().floatValue() > 0f;
boolean copyTop = top && lineBox.getTopPen().getLineWidth().floatValue() <= 0f && lineBox.getBottomPen().getLineWidth().floatValue() > 0f;
if (!(copyLeft || copyRight || copyTop))
{
return this;
}
Object key = new BoxContents(copyLeft, copyRight, copyTop);
JRFillCellContents boxContents = (JRFillCellContents) boxContentsCache.get(key);
if (boxContents == null)
{
boxContents = (JRFillCellContents) createClone();
JRLineBox newBox = lineBox.clone(this);
if (copyLeft)
{
newBox.copyLeftPen(lineBox.getRightPen());
}
if (copyRight)
{
newBox.copyRightPen(lineBox.getLeftPen());
}
if (copyTop)
{
newBox.copyTopPen(lineBox.getBottomPen());
}
boxContents.setBox(newBox);
boxContentsCache.put(key, boxContents);
}
return boxContents;
}
public JRFillCellContents getTransformedContents(
int newWidth, int newHeight,
CrosstabColumnPositionEnum xPosition, CrosstabRowPositionEnum yPosition) throws JRException
{
if ((getHeight() == newHeight) &&
(getWidth() == newWidth))
{
return this;
}
if (newHeight < getHeight() || newWidth < getWidth())
{
throw new JRException("Cannot shrink cell contents.");
}
Object key = new StretchedContents(newWidth, newHeight, xPosition, yPosition);
JRFillCellContents transformedCell = (JRFillCellContents) transformedContentsCache.get(key);
if (transformedCell == null)
{
transformedCell = (JRFillCellContents) createClone();
transformedCell.transform(newWidth, newHeight, xPosition, yPosition);
transformedContentsCache.put(key, transformedCell);
}
return transformedCell;
}
private void transform(int newWidth, int newHeight, CrosstabColumnPositionEnum xPosition, CrosstabRowPositionEnum yPosition)
{
transformElements(newWidth, newHeight, xPosition, yPosition);
width = newWidth;
height = newHeight;
}
private void transformElements(int newWidth, int newHeight, CrosstabColumnPositionEnum xPosition, CrosstabRowPositionEnum yPosition)
{
if ((height == newHeight || yPosition == CrosstabRowPositionEnum.TOP) &&
(width == newWidth || xPosition == CrosstabColumnPositionEnum.LEFT))
{
return;
}
double scaleX = -1d;
int offsetX = 0;
switch (xPosition)
{
case CENTER:
offsetX = (newWidth - width) / 2;
break;
case RIGHT:
offsetX = newWidth - width;
break;
case STRETCH:
scaleX = ((double) newWidth) / width;
break;
}
double scaleY = -1d;
int offsetY = 0;
switch (yPosition)
{
case MIDDLE:
offsetY = (newHeight - height) / 2;
break;
case BOTTOM:
offsetY = newHeight - height;
break;
case STRETCH:
scaleY = ((double) newHeight) / height;
break;
}
transformElements(getElements(), scaleX, offsetX, scaleY, offsetY);
}
private static void transformElements(JRElement[] elements, double scaleX, int offsetX, double scaleY, int offsetY)
{
if (elements != null)
{
for (int i = 0; i < elements.length; i++)
{
JRFillElement element = (JRFillElement) elements[i];
if (scaleX != -1d)
{
element.setX((int) (element.getX() * scaleX));
element.setWidth((int) (element.getWidth() * scaleX));
}
if (offsetX != 0)
{
element.setX(element.getX() + offsetX);
}
if (scaleY != -1d)
{
element.setY((int) (element.getY() * scaleY));
element.setHeight((int) (element.getHeight() * scaleY));
}
if (offsetY != 0)
{
element.setY(element.getY() + offsetY);
}
if (element instanceof JRFrame)
{
JRElement[] frameElements = ((JRFrame) element).getElements();
transformElements(frameElements, scaleX, offsetX, scaleY, offsetY);
}
}
}
}
protected void prepare(int availableHeight) throws JRException
{
initFill();
resetElements();
prepareElements(availableHeight, true);
// store the original stretch height in order to compute the external
// stretch height
prepareStretchHeight = getStretchHeight();
}
protected JRPrintFrame fill() throws JRException
{
stretchElements();
moveBandBottomElements();
removeBlankElements();
JRTemplatePrintFrame printCell = new JRTemplatePrintFrame(getTemplateFrame());
printCell.setX(x);
printCell.setY(y);
printCell.setWidth(width);
fillElements(printCell);
verticallyPositionElements(printCell);
printCell.setHeight(getPrintHeight());
setCellProperties(printCell);
return printCell;
}
protected void setCellProperties(JRTemplatePrintFrame printCell)
{
if (cellType != null)
{
printCell.getPropertiesMap().setProperty(
JRCellContents.PROPERTY_TYPE, cellType);
}
if (verticalSpan > 1)
{
printCell.getPropertiesMap().setProperty(
JRCellContents.PROPERTY_ROW_SPAN, Integer.toString(verticalSpan));
}
if (horizontalSpan > 1)
{
printCell.getPropertiesMap().setProperty(
JRCellContents.PROPERTY_COLUMN_SPAN, Integer.toString(horizontalSpan));
}
}
protected JRTemplateFrame getTemplateFrame()
{
JRStyle style = getStyle();
JRTemplateFrame template = (JRTemplateFrame) templateFrames.get(style);
if (template == null)
{
template = new JRTemplateFrame(getOrigin(),
filler.getJasperPrint().getDefaultStyleProvider(), this);
templateFrames.put(style, template);
}
return template;
}
protected JROrigin getOrigin()
{
return originProvider == null ? null : originProvider.getOrigin();
}
protected void verticallyPositionElements(JRTemplatePrintFrame printCell)
{
int positionOffset;
switch (verticalPositionType)
{
case MIDDLE:
positionOffset = (getStretchHeight() - prepareStretchHeight) / 2;
break;
case BOTTOM:
positionOffset = getStretchHeight() - prepareStretchHeight;
break;
default:
positionOffset = 0;
break;
}
if (positionOffset != 0)
{
List printElements = printCell.getElements();
int positionY = getStretchHeight() - positionOffset;
boolean outside = false;
for (Iterator it = printElements.iterator(); !outside && it.hasNext();)
{
JRPrintElement element = (JRPrintElement) it.next();
outside = element.getY() + element.getHeight() > positionY;
}
if (!outside)
{
for (Iterator it = printElements.iterator(); it.hasNext();)
{
JRPrintElement element = (JRPrintElement) it.next();
element.setY(element.getY() + positionOffset);
}
}
}
}
protected int getPrintHeight()
{
return getStretchHeight() + getTopPadding() + getBottomPadding();
}
protected void stretchTo(int stretchHeight)
{
setStretchHeight(stretchHeight - getTopPadding() - getBottomPadding());
}
protected static class BoxContents
{
final boolean left;
final boolean right;
final boolean top;
final int hashCode;
public BoxContents(boolean left, boolean right, boolean top)
{
this.left = left;
this.right = right;
this.top = top;
int hash = left ? 1231 : 1237;
hash = 31*hash + (right ? 1231 : 1237);
hash = 31*hash + (top ? 1231 : 1237);
hashCode = hash;
}
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
BoxContents b = (BoxContents) obj;
return
b.left == left && b.right == right && b.top == top;
}
public int hashCode()
{
return hashCode;
}
}
protected static class StretchedContents
{
final int newHeight;
final int newWidth;
final int hashCode;
final CrosstabColumnPositionEnum xPosition;
final CrosstabRowPositionEnum yPosition;
StretchedContents(
int newWidth, int newHeight, CrosstabColumnPositionEnum xPosition, CrosstabRowPositionEnum yPosition)
{
this.newHeight = newHeight;
this.newWidth = newWidth;
this.xPosition = xPosition;
this.yPosition = yPosition;
int hash = newHeight;
hash = 31*hash + newWidth;
hash = 31*hash + xPosition.getValue();
hash = 31*hash + yPosition.getValue();
hashCode = hash;
}
public boolean equals(Object o)
{
if (o == this)
{
return true;
}
StretchedContents s = (StretchedContents) o;
return
s.newHeight == newHeight && s.newWidth == newWidth &&
s.xPosition == xPosition && s.yPosition == yPosition;
}
public int hashCode()
{
return hashCode;
}
}
protected int getContainerHeight()
{
return getHeight() - getTopPadding() - getBottomPadding();
}
protected int getTopPadding()
{
return lineBox == null ? 0 : lineBox.getTopPadding().intValue();
}
protected int getBottomPadding()
{
return lineBox == null ? 0 : lineBox.getBottomPadding().intValue();
}
public JRFillCloneable createClone()
{
JRFillCloneFactory factory = new JRFillCloneFactory();
return createClone(factory);
}
public JRFillCloneable createClone(JRFillCloneFactory factory)
{
return new JRFillCellContents(this, factory);
}
public JRFillCellContents getWorkingClone()
{
JRFillCellContents clone = (JRFillCellContents) clonePool.getClone();
clone.original = this;
return clone;
}
public void releaseWorkingClone()
{
original.clonePool.releaseClone(this);
}
public void setX(int x)
{
this.x = x;
}
public void setY(int y)
{
this.y = y;
}
public int getVerticalSpan()
{
return verticalSpan;
}
public void setVerticalSpan(int span)
{
verticalSpan = span;
}
public void setVerticalPositionType(CrosstabRowPositionEnum positionType)
{
this.verticalPositionType = positionType;
}
public int getHorizontalSpan()
{
return horizontalSpan;
}
public void setHorizontalSpan(int horizontalSpan)
{
this.horizontalSpan = horizontalSpan;
}
protected void evaluate(byte evaluation) throws JRException
{
evaluateConditionalStyles(evaluation);
super.evaluate(evaluation);
}
public JRDefaultStyleProvider getDefaultStyleProvider()
{
return defaultStyleProvider;
}
public JRStyle getStyle()
{
JRStyle crtStyle = initStyle;
boolean isUsingDefaultStyle = false;
if (crtStyle == null)
{
crtStyle = filler.getDefaultStyle();
isUsingDefaultStyle = true;
}
JRStyle evalStyle = getEvaluatedConditionalStyle(crtStyle);
if (isUsingDefaultStyle && evalStyle == crtStyle)
{
evalStyle = null;
}
return evalStyle;
}
protected void initConditionalStyles()
{
super.initConditionalStyles();
collectConditionalStyle(initStyle);
}
/**
* @deprecated Replaced by {@link #getModeValue()}.
*/
public Byte getMode()
{
return getModeValue() == null ? null : getModeValue().getValueByte();
}
public ModeEnum getModeValue()
{
return parentCell.getModeValue();
}
public String getStyleNameReference()
{
return null;
}
public void setStyle(JRStyle style)
{
this.initStyle = style;
collectConditionalStyle(style);
}
public void setStyleNameReference(String name)
{
throw new UnsupportedOperationException("Style name references not allowed at fill time");
}
/**
*
*/
public Color getDefaultLineColor()
{
return parentCell.getDefaultLineColor();
}
}