package net.sf.jasperreports.engine.fill; import java.awt.Color; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import net.sf.jasperreports.engine.JRCommonElement; 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.JRExpression; import net.sf.jasperreports.engine.JRExpressionChunk; import net.sf.jasperreports.engine.JRGroup; import net.sf.jasperreports.engine.JRPrintElement; import net.sf.jasperreports.engine.JRPropertiesHolder; import net.sf.jasperreports.engine.JRPropertiesMap; import net.sf.jasperreports.engine.JRPropertyExpression; import net.sf.jasperreports.engine.JRStyle; import net.sf.jasperreports.engine.JRStyleContainer; import net.sf.jasperreports.engine.JRStyleSetter; import net.sf.jasperreports.engine.JRVisitable; import net.sf.jasperreports.engine.util.JRProperties; import net.sf.jasperreports.engine.util.JRStyleResolver; public abstract class JRFillElement implements JRElement, JRFillCloneable, JRStyleSetter { protected JRElement parent = null; protected Map templates = new HashMap(); protected JRBaseFiller filler = null; protected JRFillExpressionEvaluator expressionEvaluator = null; protected JRDefaultStyleProvider defaultStyleProvider; protected JRGroup printWhenGroupChanges = null; protected JRFillElementGroup elementGroup = null; protected JRFillBand band = null; private boolean isPrintWhenExpressionNull = true; private boolean isPrintWhenTrue = true; private boolean isToPrint = true; private boolean isReprinted = false; private boolean isAlreadyPrinted = false; private Collection dependantElements = new ArrayList(); private int relativeY = 0; private int stretchHeight = 0; private int bandBottomY = 0; private int x; private int y; private int width; private int height; private boolean isValueRepeating = false; protected byte currentEvaluation; protected Map delayedEvaluationsMap; protected JRFillElementContainer conditionalStylesContainer; protected JRStyle initStyle; private boolean shrinkable; protected JRPropertiesMap staticProperties; protected JRPropertiesMap dynamicProperties; protected JRPropertiesMap mergedProperties; protected JRFillElement(JRBaseFiller filler, JRElement element, JRFillObjectFactory factory) { factory.put(element, this); this.parent = element; this.filler = filler; this.expressionEvaluator = factory.getExpressionEvaluator(); this.defaultStyleProvider = factory.getDefaultStyleProvider(); this.printWhenGroupChanges = factory.getGroup(element.getPrintWhenGroupChanges()); this.elementGroup = (JRFillElementGroup)factory.getVisitResult((JRVisitable)element.getElementGroup()); this.x = element.getX(); this.y = element.getY(); this.width = element.getWidth(); this.height = element.getHeight(); this.staticProperties = element.hasProperties() ? element.getPropertiesMap().cloneProperties() : null; this.mergedProperties = this.staticProperties; factory.registerDelayedStyleSetter(this, (JRStyleContainer)this.parent); } protected JRFillElement(JRFillElement element, JRFillCloneFactory factory) { factory.put(element, this); this.parent = element.parent; this.filler = element.filler; this.expressionEvaluator = element.expressionEvaluator; this.defaultStyleProvider = element.defaultStyleProvider; this.printWhenGroupChanges = element.printWhenGroupChanges; this.elementGroup = (JRFillElementGroup)factory.getClone((JRFillElementGroup)element.getElementGroup()); this.x = element.getX(); this.y = element.getY(); this.width = element.getWidth(); this.height = element.getHeight(); this.templates = element.templates; this.initStyle = element.initStyle; this.shrinkable = element.shrinkable; this.staticProperties = (element.staticProperties == null) ? null : element.staticProperties.cloneProperties(); this.mergedProperties = this.staticProperties; } public JRDefaultStyleProvider getDefaultStyleProvider() { return this.defaultStyleProvider; } public String getKey() { return this.parent.getKey(); } public byte getPositionType() { return this.parent.getPositionType(); } public void setPositionType(byte positionType) {} public byte getStretchType() { return this.parent.getStretchType(); } public void setStretchType(byte stretchType) {} public boolean isPrintRepeatedValues() { return this.parent.isPrintRepeatedValues(); } public void setPrintRepeatedValues(boolean isPrintRepeatedValues) {} public byte getMode() { return JRStyleResolver.getMode((JRCommonElement)this, (byte)1); } public Byte getOwnMode() { return this.parent.getOwnMode(); } public void setMode(byte mode) {} public void setMode(Byte mode) {} public int getX() { return this.x; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public int getY() { return this.y; } public int getWidth() { return this.width; } public void setWidth(int width) { this.width = width; } public void setHeight(int height) { this.height = height; } public int getHeight() { return this.height; } public boolean isRemoveLineWhenBlank() { return this.parent.isRemoveLineWhenBlank(); } public void setRemoveLineWhenBlank(boolean isRemoveLine) {} public boolean isPrintInFirstWholeBand() { return this.parent.isPrintInFirstWholeBand(); } public void setPrintInFirstWholeBand(boolean isPrint) {} public boolean isPrintWhenDetailOverflows() { return this.parent.isPrintWhenDetailOverflows(); } public void setPrintWhenDetailOverflows(boolean isPrint) {} public Color getForecolor() { return JRStyleResolver.getForecolor((JRCommonElement)this); } public Color getOwnForecolor() { return this.parent.getOwnForecolor(); } public void setForecolor(Color forecolor) {} public Color getBackcolor() { return JRStyleResolver.getBackcolor((JRCommonElement)this); } public Color getOwnBackcolor() { return this.parent.getOwnBackcolor(); } public void setBackcolor(Color backcolor) {} public JRExpression getPrintWhenExpression() { return this.parent.getPrintWhenExpression(); } public JRGroup getPrintWhenGroupChanges() { return this.printWhenGroupChanges; } public JRElementGroup getElementGroup() { return this.elementGroup; } protected boolean isPrintWhenExpressionNull() { return this.isPrintWhenExpressionNull; } protected void setPrintWhenExpressionNull(boolean isPrintWhenExpressionNull) { this.isPrintWhenExpressionNull = isPrintWhenExpressionNull; } protected boolean isPrintWhenTrue() { return this.isPrintWhenTrue; } protected void setPrintWhenTrue(boolean isPrintWhenTrue) { this.isPrintWhenTrue = isPrintWhenTrue; } protected boolean isToPrint() { return this.isToPrint; } protected void setToPrint(boolean isToPrint) { this.isToPrint = isToPrint; } protected boolean isReprinted() { return this.isReprinted; } protected void setReprinted(boolean isReprinted) { this.isReprinted = isReprinted; } protected boolean isAlreadyPrinted() { return this.isAlreadyPrinted; } protected void setAlreadyPrinted(boolean isAlreadyPrinted) { this.isAlreadyPrinted = isAlreadyPrinted; } protected JRElement[] getGroupElements() { JRElement[] groupElements = null; if (this.elementGroup != null) groupElements = this.elementGroup.getElements(); return groupElements; } protected Collection getDependantElements() { return this.dependantElements; } protected void addDependantElement(JRElement element) { this.dependantElements.add(element); } protected int getRelativeY() { return this.relativeY; } protected void setRelativeY(int relativeY) { this.relativeY = relativeY; } protected int getStretchHeight() { return this.stretchHeight; } protected void setStretchHeight(int stretchHeight) { if (stretchHeight > getHeight() || (this.shrinkable && isRemoveLineWhenBlank())) { this.stretchHeight = stretchHeight; } else { this.stretchHeight = getHeight(); } } protected int getBandBottomY() { return this.bandBottomY; } protected void setBandBottomY(int bandBottomY) { this.bandBottomY = bandBottomY; } protected JRFillBand getBand() { return this.band; } protected void setBand(JRFillBand band) { this.band = band; } protected void reset() { this.relativeY = this.y; this.stretchHeight = this.height; if (this.elementGroup != null) this.elementGroup.reset(); } protected void setCurrentEvaluation(byte evaluation) { this.currentEvaluation = evaluation; } protected abstract void evaluate(byte paramByte) throws JRException; protected void evaluatePrintWhenExpression(byte evaluation) throws JRException { boolean isExprNull = true; boolean isExprTrue = false; JRExpression expression = getPrintWhenExpression(); if (expression != null) { isExprNull = false; Boolean printWhenExpressionValue = (Boolean)evaluateExpression(expression, evaluation); if (printWhenExpressionValue == null) { isExprTrue = false; } else { isExprTrue = printWhenExpressionValue.booleanValue(); } } setPrintWhenExpressionNull(isExprNull); setPrintWhenTrue(isExprTrue); } protected abstract void rewind() throws JRException; protected abstract JRPrintElement fill() throws JRException; protected boolean prepare(int availableStretchHeight, boolean isOverflow) throws JRException { if (isPrintWhenExpressionNull() || (!isPrintWhenExpressionNull() && isPrintWhenTrue())) { setToPrint(true); } else { setToPrint(false); } setReprinted(false); return false; } protected void stretchElement(int bandStretch) { switch (getStretchType()) { case 2: setStretchHeight(getHeight() + bandStretch); break; case 1: if (this.elementGroup != null) setStretchHeight(getHeight() + this.elementGroup.getStretchHeightDiff()); break; } } protected void moveDependantElements() { Collection elements = getDependantElements(); if (elements != null && elements.size() > 0) { JRFillElement element = null; int diffY = 0; for (Iterator it = elements.iterator(); it.hasNext(); ) { element = it.next(); diffY = element.getY() - getY() - getHeight() - element.getRelativeY() - getRelativeY() - getStretchHeight(); if (diffY < 0) diffY = 0; element.setRelativeY(element.getRelativeY() + diffY); } } } protected abstract void resolveElement(JRPrintElement paramJRPrintElement, byte paramByte) throws JRException; protected final Object evaluateExpression(JRExpression expression, byte evaluation) throws JRException { return this.expressionEvaluator.evaluate(expression, evaluation); } protected boolean isValueRepeating() { return this.isValueRepeating; } protected void setValueRepeating(boolean isValueRepeating) { this.isValueRepeating = isValueRepeating; } protected JRFillVariable getVariable(String variableName) { return this.filler.getVariable(variableName); } protected JRFillField getField(String fieldName) { return this.filler.getField(fieldName); } protected byte getEvaluationTime() { return 1; } protected void resolveElement(JRPrintElement element, byte evaluation, JREvaluationTime evaluationTime) throws JRException { byte evaluationTimeType = getEvaluationTime(); switch (evaluationTimeType) { case 1: return; case 7: delayedEvaluate((JRRecordedValuesPrintElement)element, evaluationTime, evaluation); } resolveElement(element, evaluation); } private static class DelayedEvaluations implements Serializable { private static final long serialVersionUID = 10200L; final Set fields = new HashSet(); final Set variables = new HashSet(); } protected void initDelayedEvaluations() { if (getEvaluationTime() == 7 && this.delayedEvaluationsMap == null) { this.delayedEvaluationsMap = new HashMap(); collectDelayedEvaluations(); } } protected void collectDelayedEvaluations() {} protected void collectDelayedEvaluations(JRExpression expression) { if (expression != null) { JRExpressionChunk[] chunks = expression.getChunks(); if (chunks != null) for (int i = 0; i < chunks.length; i++) { DelayedEvaluations delayedEvaluations; JREvaluationTime time; DelayedEvaluations delayedEvaluations1; JRExpressionChunk chunk = chunks[i]; switch (chunk.getType()) { case 3: delayedEvaluations = getDelayedEvaluations(JREvaluationTime.EVALUATION_TIME_NOW); delayedEvaluations.fields.add(chunk.getText()); break; case 4: time = autogetVariableEvaluationTime(chunk.getText()); delayedEvaluations1 = getDelayedEvaluations(time); delayedEvaluations1.variables.add(chunk.getText()); break; } } } } private DelayedEvaluations getDelayedEvaluations(JREvaluationTime time) { DelayedEvaluations delayedEvaluations = (DelayedEvaluations)this.delayedEvaluationsMap.get(time); if (delayedEvaluations == null) { delayedEvaluations = new DelayedEvaluations(); this.delayedEvaluationsMap.put(time, delayedEvaluations); } return delayedEvaluations; } private JREvaluationTime autogetVariableEvaluationTime(String variableName) { JREvaluationTime evaluationTime; JRFillVariable variable = getVariable(variableName); switch (variable.getResetType()) { case 1: evaluationTime = JREvaluationTime.EVALUATION_TIME_REPORT; break; case 2: evaluationTime = JREvaluationTime.EVALUATION_TIME_PAGE; break; case 3: evaluationTime = JREvaluationTime.EVALUATION_TIME_COLUMN; break; case 4: evaluationTime = JREvaluationTime.getGroupEvaluationTime(variable.getResetGroup().getName()); break; default: evaluationTime = JREvaluationTime.EVALUATION_TIME_NOW; break; } if (!evaluationTime.equals(JREvaluationTime.EVALUATION_TIME_NOW) && this.band.isNowEvaluationTime(evaluationTime)) evaluationTime = JREvaluationTime.EVALUATION_TIME_NOW; if (variable.getCalculation() == 8 && evaluationTime.equals(JREvaluationTime.EVALUATION_TIME_NOW) && this.band.isVariableUsedInSubreportReturns(variableName)) evaluationTime = JREvaluationTime.getBandEvaluationTime(this.band); return evaluationTime; } protected void initDelayedEvaluationPrint(JRRecordedValuesPrintElement printElement) throws JRException { for (Iterator it = this.delayedEvaluationsMap.keySet().iterator(); it.hasNext(); ) { JREvaluationTime evaluationTime = it.next(); if (!evaluationTime.equals(JREvaluationTime.EVALUATION_TIME_NOW)) this.filler.addBoundElement(this, printElement, evaluationTime); } printElement.initRecordedValues(this.delayedEvaluationsMap.keySet()); if (this.delayedEvaluationsMap.containsKey(JREvaluationTime.EVALUATION_TIME_NOW)) delayedEvaluate(printElement, JREvaluationTime.EVALUATION_TIME_NOW, this.currentEvaluation); } protected void delayedEvaluate(JRRecordedValuesPrintElement printElement, JREvaluationTime evaluationTime, byte evaluation) throws JRException { JRRecordedValues recordedValues = printElement.getRecordedValues(); if (!recordedValues.lastEvaluationTime()) { DelayedEvaluations delayedEvaluations = (DelayedEvaluations)this.delayedEvaluationsMap.get(evaluationTime); for (Iterator iterator1 = delayedEvaluations.fields.iterator(); iterator1.hasNext(); ) { String fieldName = iterator1.next(); JRFillField field = getField(fieldName); recordedValues.recordFieldValue(fieldName, field.getValue(evaluation)); } for (Iterator it = delayedEvaluations.variables.iterator(); it.hasNext(); ) { String variableName = it.next(); JRFillVariable variable = getVariable(variableName); recordedValues.recordVariableValue(variableName, variable.getValue(evaluation)); } } recordedValues.doneEvaluation(evaluationTime); if (recordedValues.finishedEvaluations()) { overwriteWithRecordedValues(recordedValues, evaluation); resolveElement(printElement, evaluation); restoreValues(recordedValues, evaluation); printElement.deleteRecordedValues(); } } private void overwriteWithRecordedValues(JRRecordedValues recordedValues, byte evaluation) { Map fieldValues = recordedValues.getRecordedFieldValues(); if (fieldValues != null) for (Iterator it = fieldValues.entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = it.next(); String fieldName = (String)entry.getKey(); Object fieldValue = entry.getValue(); JRFillField field = getField(fieldName); field.overwriteValue(fieldValue, evaluation); } Map variableValues = recordedValues.getRecordedVariableValues(); if (variableValues != null) for (Iterator it = variableValues.entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = it.next(); String variableName = (String)entry.getKey(); Object variableValue = entry.getValue(); JRFillVariable variable = getVariable(variableName); variable.overwriteValue(variableValue, evaluation); } } private void restoreValues(JRRecordedValues recordedValues, byte evaluation) { Map fieldValues = recordedValues.getRecordedFieldValues(); if (fieldValues != null) for (Iterator it = fieldValues.keySet().iterator(); it.hasNext(); ) { String fieldName = it.next(); JRFillField field = getField(fieldName); field.restoreValue(evaluation); } Map variableValues = recordedValues.getRecordedVariableValues(); if (variableValues != null) for (Iterator it = variableValues.keySet().iterator(); it.hasNext(); ) { String variableName = it.next(); JRFillVariable variable = getVariable(variableName); variable.restoreValue(evaluation); } } protected void setConditionalStylesContainer(JRFillElementContainer conditionalStylesContainer) { this.conditionalStylesContainer = conditionalStylesContainer; } public JRStyle getStyle() { JRStyle crtStyle = this.initStyle; boolean isUsingDefaultStyle = false; if (crtStyle == null) { crtStyle = this.filler.getDefaultStyle(); isUsingDefaultStyle = true; } JRStyle evalStyle = crtStyle; if (this.conditionalStylesContainer != null) evalStyle = this.conditionalStylesContainer.getEvaluatedConditionalStyle(crtStyle); if (isUsingDefaultStyle && evalStyle == crtStyle) evalStyle = null; return evalStyle; } protected JRTemplateElement getTemplate(JRStyle style) { return (JRTemplateElement)this.templates.get(style); } protected void registerTemplate(JRStyle style, JRTemplateElement template) { this.templates.put(style, template); } protected final void setShrinkable(boolean shrinkable) { this.shrinkable = shrinkable; } protected void stretchHeightFinal() {} protected boolean isEvaluateNow() { switch (getEvaluationTime()) { case 1: evaluateNow = true; return evaluateNow; case 7: evaluateNow = isAutoEvaluateNow(); return evaluateNow; } boolean evaluateNow = false; return evaluateNow; } protected boolean isAutoEvaluateNow() { return (this.delayedEvaluationsMap == null || this.delayedEvaluationsMap.isEmpty() || (this.delayedEvaluationsMap.size() == 1 && this.delayedEvaluationsMap.containsKey(JREvaluationTime.EVALUATION_TIME_NOW))); } protected boolean isEvaluateAuto() { return (getEvaluationTime() == 7 && !isAutoEvaluateNow()); } public String getStyleNameReference() { return null; } public void setStyle(JRStyle style) { this.initStyle = style; this.conditionalStylesContainer.collectConditionalStyle(style); } public void setStyleNameReference(String name) { throw new UnsupportedOperationException("Style name references not allowed at fill time"); } public Object clone() { return null; } public Object clone(JRElementGroup parentGroup) { return null; } public boolean hasProperties() { return (this.mergedProperties != null && this.mergedProperties.hasProperties()); } public JRPropertiesMap getPropertiesMap() { return this.mergedProperties; } public JRPropertiesHolder getParentProperties() { return (JRPropertiesHolder)this.filler.getJasperReport(); } public JRPropertyExpression[] getPropertyExpressions() { return this.parent.getPropertyExpressions(); } protected void transferProperties(JRTemplateElement template) { JRProperties.transferProperties((JRPropertiesHolder)this.parent, template, "net.sf.jasperreports.print.transfer."); } protected void transferProperties(JRPrintElement element) { JRProperties.transferProperties(this.dynamicProperties, (JRPropertiesHolder)element, "net.sf.jasperreports.print.transfer."); } protected JRPropertiesMap getEvaluatedProperties() { return this.mergedProperties; } protected void evaluateProperties(byte evaluation) throws JRException { JRPropertyExpression[] propExprs = getPropertyExpressions(); if (propExprs == null || propExprs.length == 0) { this.dynamicProperties = null; this.mergedProperties = this.staticProperties; } else { this.dynamicProperties = new JRPropertiesMap(); for (int i = 0; i < propExprs.length; i++) { JRPropertyExpression prop = propExprs[i]; String value = (String)evaluateExpression(prop.getValueExpression(), evaluation); if (value != null) this.dynamicProperties.setProperty(prop.getName(), value); } this.mergedProperties = this.dynamicProperties.cloneProperties(); this.mergedProperties.setBaseProperties(this.staticProperties); } } }