Files
HRMS/hrmsEjb/net/sf/jasperreports/engine/fill/JRFillCrosstab.java
2025-07-28 13:56:49 +05:30

1332 lines
56 KiB
Java

package net.sf.jasperreports.engine.fill;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import net.sf.jasperreports.crosstabs.JRCellContents;
import net.sf.jasperreports.crosstabs.JRCrosstab;
import net.sf.jasperreports.crosstabs.JRCrosstabBucket;
import net.sf.jasperreports.crosstabs.JRCrosstabCell;
import net.sf.jasperreports.crosstabs.JRCrosstabColumnGroup;
import net.sf.jasperreports.crosstabs.JRCrosstabDataset;
import net.sf.jasperreports.crosstabs.JRCrosstabGroup;
import net.sf.jasperreports.crosstabs.JRCrosstabMeasure;
import net.sf.jasperreports.crosstabs.JRCrosstabParameter;
import net.sf.jasperreports.crosstabs.JRCrosstabRowGroup;
import net.sf.jasperreports.crosstabs.base.JRBaseCrosstab;
import net.sf.jasperreports.crosstabs.design.JRDesignCrosstab;
import net.sf.jasperreports.crosstabs.fill.JRCrosstabExpressionEvaluator;
import net.sf.jasperreports.crosstabs.fill.JRFillCrosstabCell;
import net.sf.jasperreports.crosstabs.fill.JRFillCrosstabColumnGroup;
import net.sf.jasperreports.crosstabs.fill.JRFillCrosstabGroup;
import net.sf.jasperreports.crosstabs.fill.JRFillCrosstabMeasure;
import net.sf.jasperreports.crosstabs.fill.JRFillCrosstabParameter;
import net.sf.jasperreports.crosstabs.fill.JRFillCrosstabRowGroup;
import net.sf.jasperreports.crosstabs.fill.calculation.BucketDefinition;
import net.sf.jasperreports.crosstabs.fill.calculation.BucketingService;
import net.sf.jasperreports.crosstabs.fill.calculation.CrosstabCell;
import net.sf.jasperreports.crosstabs.fill.calculation.HeaderCell;
import net.sf.jasperreports.crosstabs.fill.calculation.MeasureDefinition;
import net.sf.jasperreports.engine.JRCommonElement;
import net.sf.jasperreports.engine.JRDatasetParameter;
import net.sf.jasperreports.engine.JRElement;
import net.sf.jasperreports.engine.JRElementDataset;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRExpressionChunk;
import net.sf.jasperreports.engine.JRExpressionCollector;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPrintFrame;
import net.sf.jasperreports.engine.JRPrintRectangle;
import net.sf.jasperreports.engine.JRRectangle;
import net.sf.jasperreports.engine.JRReport;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.JRStyle;
import net.sf.jasperreports.engine.JRVariable;
import net.sf.jasperreports.engine.JRVisitor;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JRDesignRectangle;
import net.sf.jasperreports.engine.util.JRStyleResolver;
import org.jfree.data.general.Dataset;
public class JRFillCrosstab extends JRFillElement implements JRCrosstab {
protected final JRCrosstab parentCrosstab;
protected JRFillCrosstabDataset dataset;
protected JRFillCrosstabRowGroup[] rowGroups;
protected Map rowGroupsMap;
protected JRFillCrosstabColumnGroup[] columnGroups;
protected Map columnGroupsMap;
protected JRFillCrosstabMeasure[] measures;
protected BucketingService bucketingService;
protected JRFillVariable[] variables;
protected Map variablesMap;
protected JRFillVariable[][][] totalVariables;
protected boolean[][] retrieveTotal;
protected JRFillCrosstabParameter[] parameters;
protected Map parametersMap;
protected JRCrosstabExpressionEvaluator crosstabEvaluator;
protected JRFillCrosstabCell[][] crossCells;
protected JRFillCellContents headerCell;
protected JRFillCellContents whenNoDataCell;
protected boolean hasData;
protected HeaderCell[][] columnHeadersData;
protected HeaderCell[][] rowHeadersData;
protected CrosstabCell[][] cellData;
protected MeasureDefinition.MeasureValue[] grandTotals;
private boolean percentage;
private CrosstabFiller crosstabFiller;
public JRFillCrosstab(JRBaseFiller filler, JRCrosstab crosstab, JRFillObjectFactory factory) {
super(filler, (JRElement)crosstab, factory);
this.parentCrosstab = crosstab;
loadEvaluator(filler.getJasperReport());
JRFillObjectFactory crosstabFactory = new JRFillObjectFactory(factory, (JRFillExpressionEvaluator)this.crosstabEvaluator);
this.headerCell = crosstabFactory.getCell(crosstab.getHeaderCell());
copyRowGroups(crosstab, crosstabFactory);
copyColumnGroups(crosstab, crosstabFactory);
copyMeasures(crosstab, crosstabFactory);
copyCells(crosstab, crosstabFactory);
this.whenNoDataCell = crosstabFactory.getCell(crosstab.getWhenNoDataCell());
this.dataset = factory.getCrosstabDataset(crosstab.getDataset(), this);
copyParameters(crosstab, factory);
copyVariables(crosstab, crosstabFactory);
this.crosstabFiller = new CrosstabFiller();
}
public byte getMode() {
return JRStyleResolver.getMode((JRCommonElement)this, (byte)2);
}
private void copyRowGroups(JRCrosstab crosstab, JRFillObjectFactory factory) {
JRCrosstabRowGroup[] groups = crosstab.getRowGroups();
this.rowGroups = new JRFillCrosstabRowGroup[groups.length];
this.rowGroupsMap = new HashMap();
for (int i = 0; i < groups.length; i++) {
JRFillCrosstabRowGroup group = factory.getCrosstabRowGroup(groups[i]);
group.getFillHeader().setVerticalPositionType(groups[i].getPosition());
this.rowGroups[i] = group;
this.rowGroupsMap.put(group.getName(), new Integer(i));
}
}
private void copyColumnGroups(JRCrosstab crosstab, JRFillObjectFactory factory) {
JRCrosstabColumnGroup[] groups = crosstab.getColumnGroups();
this.columnGroups = new JRFillCrosstabColumnGroup[groups.length];
this.columnGroupsMap = new HashMap();
for (int i = 0; i < groups.length; i++) {
JRFillCrosstabColumnGroup group = factory.getCrosstabColumnGroup(groups[i]);
this.columnGroups[i] = group;
this.columnGroupsMap.put(group.getName(), new Integer(i));
}
}
private void copyMeasures(JRCrosstab crosstab, JRFillObjectFactory factory) {
JRCrosstabMeasure[] crossMeasures = crosstab.getMeasures();
this.measures = new JRFillCrosstabMeasure[crossMeasures.length];
for (int i = 0; i < crossMeasures.length; i++)
this.measures[i] = factory.getCrosstabMeasure(crossMeasures[i]);
}
private void copyParameters(JRCrosstab crosstab, JRFillObjectFactory factory) {
JRCrosstabParameter[] crossParams = crosstab.getParameters();
this.parameters = new JRFillCrosstabParameter[crossParams.length];
this.parametersMap = new HashMap();
for (int i = 0; i < crossParams.length; i++) {
this.parameters[i] = factory.getCrosstabParameter(crossParams[i]);
this.parametersMap.put(this.parameters[i].getName(), this.parameters[i]);
}
}
private void copyCells(JRCrosstab crosstab, JRFillObjectFactory factory) {
JRCrosstabCell[][] crosstabCells = crosstab.getCells();
this.crossCells = new JRFillCrosstabCell[this.rowGroups.length + 1][this.columnGroups.length + 1];
for (int i = 0; i <= this.rowGroups.length; i++) {
for (int j = 0; j <= this.columnGroups.length; j++) {
if (crosstabCells[i][j] != null)
this.crossCells[i][j] = factory.getCrosstabCell(crosstabCells[i][j]);
}
}
}
private void copyVariables(JRCrosstab crosstab, JRFillObjectFactory factory) {
JRVariable[] vars = crosstab.getVariables();
this.variables = new JRFillVariable[vars.length];
this.variablesMap = new HashMap();
for (int i = 0; i < this.variables.length; i++) {
this.variables[i] = factory.getVariable(vars[i]);
this.variablesMap.put(this.variables[i].getName(), this.variables[i]);
}
Map totalVarPos = new HashMap();
this.totalVariables = new JRFillVariable[this.rowGroups.length + 1][this.columnGroups.length + 1][this.measures.length];
for (int row = 0; row <= this.rowGroups.length; row++) {
JRFillCrosstabRowGroup jRFillCrosstabRowGroup = (row == this.rowGroups.length) ? null : this.rowGroups[row];
for (int col = 0; col <= this.columnGroups.length; col++) {
JRFillCrosstabColumnGroup jRFillCrosstabColumnGroup = (col == this.columnGroups.length) ? null : this.columnGroups[col];
if (row < this.rowGroups.length || col < this.columnGroups.length)
for (int m = 0; m < this.measures.length; m++) {
String totalVariableName = JRDesignCrosstab.getTotalVariableName((JRCrosstabMeasure)this.measures[m], (JRCrosstabRowGroup)jRFillCrosstabRowGroup, (JRCrosstabColumnGroup)jRFillCrosstabColumnGroup);
this.totalVariables[row][col][m] = (JRFillVariable)this.variablesMap.get(totalVariableName);
totalVarPos.put(totalVariableName, new int[] { row, col });
}
}
}
this.retrieveTotal = new boolean[this.rowGroups.length + 1][this.columnGroups.length + 1];
List expressions = JRExpressionCollector.collectExpressions((JRReport)this.filler.getJasperReport(), crosstab);
for (Iterator iter = expressions.iterator(); iter.hasNext(); ) {
JRExpression expression = iter.next();
JRExpressionChunk[] chunks = expression.getChunks();
if (chunks != null)
for (int j = 0; j < chunks.length; j++) {
JRExpressionChunk chunk = chunks[j];
if (chunk.getType() == 4) {
String varName = chunk.getText();
int[] pos = (int[])totalVarPos.get(varName);
if (pos != null)
this.retrieveTotal[pos[0]][pos[1]] = true;
}
}
}
}
protected void loadEvaluator(JasperReport jasperReport) {
try {
JREvaluator evaluator = JasperCompileManager.loadEvaluator(jasperReport, this.parentCrosstab);
this.crosstabEvaluator = new JRCrosstabExpressionEvaluator(evaluator);
} catch (JRException e) {
throw new JRRuntimeException("Could not load evaluator for crosstab.", e);
}
}
private BucketingService createService(byte evaluation) throws JRException {
List rowBuckets = new ArrayList(this.rowGroups.length);
for (int i = 0; i < this.rowGroups.length; i++)
rowBuckets.add(createServiceBucket((JRCrosstabGroup)this.rowGroups[i], evaluation));
List colBuckets = new ArrayList(this.columnGroups.length);
for (int j = 0; j < this.columnGroups.length; j++)
colBuckets.add(createServiceBucket((JRCrosstabGroup)this.columnGroups[j], evaluation));
this.percentage = false;
List measureList = new ArrayList(this.measures.length);
for (int k = 0; k < this.measures.length; k++) {
measureList.add(createServiceMeasure(this.measures[k]));
this.percentage |= (this.measures[k].getPercentageOfType() == 1) ? 1 : 0;
}
if (this.percentage) {
((BucketDefinition)rowBuckets.get(0)).setComputeTotal();
((BucketDefinition)colBuckets.get(0)).setComputeTotal();
}
return new BucketingService(rowBuckets, colBuckets, measureList, this.dataset.isDataPreSorted(), this.retrieveTotal);
}
private BucketDefinition createServiceBucket(JRCrosstabGroup group, byte evaluation) throws JRException {
JRCrosstabBucket bucket = group.getBucket();
Comparator comparator = null;
JRExpression comparatorExpression = bucket.getComparatorExpression();
if (comparatorExpression != null)
comparator = (Comparator)evaluateExpression(comparatorExpression, evaluation);
byte totalPosition = group.getTotalPosition();
return new BucketDefinition(bucket.getExpression().getValueClass(), comparator, bucket.getOrder(), totalPosition);
}
private MeasureDefinition createServiceMeasure(JRFillCrosstabMeasure measure) {
return new MeasureDefinition(measure.getValueClass(), measure.getCalculation(), measure.getIncrementerFactory());
}
protected void reset() {
super.reset();
for (int i = 0; i < this.variables.length; i++) {
this.variables[i].setValue(null);
this.variables[i].setInitialized(true);
}
}
protected void evaluate(byte evaluation) throws JRException {
reset();
evaluatePrintWhenExpression(evaluation);
evaluateProperties(evaluation);
if (isPrintWhenExpressionNull() || isPrintWhenTrue()) {
this.dataset.evaluateDatasetRun(evaluation);
initEvaluator(evaluation);
this.bucketingService.processData();
this.hasData = this.bucketingService.hasData();
if (this.hasData) {
this.columnHeadersData = this.bucketingService.getColumnHeaders();
this.rowHeadersData = this.bucketingService.getRowHeaders();
this.cellData = this.bucketingService.getCrosstabCells();
if (this.percentage)
this.grandTotals = this.bucketingService.getGrandTotals();
this.crosstabFiller.initCrosstab();
}
}
}
protected void initEvaluator(byte evaluation) throws JRException {
Map parameterValues = JRFillSubreport.getParameterValues(this.filler, getParametersMapExpression(), (JRDatasetParameter[])getParameters(), evaluation, true, false, false);
ResourceBundle resBdl = (ResourceBundle)parameterValues.get("REPORT_RESOURCE_BUNDLE");
if (resBdl == null) {
JRFillParameter resourceBundleParam = (JRFillParameter)this.filler.getParametersMap().get("REPORT_RESOURCE_BUNDLE");
parameterValues.put("REPORT_RESOURCE_BUNDLE", resourceBundleParam.getValue());
}
parameterValues.put("REPORT_PARAMETERS_MAP", parameterValues);
for (int i = 0; i < this.parameters.length; i++) {
Object value = parameterValues.get(this.parameters[i].getName());
this.parameters[i].setValue(value);
}
this.crosstabEvaluator.init(this.parametersMap, this.variablesMap, this.filler.getWhenResourceMissingType());
}
protected void initBucketingService() {
if (this.bucketingService == null) {
try {
this.bucketingService = createService((byte)1);
} catch (JRException e) {
throw new JRRuntimeException("Could not create bucketing service", e);
}
} else {
this.bucketingService.clear();
}
}
protected boolean prepare(int availableStretchHeight, boolean isOverflow) throws JRException {
super.prepare(availableStretchHeight, isOverflow);
if (!isToPrint())
return false;
if (availableStretchHeight < getRelativeY() - getY() - getBandBottomY()) {
setToPrint(false);
return true;
}
if (isOverflow && this.crosstabFiller.ended() && isAlreadyPrinted())
if (isPrintWhenDetailOverflows()) {
rewind();
setReprinted(true);
} else {
setStretchHeight(getHeight());
setToPrint(false);
return false;
}
if (isOverflow && isPrintWhenDetailOverflows())
setReprinted(true);
int availableHeight = getHeight() + availableStretchHeight - getRelativeY() + getY() + getBandBottomY();
this.crosstabFiller.fill(availableHeight);
boolean willOverflow = this.crosstabFiller.willOverflow();
setStretchHeight(willOverflow ? availableHeight : this.crosstabFiller.getUsedHeight());
return willOverflow;
}
protected JRPrintElement fill() {
JRPrintRectangle printRectangle = null;
printRectangle = new JRTemplatePrintRectangle(getJRTemplateRectangle());
printRectangle.setX(getX());
printRectangle.setY(getRelativeY());
printRectangle.setWidth(getWidth());
printRectangle.setHeight(getStretchHeight());
return (JRPrintElement)printRectangle;
}
protected JRTemplateRectangle getJRTemplateRectangle() {
JRStyle style = getStyle();
JRTemplateRectangle template = (JRTemplateRectangle)getTemplate(style);
if (template == null) {
JRDesignRectangle rectangle = new JRDesignRectangle();
rectangle.setKey(getKey());
rectangle.setPositionType(getPositionType());
rectangle.setMode(getMode());
rectangle.setX(getX());
rectangle.setY(getY());
rectangle.setWidth(getWidth());
rectangle.setHeight(getHeight());
rectangle.setRemoveLineWhenBlank(isRemoveLineWhenBlank());
rectangle.setPrintInFirstWholeBand(isPrintInFirstWholeBand());
rectangle.setPrintWhenDetailOverflows(isPrintWhenDetailOverflows());
rectangle.setPrintWhenGroupChanges(getPrintWhenGroupChanges());
rectangle.setForecolor(getForecolor());
rectangle.setBackcolor(getBackcolor());
rectangle.getLinePen().setLineWidth(0.0F);
template = new JRTemplateRectangle(this.band.getOrigin(), this.filler.getJasperPrint().getDefaultStyleProvider(), (JRRectangle)rectangle);
registerTemplate(style, template);
}
return template;
}
protected void rewind() {
this.crosstabFiller.initCrosstab();
}
protected List getPrintElements() {
List printElements = this.crosstabFiller.getPrintElements();
if (getRunDirection() == 1)
mirrorPrintElements(printElements);
return printElements;
}
protected void mirrorPrintElements(List printElements) {
for (Iterator it = printElements.iterator(); it.hasNext(); ) {
JRPrintElement element = it.next();
int mirrorX = getWidth() - element.getX() - element.getWidth();
element.setX(mirrorX);
}
}
protected void resolveElement(JRPrintElement element, byte evaluation) {}
public void collectExpressions(JRExpressionCollector collector) {
collector.collect(this);
}
public void visit(JRVisitor visitor) {
visitor.visitCrosstab(this);
}
public int getId() {
return this.parentCrosstab.getId();
}
public JRCrosstabDataset getDataset() {
return this.dataset;
}
public JRCrosstabRowGroup[] getRowGroups() {
return (JRCrosstabRowGroup[])this.rowGroups;
}
public JRCrosstabColumnGroup[] getColumnGroups() {
return (JRCrosstabColumnGroup[])this.columnGroups;
}
public JRCrosstabMeasure[] getMeasures() {
return (JRCrosstabMeasure[])this.measures;
}
public class JRFillCrosstabDataset extends JRFillElementDataset implements JRCrosstabDataset {
private Object[] bucketValues;
private Object[] measureValues;
private final JRFillCrosstab this$0;
public JRFillCrosstabDataset(JRCrosstabDataset dataset, JRFillObjectFactory factory) {
super((JRElementDataset)dataset, factory);
this.bucketValues = new Object[JRFillCrosstab.this.rowGroups.length + JRFillCrosstab.this.columnGroups.length];
this.measureValues = new Object[JRFillCrosstab.this.measures.length];
}
protected void customInitialize() {
JRFillCrosstab.this.initBucketingService();
}
protected void customEvaluate(JRCalculator calculator) throws JRExpressionEvalException {
int i;
for (i = 0; i < JRFillCrosstab.this.rowGroups.length; i++)
this.bucketValues[i] = calculator.evaluate(JRFillCrosstab.this.rowGroups[i].getBucket().getExpression());
for (i = 0; i < JRFillCrosstab.this.columnGroups.length; i++)
this.bucketValues[i + JRFillCrosstab.this.rowGroups.length] = calculator.evaluate(JRFillCrosstab.this.columnGroups[i].getBucket().getExpression());
for (i = 0; i < JRFillCrosstab.this.measures.length; i++)
this.measureValues[i] = calculator.evaluate(JRFillCrosstab.this.measures[i].getValueExpression());
}
protected void customIncrement() {
try {
JRFillCrosstab.this.bucketingService.addData(this.bucketValues, this.measureValues);
} catch (JRException e) {
throw new JRRuntimeException("Error incrementing crosstab dataset", e);
}
}
protected Dataset getCustomDataset() {
return null;
}
public void collectExpressions(JRExpressionCollector collector) {}
public boolean isDataPreSorted() {
return ((JRCrosstabDataset)this.parent).isDataPreSorted();
}
}
protected class CrosstabFiller {
private int yOffset;
private boolean willOverflow;
private int[] rowHeadersXOffsets;
private boolean[] columnBreakable;
private boolean[] rowBreakable;
private int[] columnCount;
private int[] rowCount;
private int[] columnXOffsets;
private boolean noDataCellPrinted;
private int startRowIndex;
private int startColumnIndex;
private int lastColumnIndex;
private List columnHeaders;
private List printRows;
private HeaderCell[] spanHeaders;
private int[] spanHeadersStart;
private List rowYs = new ArrayList();
private int rowIdx;
private List preparedRow = new ArrayList();
private int preparedRowHeight;
private boolean printRowHeaders;
private boolean printColumnHeaders;
private JRFillVariable rowCountVar;
private JRFillVariable colCountVar;
private final JRFillCrosstab this$0;
protected CrosstabFiller() {
setRowHeadersXOffsets();
this.printRows = new ArrayList();
this.rowCountVar = (JRFillVariable)JRFillCrosstab.this.variablesMap.get("ROW_COUNT");
this.colCountVar = (JRFillVariable)JRFillCrosstab.this.variablesMap.get("COLUMN_COUNT");
}
protected void initCrosstab() {
this.columnXOffsets = computeOffsets(JRFillCrosstab.this.columnHeadersData, (JRFillCrosstabGroup[])JRFillCrosstab.this.columnGroups, true);
this.columnBreakable = computeBreakableHeaders(JRFillCrosstab.this.columnHeadersData, (JRFillCrosstabGroup[])JRFillCrosstab.this.columnGroups, this.columnXOffsets, true, true);
this.columnCount = computeCounts(JRFillCrosstab.this.columnHeadersData);
int[] rowYOffsets = computeOffsets(JRFillCrosstab.this.rowHeadersData, (JRFillCrosstabGroup[])JRFillCrosstab.this.rowGroups, false);
this.rowBreakable = computeBreakableHeaders(JRFillCrosstab.this.rowHeadersData, (JRFillCrosstabGroup[])JRFillCrosstab.this.rowGroups, rowYOffsets, false, false);
this.rowCount = computeCounts(JRFillCrosstab.this.rowHeadersData);
this.spanHeaders = new HeaderCell[JRFillCrosstab.this.rowGroups.length - 1];
this.spanHeadersStart = new int[JRFillCrosstab.this.rowGroups.length - 1];
this.startRowIndex = 0;
this.startColumnIndex = 0;
this.lastColumnIndex = 0;
this.noDataCellPrinted = false;
}
protected void setRowHeadersXOffsets() {
this.rowHeadersXOffsets = new int[JRFillCrosstab.this.rowGroups.length + 1];
this.rowHeadersXOffsets[0] = 0;
for (int i = 0; i < JRFillCrosstab.this.rowGroups.length; i++)
this.rowHeadersXOffsets[i + 1] = this.rowHeadersXOffsets[i] + JRFillCrosstab.this.rowGroups[i].getWidth();
}
protected int[] computeOffsets(HeaderCell[][] headersData, JRFillCrosstabGroup[] groups, boolean width) {
int[] offsets = new int[(headersData[0]).length + 1];
offsets[0] = 0;
for (int i = 0; i < (headersData[0]).length; i++) {
int size = 0;
for (int j = groups.length - 1; j >= 0; j--) {
if (headersData[j][i] != null) {
JRFillCellContents cell = headersData[j][i].isTotal() ? groups[j].getFillTotalHeader() : groups[j].getFillHeader();
size = (cell == null) ? 0 : (width ? cell.getWidth() : cell.getHeight());
break;
}
}
offsets[i + 1] = offsets[i] + size;
}
return offsets;
}
protected boolean[] computeBreakableHeaders(HeaderCell[][] headersData, JRFillCrosstabGroup[] groups, int[] offsets, boolean width, boolean startHeaders) {
boolean[] breakable = new boolean[(headersData[0]).length];
for (int i = 0; i < breakable.length; i++)
breakable[i] = true;
for (int j = 0; j < groups.length; j++) {
JRFillCellContents fillHeader = groups[j].getFillHeader();
if (fillHeader != null) {
int size = width ? fillHeader.getWidth() : fillHeader.getHeight();
for (int k = 0; k < (headersData[0]).length; k++) {
HeaderCell header = headersData[j][k];
if (header != null && !header.isTotal() && header.getLevelSpan() > 1) {
int span = header.getLevelSpan();
if (startHeaders)
for (int n = k + 1; n < k + span && offsets[n] - offsets[k] < size; n++)
breakable[n] = false;
for (int m = k + span - 1; m > k && offsets[k + span] - offsets[m] < size; m--)
breakable[m] = false;
}
}
}
}
return breakable;
}
private int[] computeCounts(HeaderCell[][] headersData) {
int[] counts = new int[(headersData[0]).length];
HeaderCell[] lastHeaders = headersData[headersData.length - 1];
for (int i = 0, c = 0; i < counts.length; i++) {
HeaderCell lastHeader = lastHeaders[i];
if (lastHeader != null && !lastHeader.isTotal())
c++;
counts[i] = c;
}
return counts;
}
protected void fill(int availableHeight) throws JRException {
this.printRows.clear();
this.yOffset = 0;
this.willOverflow = false;
fillVerticalCrosstab(availableHeight);
}
protected boolean willOverflow() {
return this.willOverflow;
}
protected int getUsedHeight() {
return this.yOffset;
}
protected boolean ended() {
return JRFillCrosstab.this.hasData ? ((this.startRowIndex >= (JRFillCrosstab.this.rowHeadersData[0]).length && this.startColumnIndex >= (JRFillCrosstab.this.columnHeadersData[0]).length)) : this.noDataCellPrinted;
}
protected void fillVerticalCrosstab(int availableHeight) throws JRException {
if (!JRFillCrosstab.this.hasData) {
fillNoDataCell(availableHeight);
return;
}
this.printRowHeaders = (this.startColumnIndex == 0 || JRFillCrosstab.this.isRepeatRowHeaders());
int rowHeadersXOffset = this.printRowHeaders ? this.rowHeadersXOffsets[JRFillCrosstab.this.rowGroups.length] : 0;
if (this.startColumnIndex == this.lastColumnIndex) {
int availableWidth = JRFillCrosstab.this.getWidth();
this.columnHeaders = getGroupHeaders(availableWidth - rowHeadersXOffset, this.columnXOffsets, this.columnBreakable, this.startColumnIndex, JRFillCrosstab.this.columnHeadersData, (JRFillCrosstabGroup[])JRFillCrosstab.this.columnGroups);
this.lastColumnIndex = this.startColumnIndex + this.columnHeaders.size();
if (this.startColumnIndex == this.lastColumnIndex)
throw new JRRuntimeException("Not enough space to render the crosstab.");
}
this.printColumnHeaders = (this.startRowIndex == 0 || JRFillCrosstab.this.isRepeatColumnHeaders());
List columnHeaderRows = null;
if (this.printColumnHeaders) {
columnHeaderRows = fillColumnHeaders(rowHeadersXOffset, availableHeight - this.yOffset);
if (this.willOverflow)
return;
}
int lastRowIndex = fillRows(rowHeadersXOffset, availableHeight - this.yOffset);
if (lastRowIndex == this.startRowIndex) {
this.willOverflow = true;
return;
}
if (columnHeaderRows != null)
this.printRows.addAll(columnHeaderRows);
if (lastRowIndex >= (JRFillCrosstab.this.rowHeadersData[0]).length) {
this.startColumnIndex = this.lastColumnIndex;
if (this.startColumnIndex < (JRFillCrosstab.this.columnHeadersData[0]).length) {
this.startRowIndex = lastRowIndex = 0;
this.yOffset += JRFillCrosstab.this.getColumnBreakOffset();
fillVerticalCrosstab(availableHeight);
return;
}
}
boolean fillEnded = (lastRowIndex >= (JRFillCrosstab.this.rowHeadersData[0]).length && this.lastColumnIndex >= (JRFillCrosstab.this.columnHeadersData[0]).length);
if (fillEnded) {
JRFillCrosstab.this.setStretchHeight(this.yOffset);
} else {
JRFillCrosstab.this.setStretchHeight(availableHeight);
}
this.startRowIndex = lastRowIndex;
this.willOverflow = !fillEnded;
}
protected List getGroupHeaders(int available, int[] offsets, boolean[] breakable, int firstIndex, HeaderCell[][] headersData, JRFillCrosstabGroup[] groups) {
List headers = new ArrayList();
int maxOffset = available + offsets[firstIndex];
int lastIndex;
for (lastIndex = firstIndex; lastIndex < (headersData[0]).length && offsets[lastIndex + 1] <= maxOffset; lastIndex++) {
HeaderCell[] groupHeaders = new HeaderCell[groups.length];
for (int j = 0; j < groups.length; j++)
groupHeaders[j] = headersData[j][lastIndex];
headers.add(groupHeaders);
}
if (lastIndex < (headersData[0]).length)
while (lastIndex > firstIndex && !breakable[lastIndex]) {
lastIndex--;
headers.remove(headers.size() - 1);
}
if (lastIndex > firstIndex) {
if (firstIndex > 0) {
HeaderCell[] firstHeaders = headers.get(0);
for (int j = 0; j < groups.length; j++) {
HeaderCell header = headersData[j][firstIndex];
if (header == null) {
int spanIndex = getSpanIndex(firstIndex, j, headersData);
if (spanIndex >= 0) {
HeaderCell spanCell = headersData[j][spanIndex];
int headerEndIdx = spanCell.getLevelSpan() + spanIndex;
if (headerEndIdx > lastIndex)
headerEndIdx = lastIndex;
firstHeaders[j] = HeaderCell.createLevelSpanCopy(spanCell, headerEndIdx - firstIndex);
}
}
}
}
if (lastIndex < (headersData[0]).length)
for (int j = 0; j < groups.length; j++) {
HeaderCell header = headersData[j][lastIndex];
if (header == null) {
int spanIndex = getSpanIndex(lastIndex, j, headersData);
if (spanIndex >= firstIndex) {
HeaderCell spanCell = headersData[j][spanIndex];
HeaderCell[] headerCells = headers.get(spanIndex - firstIndex);
headerCells[j] = HeaderCell.createLevelSpanCopy(spanCell, lastIndex - spanIndex);
}
}
}
}
return headers;
}
protected int getSpanIndex(int i, int j, HeaderCell[][] headersData) {
int spanIndex = i - 1;
while (spanIndex >= 0 && headersData[j][spanIndex] == null)
spanIndex--;
if (spanIndex >= 0) {
HeaderCell spanCell = headersData[j][spanIndex];
int span = spanCell.getLevelSpan();
if (span > i - spanIndex)
return spanIndex;
}
return -1;
}
protected void fillNoDataCell(int availableHeight) throws JRException {
if (JRFillCrosstab.this.whenNoDataCell == null) {
this.noDataCellPrinted = true;
} else if (availableHeight < JRFillCrosstab.this.whenNoDataCell.getHeight()) {
this.willOverflow = true;
} else {
JRFillCrosstab.this.whenNoDataCell.evaluate((byte)3);
JRFillCrosstab.this.whenNoDataCell.prepare(availableHeight - JRFillCrosstab.this.whenNoDataCell.getHeight());
this.willOverflow = JRFillCrosstab.this.whenNoDataCell.willOverflow();
if (!this.willOverflow) {
JRFillCrosstab.this.whenNoDataCell.setX(0);
JRFillCrosstab.this.whenNoDataCell.setY(0);
JRPrintFrame printCell = JRFillCrosstab.this.whenNoDataCell.fill();
List noDataRow = new ArrayList(1);
noDataRow.add(printCell);
addPrintRow(noDataRow);
this.yOffset += JRFillCrosstab.this.whenNoDataCell.getPrintHeight();
this.noDataCellPrinted = true;
}
}
}
protected List fillColumnHeaders(int rowHeadersXOffset, int availableHeight) throws JRException {
List headerRows;
JRFillCellContents[][] columnHeaderRows = new JRFillCellContents[JRFillCrosstab.this.columnGroups.length][this.lastColumnIndex - this.startColumnIndex + 1];
this.rowYs.clear();
this.rowYs.add(new Integer(0));
if (this.printRowHeaders && JRFillCrosstab.this.headerCell != null) {
JRFillCellContents contents = fillHeader(availableHeight);
if (this.willOverflow)
return null;
columnHeaderRows[JRFillCrosstab.this.columnGroups.length - 1][0] = contents;
}
label29: for (this.rowIdx = 0; this.rowIdx < JRFillCrosstab.this.columnGroups.length; this.rowIdx++) {
for (int columnIdx = this.startColumnIndex; columnIdx < this.lastColumnIndex; columnIdx++) {
HeaderCell[] headers = this.columnHeaders.get(columnIdx - this.startColumnIndex);
HeaderCell cell = headers[this.rowIdx];
if (cell != null) {
JRFillCellContents contents = prepareColumnHeader(cell, columnIdx, rowHeadersXOffset, availableHeight);
columnHeaderRows[this.rowIdx + cell.getDepthSpan() - 1][columnIdx - this.startColumnIndex + 1] = contents;
if (this.willOverflow)
break label29;
}
}
int rowStretchHeight = stretchColumnHeadersRow(columnHeaderRows[this.rowIdx]);
this.rowYs.add(new Integer(((Integer)this.rowYs.get(this.rowIdx)).intValue() + rowStretchHeight));
}
if (this.willOverflow) {
headerRows = null;
releaseColumnHeaderCells(columnHeaderRows);
} else {
headerRows = fillColumnHeaders(columnHeaderRows);
this.yOffset += ((Integer)this.rowYs.get(JRFillCrosstab.this.columnGroups.length)).intValue();
}
resetVariables();
return headerRows;
}
private void setCountVars(int rowIdx, int colIdx) {
if (rowIdx == -1) {
this.rowCountVar.setValue(null);
} else {
this.rowCountVar.setValue(new Integer(this.rowCount[rowIdx]));
}
if (colIdx == -1) {
this.colCountVar.setValue(null);
} else {
this.colCountVar.setValue(new Integer(this.columnCount[colIdx]));
}
}
private JRFillCellContents fillHeader(int availableHeight) throws JRException {
setCountVars(-1, -1);
JRFillCellContents contents = JRFillCrosstab.this.headerCell.getWorkingClone();
contents.evaluate((byte)3);
contents.prepare(availableHeight - JRFillCrosstab.this.headerCell.getHeight());
this.willOverflow = contents.willOverflow();
if (!this.willOverflow) {
contents.setX(0);
contents.setY(this.yOffset);
contents.setVerticalSpan(JRFillCrosstab.this.columnGroups.length);
}
return contents;
}
private JRFillCellContents prepareColumnHeader(HeaderCell cell, int columnIdx, int xOffset, int availableHeight) throws JRException {
JRFillCrosstabColumnGroup group = JRFillCrosstab.this.columnGroups[this.rowIdx];
JRFillCellContents contents = cell.isTotal() ? group.getFillTotalHeader() : group.getFillHeader();
int width = this.columnXOffsets[columnIdx + cell.getLevelSpan()] - this.columnXOffsets[columnIdx];
int height = contents.getHeight();
if (width <= 0 || height <= 0)
return null;
JRFillCellContents preparedContents = null;
int rowY = ((Integer)this.rowYs.get(this.rowIdx)).intValue();
int cellAvailableStretch = availableHeight - rowY - height;
if (cellAvailableStretch >= 0) {
setCountVars(-1, columnIdx);
setGroupVariables((JRFillCrosstabGroup[])JRFillCrosstab.this.columnGroups, cell.getBucketValues());
contents = contents.getTransformedContents(width, height, group.getPosition(), (byte)1);
boolean firstOnRow = (columnIdx == this.startColumnIndex && (!this.printRowHeaders || JRFillCrosstab.this.headerCell == null));
contents = contents.getBoxContents((firstOnRow && JRFillCrosstab.this.getRunDirection() == 0), (firstOnRow && JRFillCrosstab.this.getRunDirection() == 1), false);
contents = contents.getWorkingClone();
contents.evaluate((byte)3);
contents.prepare(cellAvailableStretch);
if (contents.willOverflow()) {
this.willOverflow = true;
} else {
contents.setX(this.columnXOffsets[columnIdx] - this.columnXOffsets[this.startColumnIndex] + xOffset);
contents.setY(rowY + this.yOffset);
contents.setVerticalSpan(cell.getDepthSpan());
preparedContents = contents;
}
} else {
this.willOverflow = true;
}
return preparedContents;
}
private int stretchColumnHeadersRow(JRFillCellContents[] headers) {
int rowY = ((Integer)this.rowYs.get(this.rowIdx)).intValue();
int rowStretchHeight = 0;
int j;
for (j = 0; j < headers.length; j++) {
JRFillCellContents contents = headers[j];
if (contents != null) {
int startRowY = rowY;
if (contents.getVerticalSpan() > 1)
startRowY = ((Integer)this.rowYs.get(this.rowIdx - contents.getVerticalSpan() + 1)).intValue();
int height = contents.getPrintHeight() - rowY + startRowY;
if (height > rowStretchHeight)
rowStretchHeight = height;
}
}
for (j = 0; j < headers.length; j++) {
JRFillCellContents contents = headers[j];
if (contents != null) {
int startRowY = rowY;
if (contents.getVerticalSpan() > 1)
startRowY = ((Integer)this.rowYs.get(this.rowIdx - contents.getVerticalSpan() + 1)).intValue();
contents.stretchTo(rowStretchHeight + rowY - startRowY);
}
}
return rowStretchHeight;
}
private List fillColumnHeaders(JRFillCellContents[][] columnHeaderRows) throws JRException {
List headerRows = new ArrayList(JRFillCrosstab.this.columnGroups.length);
for (int i = 0; i < columnHeaderRows.length; i++) {
List headerRow = new ArrayList(this.lastColumnIndex - this.startColumnIndex);
headerRows.add(headerRow);
for (int j = 0; j < (columnHeaderRows[i]).length; j++) {
JRFillCellContents contents = columnHeaderRows[i][j];
if (contents != null) {
headerRow.add(contents.fill());
contents.releaseWorkingClone();
}
}
}
return headerRows;
}
private void releaseColumnHeaderCells(JRFillCellContents[][] columnHeaderRows) throws JRException {
for (int i = 0; i < columnHeaderRows.length; i++) {
for (int j = 0; j < (columnHeaderRows[i]).length; j++) {
JRFillCellContents contents = columnHeaderRows[i][j];
if (contents != null) {
contents.rewind();
contents.releaseWorkingClone();
}
}
}
}
protected int fillRows(int xOffset, int availableHeight) throws JRException {
this.rowYs.clear();
this.rowYs.add(new Integer(0));
for (this.rowIdx = 0; this.rowIdx < JRFillCrosstab.this.cellData.length - this.startRowIndex; this.rowIdx++) {
initPreparedRow();
prepareRow(xOffset, availableHeight);
if (this.willOverflow)
break;
fillRow();
this.rowYs.add(new Integer(((Integer)this.rowYs.get(this.rowIdx)).intValue() + this.preparedRowHeight));
}
if (this.rowIdx < JRFillCrosstab.this.cellData.length - this.startRowIndex) {
releasePreparedRow();
if (this.printRowHeaders)
fillContinuingRowHeaders(xOffset, availableHeight);
}
this.yOffset += ((Integer)this.rowYs.get(this.rowIdx)).intValue();
return this.rowIdx + this.startRowIndex;
}
private void initPreparedRow() {
this.preparedRow.clear();
this.preparedRowHeight = 0;
}
private void removeFilledRows(int rowsToRemove) {
if (rowsToRemove > 0) {
for (int i = 0; i < rowsToRemove; i++) {
this.printRows.remove(this.printRows.size() - 1);
this.rowYs.remove(this.rowYs.size() - 1);
}
this.rowIdx -= rowsToRemove;
}
}
private void releasePreparedRow() throws JRException {
for (Iterator it = this.preparedRow.iterator(); it.hasNext(); ) {
JRFillCellContents cell = it.next();
cell.rewind();
cell.releaseWorkingClone();
}
this.preparedRow.clear();
}
private void fillRow() throws JRException {
int rowY = ((Integer)this.rowYs.get(this.rowIdx)).intValue();
List rowPrints = new ArrayList(this.preparedRow.size());
for (Iterator it = this.preparedRow.iterator(); it.hasNext(); ) {
JRFillCellContents cell = it.next();
int spanHeight = 0;
if (cell.getVerticalSpan() > 1)
spanHeight = rowY - ((Integer)this.rowYs.get(this.rowIdx - cell.getVerticalSpan() + 1)).intValue();
cell.stretchTo(this.preparedRowHeight + spanHeight);
rowPrints.add(cell.fill());
cell.releaseWorkingClone();
}
addPrintRow(rowPrints);
}
private void prepareRow(int xOffset, int availableHeight) throws JRException {
for (int col = this.startColumnIndex; col < this.lastColumnIndex; col++) {
CrosstabCell data = JRFillCrosstab.this.cellData[this.rowIdx + this.startRowIndex][col];
boolean overflow = prepareDataCell(data, col, availableHeight, xOffset);
if (overflow) {
this.willOverflow = true;
return;
}
}
resetVariables();
if (this.printRowHeaders) {
int j = 0;
while (true) {
boolean overflow;
if (j < JRFillCrosstab.this.rowGroups.length) {
HeaderCell cell = JRFillCrosstab.this.rowHeadersData[j][this.rowIdx + this.startRowIndex];
overflow = false;
if (cell == null) {
overflow = prepareClosingRowHeader(j, availableHeight);
} else {
if (cell.getLevelSpan() > 1) {
this.spanHeaders[j] = cell;
this.spanHeadersStart[j] = this.rowIdx + this.startRowIndex;
} else {
overflow = prepareRowHeader(j, cell, 1, availableHeight);
if (overflow) {
this.willOverflow = true;
return;
}
}
j++;
}
} else {
break;
}
if (overflow) {
this.willOverflow = true;
return;
}
}
resetVariables();
}
}
private boolean prepareDataCell(CrosstabCell data, int column, int availableHeight, int xOffset) throws JRException {
int rowY = ((Integer)this.rowYs.get(this.rowIdx)).intValue();
JRFillCrosstabCell cell = JRFillCrosstab.this.crossCells[data.getRowTotalGroupIndex()][data.getColumnTotalGroupIndex()];
JRFillCellContents contents = (cell == null) ? null : cell.getFillContents();
if (contents == null || contents.getWidth() <= 0 || contents.getHeight() <= 0)
return false;
int cellAvailableStretch = availableHeight - rowY - contents.getHeight();
boolean overflow = (cellAvailableStretch < 0);
if (!overflow) {
boolean leftEmpty = (this.startColumnIndex != 0 && !JRFillCrosstab.this.isRepeatRowHeaders());
boolean topEmpty = (this.startRowIndex != 0 && !JRFillCrosstab.this.isRepeatColumnHeaders());
setCountVars(this.rowIdx + this.startRowIndex, column);
setGroupVariables((JRFillCrosstabGroup[])JRFillCrosstab.this.rowGroups, data.getRowBucketValues());
setGroupVariables((JRFillCrosstabGroup[])JRFillCrosstab.this.columnGroups, data.getColumnBucketValues());
setMeasureVariables(data);
boolean firstOnRow = (leftEmpty && column == this.startColumnIndex);
contents = contents.getBoxContents((firstOnRow && JRFillCrosstab.this.getRunDirection() == 0), (firstOnRow && JRFillCrosstab.this.getRunDirection() == 1), (topEmpty && this.rowIdx == 0));
contents = contents.getWorkingClone();
contents.evaluate((byte)3);
contents.prepare(cellAvailableStretch);
this.preparedRow.add(contents);
overflow = contents.willOverflow();
if (!overflow) {
contents.setX(this.columnXOffsets[column] - this.columnXOffsets[this.startColumnIndex] + xOffset);
contents.setY(rowY + this.yOffset);
int rowCellHeight = contents.getPrintHeight();
if (rowCellHeight > this.preparedRowHeight)
this.preparedRowHeight = rowCellHeight;
}
}
return overflow;
}
private boolean prepareRowHeader(int rowGroup, HeaderCell cell, int vSpan, int availableHeight) throws JRException {
JRFillCrosstabRowGroup group = JRFillCrosstab.this.rowGroups[rowGroup];
JRFillCellContents contents = cell.isTotal() ? group.getFillTotalHeader() : group.getFillHeader();
if (contents.getWidth() <= 0 || contents.getHeight() <= 0)
return false;
int spanHeight = 0;
int headerY = ((Integer)this.rowYs.get(this.rowIdx - vSpan + 1)).intValue();
if (vSpan > 1)
spanHeight += ((Integer)this.rowYs.get(this.rowIdx)).intValue() - headerY;
int rowHeight = spanHeight + this.preparedRowHeight;
boolean stretchContents = (group.getPosition() == 4);
int contentsHeight = stretchContents ? rowHeight : contents.getHeight();
int cellAvailableStretch = availableHeight - headerY - contentsHeight;
boolean headerOverflow = (cellAvailableStretch < 0 || rowHeight < contents.getHeight());
if (!headerOverflow) {
setCountVars(this.rowIdx + this.startRowIndex - vSpan + 1, -1);
setGroupVariables((JRFillCrosstabGroup[])JRFillCrosstab.this.rowGroups, cell.getBucketValues());
if (stretchContents)
contents = contents.getTransformedContents(contents.getWidth(), rowHeight, (byte)1, (byte)4);
contents = contents.getBoxContents(false, false, (this.rowIdx + 1 == vSpan && (!this.printColumnHeaders || JRFillCrosstab.this.headerCell == null)));
contents.getWorkingClone();
contents.evaluate((byte)3);
contents.prepare(cellAvailableStretch);
this.preparedRow.add(contents);
headerOverflow = contents.willOverflow();
if (!headerOverflow) {
contents.setX(this.rowHeadersXOffsets[rowGroup]);
contents.setY(headerY + this.yOffset);
contents.setVerticalSpan(vSpan);
int rowCellHeight = contents.getPrintHeight() - spanHeight;
if (rowCellHeight > this.preparedRowHeight)
this.preparedRowHeight = rowCellHeight;
}
}
if (headerOverflow)
removeFilledRows(vSpan - 1);
return headerOverflow;
}
private boolean prepareClosingRowHeader(int rowGroup, int availableHeight) throws JRException {
if (rowGroup < JRFillCrosstab.this.rowGroups.length - 1 && this.spanHeaders[rowGroup] != null && this.spanHeaders[rowGroup].getLevelSpan() + this.spanHeadersStart[rowGroup] == this.rowIdx + this.startRowIndex + 1) {
HeaderCell cell = this.spanHeaders[rowGroup];
int vSpan = cell.getLevelSpan();
if (this.spanHeadersStart[rowGroup] < this.startRowIndex)
vSpan += this.spanHeadersStart[rowGroup] - this.startRowIndex;
this.spanHeaders[rowGroup] = null;
return prepareRowHeader(rowGroup, cell, vSpan, availableHeight);
}
return false;
}
private void removeExceedingSpanHeaders() {
for (int j = JRFillCrosstab.this.rowGroups.length - 2; j >= 0; j--) {
if (this.spanHeaders[j] != null && this.spanHeadersStart[j] >= this.rowIdx + this.startRowIndex)
this.spanHeaders[j] = null;
}
}
private void setBackSpanHeaders() {
for (int j = JRFillCrosstab.this.rowGroups.length - 2; j >= 0 && this.spanHeaders[j] == null; j--) {
int spanIndex = getSpanIndex(this.rowIdx + this.startRowIndex, j, JRFillCrosstab.this.rowHeadersData);
if (spanIndex >= 0) {
this.spanHeaders[j] = JRFillCrosstab.this.rowHeadersData[j][spanIndex];
this.spanHeadersStart[j] = spanIndex;
}
}
}
private void fillContinuingRowHeaders(int xOffset, int availableHeight) throws JRException {
boolean done = false;
label27: do {
removeExceedingSpanHeaders();
if (!this.rowBreakable[this.rowIdx + this.startRowIndex]) {
removeFilledRows(1);
setBackSpanHeaders();
} else {
initPreparedRow();
for (int j = 0; j < JRFillCrosstab.this.rowGroups.length - 1; j++) {
if (this.spanHeaders[j] != null) {
boolean headerOverflow = prepareContinuingRowHeader(j, availableHeight);
if (headerOverflow) {
releasePreparedRow();
continue label27;
}
}
}
if (!this.preparedRow.isEmpty()) {
int lastRowHeight = ((Integer)this.rowYs.get(this.rowIdx)).intValue() - ((Integer)this.rowYs.get(this.rowIdx - 1)).intValue();
if (this.preparedRowHeight > lastRowHeight) {
refillLastRow(xOffset, availableHeight);
} else {
fillContinuingHeaders(lastRowHeight);
}
}
done = true;
}
} while (!done && this.rowIdx > 0);
}
private void fillContinuingHeaders(int lastRowHeight) throws JRException {
int nextToLastHeaderY = ((Integer)this.rowYs.get(this.rowIdx - 1)).intValue();
List lastPrintRow = getLastPrintRow();
for (int j = 0; j < this.preparedRow.size(); j++) {
JRFillCellContents contents = this.preparedRow.get(j);
int headerY = ((Integer)this.rowYs.get(this.rowIdx - contents.getVerticalSpan())).intValue();
contents.stretchTo(nextToLastHeaderY - headerY + lastRowHeight);
lastPrintRow.add(contents.fill());
contents.releaseWorkingClone();
}
}
private void refillLastRow(int xOffset, int availableHeight) throws JRException {
removeFilledRows(1);
setBackSpanHeaders();
prepareRow(xOffset, availableHeight);
fillRow();
this.rowYs.add(new Integer(((Integer)this.rowYs.get(this.rowIdx)).intValue() + this.preparedRowHeight));
this.rowIdx++;
}
private boolean prepareContinuingRowHeader(int rowGroup, int availableHeight) throws JRException {
HeaderCell cell = this.spanHeaders[rowGroup];
int vSpan = this.rowIdx + this.startRowIndex - this.spanHeadersStart[rowGroup];
if (this.spanHeadersStart[rowGroup] < this.startRowIndex)
vSpan += this.spanHeadersStart[rowGroup] - this.startRowIndex;
int headerY = ((Integer)this.rowYs.get(this.rowIdx - vSpan)).intValue();
int lastHeaderY = ((Integer)this.rowYs.get(this.rowIdx)).intValue();
int headerHeight = lastHeaderY - headerY;
int nextToLastHeaderY = ((Integer)this.rowYs.get(this.rowIdx - 1)).intValue();
int stretchHeight = nextToLastHeaderY - headerY;
JRFillCrosstabRowGroup group = JRFillCrosstab.this.rowGroups[rowGroup];
JRFillCellContents contents = cell.isTotal() ? group.getFillTotalHeader() : group.getFillHeader();
boolean stretchContents = (group.getPosition() == 4);
int contentsHeight = stretchContents ? headerHeight : contents.getHeight();
int cellAvailableStretch = availableHeight - headerY - contentsHeight;
boolean headerOverflow = (cellAvailableStretch < 0 || headerHeight < contents.getHeight());
if (!headerOverflow) {
setCountVars(this.rowIdx + this.startRowIndex - vSpan, -1);
setGroupVariables((JRFillCrosstabGroup[])JRFillCrosstab.this.rowGroups, cell.getBucketValues());
if (stretchContents)
contents = contents.getTransformedContents(contents.getWidth(), headerHeight, (byte)1, (byte)4);
contents = contents.getBoxContents(false, false, (this.rowIdx == vSpan && (!this.printColumnHeaders || JRFillCrosstab.this.headerCell == null)));
contents.getWorkingClone();
contents.evaluate((byte)3);
contents.prepare(cellAvailableStretch);
this.preparedRow.add(contents);
headerOverflow = contents.willOverflow();
if (!headerOverflow) {
contents.setX(this.rowHeadersXOffsets[rowGroup]);
contents.setY(headerY + this.yOffset);
contents.setVerticalSpan(vSpan);
int rowHeight = contents.getPrintHeight() - stretchHeight;
if (rowHeight > this.preparedRowHeight)
this.preparedRowHeight = rowHeight;
}
}
if (headerOverflow)
removeFilledRows(vSpan);
return headerOverflow;
}
protected void addPrintRow(List printRow) {
this.printRows.add(printRow);
}
protected List getLastPrintRow() {
return this.printRows.get(this.printRows.size() - 1);
}
protected List getPrintElements() {
List prints = new ArrayList();
for (Iterator it = this.printRows.iterator(); it.hasNext(); ) {
List rowPrints = it.next();
prints.addAll(rowPrints);
}
return prints;
}
protected void setGroupVariables(JRFillCrosstabGroup[] groups, BucketDefinition.Bucket[] bucketValues) {
for (int i = 0; i < groups.length; i++) {
Object value = null;
if (bucketValues[i] != null && !bucketValues[i].isTotal())
value = bucketValues[i].getValue();
groups[i].getFillVariable().setValue(value);
}
}
protected void setMeasureVariables(CrosstabCell cell) {
MeasureDefinition.MeasureValue[] values = cell.getMesureValues();
for (int i = 0; i < JRFillCrosstab.this.measures.length; i++) {
Object value = measureValue(values, i);
JRFillCrosstab.this.measures[i].getFillVariable().setValue(value);
}
MeasureDefinition.MeasureValue[][][] totals = cell.getTotals();
for (int row = 0; row <= JRFillCrosstab.this.rowGroups.length; row++) {
for (int col = 0; col <= JRFillCrosstab.this.columnGroups.length; col++) {
MeasureDefinition.MeasureValue[] vals = totals[row][col];
if (JRFillCrosstab.this.retrieveTotal[row][col])
for (int m = 0; m < JRFillCrosstab.this.measures.length; m++) {
JRFillVariable totalVar = JRFillCrosstab.this.totalVariables[row][col][m];
Object value = measureValue(vals, m);
totalVar.setValue(value);
}
}
}
}
protected Object measureValue(MeasureDefinition.MeasureValue[] values, int measureIdx) {
Object value;
if (JRFillCrosstab.this.measures[measureIdx].getPercentageOfType() == 1) {
if (values[measureIdx].isInitialized()) {
value = values[measureIdx].getValue();
} else {
value = JRFillCrosstab.this.measures[measureIdx].getPercentageCalculator().calculatePercentage((JRCalculable)values[measureIdx], (JRCalculable)JRFillCrosstab.this.grandTotals[measureIdx]);
}
} else {
value = values[measureIdx].getValue();
}
return value;
}
protected void resetVariables() {
int i;
for (i = 0; i < JRFillCrosstab.this.rowGroups.length; i++)
JRFillCrosstab.this.rowGroups[i].getFillVariable().setValue(null);
for (i = 0; i < JRFillCrosstab.this.columnGroups.length; i++)
JRFillCrosstab.this.columnGroups[i].getFillVariable().setValue(null);
for (i = 0; i < JRFillCrosstab.this.measures.length; i++)
JRFillCrosstab.this.measures[i].getFillVariable().setValue(null);
for (int row = 0; row <= JRFillCrosstab.this.rowGroups.length; row++) {
for (int col = 0; col <= JRFillCrosstab.this.columnGroups.length; col++) {
if (JRFillCrosstab.this.retrieveTotal[row][col])
for (int j = 0; j < JRFillCrosstab.this.measures.length; j++)
JRFillCrosstab.this.totalVariables[row][col][j].setValue(null);
}
}
}
}
public int getColumnBreakOffset() {
return this.parentCrosstab.getColumnBreakOffset();
}
public boolean isRepeatColumnHeaders() {
return this.parentCrosstab.isRepeatColumnHeaders();
}
public boolean isRepeatRowHeaders() {
return this.parentCrosstab.isRepeatRowHeaders();
}
public JRCrosstabCell[][] getCells() {
return (JRCrosstabCell[][])this.crossCells;
}
public JRCellContents getWhenNoDataCell() {
return this.whenNoDataCell;
}
public JRCrosstabParameter[] getParameters() {
return (JRCrosstabParameter[])this.parameters;
}
public JRExpression getParametersMapExpression() {
return this.parentCrosstab.getParametersMapExpression();
}
public JRElement getElementByKey(String elementKey) {
return JRBaseCrosstab.getElementByKey(this, elementKey);
}
public JRFillCloneable createClone(JRFillCloneFactory factory) {
return null;
}
public JRCellContents getHeaderCell() {
return this.headerCell;
}
public JRVariable[] getVariables() {
return (JRVariable[])this.variables;
}
public byte getRunDirection() {
return this.parentCrosstab.getRunDirection();
}
public void setRunDirection(byte direction) {}
}