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.engine.JRBox; import net.sf.jasperreports.engine.JRBoxContainer; import net.sf.jasperreports.engine.JRDefaultStyleProvider; import net.sf.jasperreports.engine.JRElement; import net.sf.jasperreports.engine.JRElementGroup; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRFrame; import net.sf.jasperreports.engine.JRLineBox; import net.sf.jasperreports.engine.JRPrintElement; import net.sf.jasperreports.engine.JRPrintFrame; import net.sf.jasperreports.engine.JRStyle; import net.sf.jasperreports.engine.JRStyleContainer; import net.sf.jasperreports.engine.JRStyleSetter; import net.sf.jasperreports.engine.util.LineBoxWrapper; import org.apache.commons.collections.ReferenceMap; public class JRFillCellContents extends JRFillElementContainer implements JRCellContents, JRFillCloneable, JRStyleSetter { private final Map transformedContentsCache; private final Map boxContentsCache; private final JRClonePool clonePool; private JRFillCellContents original; private final JRCellContents parentCell; private JRLineBox lineBox; private int height; private int width; private int x; private int y; private int verticalSpan; private byte verticalPositionType = 1; private Map templateFrames; private JRDefaultStyleProvider defaultStyleProvider; private JRStyle initStyle; public JRFillCellContents(JRBaseFiller filler, JRCellContents cell, JRFillObjectFactory factory) { super(filler, (JRElementGroup)cell, factory); this.defaultStyleProvider = factory.getDefaultStyleProvider(); this.parentCell = cell; this.lineBox = cell.getLineBox(); this.width = cell.getWidth(); this.height = cell.getHeight(); factory.registerDelayedStyleSetter(this, (JRStyleContainer)this.parentCell); initElements(); initConditionalStyles(); initTemplatesMap(); this.transformedContentsCache = (Map)new ReferenceMap(); this.boxContentsCache = new HashMap(); this.clonePool = new JRClonePool(this, true, true); } private void initTemplatesMap() { this.templateFrames = new HashMap(); } protected JRFillCellContents(JRFillCellContents cellContents, JRFillCloneFactory factory) { super(cellContents, factory); this.defaultStyleProvider = cellContents.defaultStyleProvider; this.parentCell = cellContents.parentCell; this.lineBox = cellContents.lineBox; this.width = cellContents.width; this.height = cellContents.height; this.initStyle = cellContents.initStyle; initElements(); initConditionalStyles(); this.templateFrames = cellContents.templateFrames; this.transformedContentsCache = (Map)new ReferenceMap(); this.boxContentsCache = new HashMap(); this.clonePool = new JRClonePool(this, true, true); this.verticalPositionType = cellContents.verticalPositionType; } public Color getBackcolor() { return this.parentCell.getBackcolor(); } public JRBox getBox() { return (JRBox)new LineBoxWrapper(getLineBox()); } public JRLineBox getLineBox() { return this.lineBox; } protected void setBox(JRLineBox box) { this.lineBox = box; initTemplatesMap(); } public int getHeight() { return this.height; } public int getWidth() { return this.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 (this.lineBox == null) return this; boolean copyLeft = (left && this.lineBox.getLeftPen().getLineWidth().floatValue() <= 0.0F && this.lineBox.getRightPen().getLineWidth().floatValue() > 0.0F); boolean copyRight = (right && this.lineBox.getRightPen().getLineWidth().floatValue() <= 0.0F && this.lineBox.getLeftPen().getLineWidth().floatValue() > 0.0F); boolean copyTop = (top && this.lineBox.getTopPen().getLineWidth().floatValue() <= 0.0F && this.lineBox.getBottomPen().getLineWidth().floatValue() > 0.0F); if (!copyLeft && !copyRight && !copyTop) return this; Object key = new BoxContents(copyLeft, copyRight, copyTop); JRFillCellContents boxContents = (JRFillCellContents)this.boxContentsCache.get(key); if (boxContents == null) { boxContents = (JRFillCellContents)createClone(); JRLineBox newBox = this.lineBox.clone((JRBoxContainer)this.parentCell); if (copyLeft) newBox.copyLeftPen(this.lineBox.getRightPen()); if (copyRight) newBox.copyRightPen(this.lineBox.getLeftPen()); if (copyTop) newBox.copyTopPen(this.lineBox.getBottomPen()); boxContents.setBox(newBox); this.boxContentsCache.put(key, boxContents); } return boxContents; } public JRFillCellContents getTransformedContents(int newWidth, int newHeight, byte xPosition, byte 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)this.transformedContentsCache.get(key); if (transformedCell == null) { transformedCell = (JRFillCellContents)createClone(); transformedCell.transform(newWidth, newHeight, xPosition, yPosition); transformedCell.setElementsBandBottomY(); this.transformedContentsCache.put(key, transformedCell); } return transformedCell; } private void transform(int newWidth, int newHeight, byte xPosition, byte yPosition) { transformElements(newWidth, newHeight, xPosition, yPosition); this.width = newWidth; this.height = newHeight; } private void transformElements(int newWidth, int newHeight, byte xPosition, byte yPosition) { if ((this.height == newHeight || yPosition == 1) && (this.width == newWidth || xPosition == 1)) return; double scaleX = -1.0D; int offsetX = 0; switch (xPosition) { case 2: offsetX = (newWidth - this.width) / 2; break; case 3: offsetX = newWidth - this.width; break; case 4: scaleX = newWidth / this.width; break; } double scaleY = -1.0D; int offsetY = 0; switch (yPosition) { case 2: offsetY = (newHeight - this.height) / 2; break; case 3: offsetY = newHeight - this.height; break; case 4: scaleY = newHeight / this.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 != -1.0D) { element.setX((int)(element.getX() * scaleX)); element.setWidth((int)(element.getWidth() * scaleX)); } if (offsetX != 0) element.setX(element.getX() + offsetX); if (scaleY != -1.0D) { 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 availableStretchHeight) throws JRException { initFill(); resetElements(); prepareElements(availableStretchHeight, true); } protected JRPrintFrame fill() throws JRException { stretchElements(); moveBandBottomElements(); removeBlankElements(); JRTemplatePrintFrame printCell = new JRTemplatePrintFrame(getTemplateFrame()); printCell.setX(this.x); printCell.setY(this.y); printCell.setWidth(this.width); fillElements(printCell); verticallyPositionElements(printCell); printCell.setHeight(getPrintHeight()); return printCell; } private JRTemplateFrame getTemplateFrame() { JRStyle style = getStyle(); JRTemplateFrame template = (JRTemplateFrame)this.templateFrames.get(style); if (template == null) { template = new JRTemplateFrame(null, this.filler.getJasperPrint().getDefaultStyleProvider(), this); this.templateFrames.put(style, template); } return template; } protected void verticallyPositionElements(JRTemplatePrintFrame printCell) { int positionOffset; switch (this.verticalPositionType) { case 2: positionOffset = (getStretchHeight() - getContainerHeight()) / 2; break; case 3: positionOffset = getStretchHeight() - getContainerHeight(); 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 = it.next(); outside = (element.getY() > positionY); } if (!outside) for (Iterator iterator = printElements.iterator(); iterator.hasNext(); ) { JRPrintElement element = iterator.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); this.hashCode = hash; } public boolean equals(Object obj) { if (obj == this) return true; BoxContents b = (BoxContents)obj; return (b.left == this.left && b.right == this.right && b.top == this.top); } public int hashCode() { return this.hashCode; } } protected static class StretchedContents { final int newHeight; final int newWidth; final int hashCode; final byte xPosition; final byte yPosition; StretchedContents(int newWidth, int newHeight, byte xPosition, byte yPosition) { this.newHeight = newHeight; this.newWidth = newWidth; this.xPosition = xPosition; this.yPosition = yPosition; int hash = newHeight; hash = 31 * hash + newWidth; hash = 31 * hash + xPosition; hash = 31 * hash + yPosition; this.hashCode = hash; } public boolean equals(Object o) { if (o == this) return true; StretchedContents s = (StretchedContents)o; return (s.newHeight == this.newHeight && s.newWidth == this.newWidth && s.xPosition == this.xPosition && s.yPosition == this.yPosition); } public int hashCode() { return this.hashCode; } } protected int getContainerHeight() { return getHeight() - getTopPadding() - getBottomPadding(); } protected int getTopPadding() { return (this.lineBox == null) ? 0 : this.lineBox.getTopPadding().intValue(); } protected int getBottomPadding() { return (this.lineBox == null) ? 0 : this.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)this.clonePool.getClone(); clone.original = this; return clone; } public void releaseWorkingClone() { this.original.clonePool.releaseClone(this); } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public int getVerticalSpan() { return this.verticalSpan; } public void setVerticalSpan(int span) { this.verticalSpan = span; } public void setVerticalPositionType(byte positionType) { this.verticalPositionType = positionType; } protected void evaluate(byte evaluation) throws JRException { evaluateConditionalStyles(evaluation); super.evaluate(evaluation); } public JRDefaultStyleProvider getDefaultStyleProvider() { return this.defaultStyleProvider; } public JRStyle getStyle() { JRStyle crtStyle = this.initStyle; boolean isUsingDefaultStyle = false; if (crtStyle == null) { crtStyle = this.filler.getDefaultStyle(); isUsingDefaultStyle = true; } JRStyle evalStyle = getEvaluatedConditionalStyle(crtStyle); if (isUsingDefaultStyle && evalStyle == crtStyle) evalStyle = null; return evalStyle; } protected void initConditionalStyles() { super.initConditionalStyles(); collectConditionalStyle(this.initStyle); } public Byte getMode() { return this.parentCell.getMode(); } 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 this.parentCell.getDefaultLineColor(); } }