Java tutorial
/* * JasperReports - Free Java Reporting Library. * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved. * http://www.jaspersoft.com * * Unless you have purchased a commercial license agreement from Jaspersoft, * the following license terms apply: * * This program is part of JasperReports. * * JasperReports is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JasperReports is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with JasperReports. If not, see <http://www.gnu.org/licenses/>. */ package net.sf.jasperreports.crosstabs.design; import java.awt.Color; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.TimeZone; import org.apache.commons.collections4.map.LinkedMap; import net.sf.jasperreports.crosstabs.CrosstabColumnCell; import net.sf.jasperreports.crosstabs.CrosstabDeepVisitor; 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.engine.JRConstants; import net.sf.jasperreports.engine.JRDefaultStyleProvider; import net.sf.jasperreports.engine.JRElement; import net.sf.jasperreports.engine.JRException; import net.sf.jasperreports.engine.JRExpression; import net.sf.jasperreports.engine.JRExpressionCollector; import net.sf.jasperreports.engine.JRLineBox; import net.sf.jasperreports.engine.JRParameter; import net.sf.jasperreports.engine.JRVariable; import net.sf.jasperreports.engine.JRVisitor; import net.sf.jasperreports.engine.ReportContext; import net.sf.jasperreports.engine.base.JRBaseLineBox; import net.sf.jasperreports.engine.design.JRDesignElement; import net.sf.jasperreports.engine.design.JRDesignVariable; import net.sf.jasperreports.engine.type.CalculationEnum; import net.sf.jasperreports.engine.type.HorizontalPosition; import net.sf.jasperreports.engine.type.ModeEnum; import net.sf.jasperreports.engine.type.RunDirectionEnum; import net.sf.jasperreports.engine.util.ElementsVisitorUtils; import net.sf.jasperreports.engine.util.FormatFactory; import net.sf.jasperreports.engine.util.JRCloneUtils; import net.sf.jasperreports.engine.util.Pair; /** * Design-time {@link net.sf.jasperreports.crosstabs.JRCrosstab crosstab} implementation. * * @author Lucian Chirita (lucianc@users.sourceforge.net) */ public class JRDesignCrosstab extends JRDesignElement implements JRCrosstab { private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID; public static final String EXCEPTION_MESSAGE_KEY_COLUMN_GROUP_DOES_NOT_EXIST = "crosstabs.design.column.group.does.not.exist"; public static final String EXCEPTION_MESSAGE_KEY_DUPLICATE_CELL = "crosstabs.design.duplicate.cell"; public static final String EXCEPTION_MESSAGE_KEY_DUPLICATE_GROUP_OR_MEASURE = "crosstabs.design.duplicate.group.or.measure"; public static final String EXCEPTION_MESSAGE_KEY_DUPLICATE_PARAMETER = "crosstabs.design.duplicate.parameter"; public static final String EXCEPTION_MESSAGE_KEY_ROW_GROUP_DOES_NOT_EXIST = "crosstabs.design.row.group.does.not.exist"; public static final String PROPERTY_COLUMN_BREAK_OFFSET = "columnBreakOffset"; public static final String PROPERTY_DATASET = "dataset"; public static final String PROPERTY_TITLE_CELL = "titleCell"; public static final String PROPERTY_HEADER_CELL = "headerCell"; public static final String PROPERTY_PARAMETERS_MAP_EXPRESSION = "parametersMapExpression"; public static final String PROPERTY_REPEAT_COLUMN_HEADERS = "isRepeatColumnHeaders"; public static final String PROPERTY_REPEAT_ROW_HEADERS = "isRepeatRowHeaders"; public static final String PROPERTY_WHEN_NO_DATA_CELL = "whenNoDataCell"; public static final String PROPERTY_CELLS = "cells"; public static final String PROPERTY_ROW_GROUPS = "rowGroups"; public static final String PROPERTY_COLUMN_GROUPS = "columnGroups"; public static final String PROPERTY_MEASURES = "measures"; public static final String PROPERTY_PARAMETERS = "parameters"; public static final String PROPERTY_IGNORE_WIDTH = "ignoreWidth"; protected List<JRCrosstabParameter> parametersList; protected Map<String, JRCrosstabParameter> parametersMap; // used to be a org.apache.commons.collections.SequencedHashMap, we're now using LinkedMap protected Map<String, JRVariable> variablesList; protected JRExpression parametersMapExpression; protected JRDesignCrosstabDataset dataset; protected List<JRCrosstabRowGroup> rowGroups; protected List<JRCrosstabColumnGroup> columnGroups; protected List<JRCrosstabMeasure> measures; protected Map<String, Integer> rowGroupsMap; protected Map<String, Integer> columnGroupsMap; protected Map<String, Integer> measuresMap; protected int columnBreakOffset = DEFAULT_COLUMN_BREAK_OFFSET; protected boolean repeatColumnHeaders = true; protected boolean repeatRowHeaders = true; protected RunDirectionEnum runDirectionValue; protected HorizontalPosition horizontalPosition; protected List<JRCrosstabCell> cellsList; protected Map<Pair<String, String>, JRCrosstabCell> cellsMap; protected JRDesignCrosstabCell[][] crossCells; protected JRDesignCellContents whenNoDataCell; protected DesignCrosstabColumnCell titleCell; protected JRDesignCellContents headerCell; protected Boolean ignoreWidth; protected JRLineBox lineBox; private class MeasureClassChangeListener implements PropertyChangeListener, Serializable { private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID; @Override public void propertyChange(PropertyChangeEvent evt) { measureClassChanged((JRDesignCrosstabMeasure) evt.getSource(), (String) evt.getNewValue()); } } private PropertyChangeListener measureClassChangeListener = new MeasureClassChangeListener(); private static final Object[] BUILT_IN_PARAMETERS = new Object[] { JRParameter.REPORT_CONTEXT, ReportContext.class, JRParameter.REPORT_PARAMETERS_MAP, java.util.Map.class, JRParameter.REPORT_LOCALE, Locale.class, JRParameter.REPORT_RESOURCE_BUNDLE, ResourceBundle.class, JRParameter.REPORT_TIME_ZONE, TimeZone.class, JRParameter.REPORT_FORMAT_FACTORY, FormatFactory.class, JRParameter.REPORT_CLASS_LOADER, ClassLoader.class }; private static final Object[] BUILT_IN_VARIABLES = new Object[] { JRCrosstab.VARIABLE_ROW_COUNT, Integer.class, JRCrosstab.VARIABLE_COLUMN_COUNT, Integer.class }; /** * Creates a new crosstab. * * @param defaultStyleProvider default style provider */ public JRDesignCrosstab(JRDefaultStyleProvider defaultStyleProvider) { super(defaultStyleProvider); parametersList = new ArrayList<JRCrosstabParameter>(); parametersMap = new HashMap<String, JRCrosstabParameter>(); rowGroupsMap = new HashMap<String, Integer>(); rowGroups = new ArrayList<JRCrosstabRowGroup>(); columnGroupsMap = new HashMap<String, Integer>(); columnGroups = new ArrayList<JRCrosstabColumnGroup>(); measuresMap = new HashMap<String, Integer>(); measures = new ArrayList<JRCrosstabMeasure>(); cellsMap = new HashMap<Pair<String, String>, JRCrosstabCell>(); cellsList = new ArrayList<JRCrosstabCell>(); addBuiltinParameters(); variablesList = new LinkedMap<String, JRVariable>(); addBuiltinVariables(); dataset = new JRDesignCrosstabDataset(); lineBox = new JRBaseLineBox(this); } private void addBuiltinParameters() { for (int i = 0; i < BUILT_IN_PARAMETERS.length; i++) { JRDesignCrosstabParameter parameter = new JRDesignCrosstabParameter(); parameter.setName((String) BUILT_IN_PARAMETERS[i++]); parameter.setValueClass((Class<?>) BUILT_IN_PARAMETERS[i]); parameter.setSystemDefined(true); try { addParameter(parameter); } catch (JRException e) { // never reached } } } private void addBuiltinVariables() { for (int i = 0; i < BUILT_IN_VARIABLES.length; ++i) { JRDesignVariable variable = new JRDesignVariable(); variable.setName((String) BUILT_IN_VARIABLES[i]); variable.setValueClass((Class<?>) BUILT_IN_VARIABLES[++i]); variable.setCalculation(CalculationEnum.SYSTEM); variable.setSystemDefined(true); addVariable(variable); } } /** * Creates a new crosstab. */ public JRDesignCrosstab() { this(null); } /** * The ID of the crosstab is only generated at compile time. */ @Override public int getId() { return 0; } @Override public JRCrosstabDataset getDataset() { return dataset; } /** * Returns the crosstab dataset object to be used for report designing. * * @return the crosstab dataset design object */ public JRDesignCrosstabDataset getDesignDataset() { return dataset; } @Override public JRCrosstabRowGroup[] getRowGroups() { JRCrosstabRowGroup[] groups = new JRCrosstabRowGroup[rowGroups.size()]; rowGroups.toArray(groups); return groups; } @Override public JRCrosstabColumnGroup[] getColumnGroups() { JRCrosstabColumnGroup[] groups = new JRCrosstabColumnGroup[columnGroups.size()]; columnGroups.toArray(groups); return groups; } @Override public JRCrosstabMeasure[] getMeasures() { JRCrosstabMeasure[] measureArray = new JRCrosstabMeasure[measures.size()]; measures.toArray(measureArray); return measureArray; } @Override public void collectExpressions(JRExpressionCollector collector) { collector.collect(this); } @Override public void visit(JRVisitor visitor) { visitor.visitCrosstab(this); if (ElementsVisitorUtils.visitDeepElements(visitor)) { new CrosstabDeepVisitor(visitor).deepVisitCrosstab(this); } } /** * Sets the crosstab input dataset. * * @param dataset the dataset * @see JRCrosstab#getDataset() */ public void setDataset(JRDesignCrosstabDataset dataset) { Object old = this.dataset; this.dataset = dataset; getEventSupport().firePropertyChange(PROPERTY_DATASET, old, this.dataset); } /** * Adds a row group. * <p> * This group will be a sub group of the last row group, if any. * * @param group the group * @throws JRException * @see JRCrosstab#getRowGroups() */ public void addRowGroup(JRDesignCrosstabRowGroup group) throws JRException { String groupName = group.getName(); if (rowGroupsMap.containsKey(groupName) || columnGroupsMap.containsKey(groupName) || measuresMap.containsKey(groupName)) { throw new JRException(EXCEPTION_MESSAGE_KEY_DUPLICATE_GROUP_OR_MEASURE, (Object[]) null); } rowGroupsMap.put(groupName, rowGroups.size()); rowGroups.add(group); addRowGroupVars(group); setParent(group); getEventSupport().fireCollectionElementAddedEvent(PROPERTY_ROW_GROUPS, group, rowGroups.size() - 1); } /** * Adds a row group. * <p> * This group will be a sub group of the last row group, if any. * * @param group the group * @param index position * @throws JRException * @see JRCrosstab#getRowGroups() */ public void addRowGroup(int index, JRDesignCrosstabRowGroup group) throws JRException { String groupName = group.getName(); if (rowGroupsMap.containsKey(groupName) || columnGroupsMap.containsKey(groupName) || measuresMap.containsKey(groupName)) { throw new JRException(EXCEPTION_MESSAGE_KEY_DUPLICATE_GROUP_OR_MEASURE, (Object[]) null); } rowGroups.add(index, group); for (ListIterator<JRCrosstabRowGroup> it = rowGroups.listIterator(index); it.hasNext();) { JRCrosstabRowGroup rowGroup = it.next(); rowGroupsMap.put(rowGroup.getName(), it.previousIndex()); } addRowGroupVars(group); setParent(group); getEventSupport().fireCollectionElementAddedEvent(PROPERTY_ROW_GROUPS, group, index); } protected void addRowGroupVars(JRDesignCrosstabRowGroup rowGroup) { addVariable(rowGroup.getVariable()); for (Iterator<JRCrosstabMeasure> measureIt = measures.iterator(); measureIt.hasNext();) { JRCrosstabMeasure measure = measureIt.next(); addTotalVar(measure, rowGroup, null); for (Iterator<JRCrosstabColumnGroup> colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); addTotalVar(measure, rowGroup, colGroup); } } } /** * Adds a column group. * <p> * This group will be a sub group of the last column group, if any. * * @param group the group * @throws JRException * @see JRCrosstab#getColumnGroups() */ public void addColumnGroup(JRDesignCrosstabColumnGroup group) throws JRException { String groupName = group.getName(); if (rowGroupsMap.containsKey(groupName) || columnGroupsMap.containsKey(groupName) || measuresMap.containsKey(groupName)) { throw new JRException(EXCEPTION_MESSAGE_KEY_DUPLICATE_GROUP_OR_MEASURE, (Object[]) null); } columnGroupsMap.put(groupName, columnGroups.size()); columnGroups.add(group); addColGroupVars(group); setParent(group); getEventSupport().fireCollectionElementAddedEvent(PROPERTY_COLUMN_GROUPS, group, columnGroups.size() - 1); } /** * Adds a column group. * <p> * This group will be a sub group of the last column group, if any. * * @param group the group * @throws JRException * @see JRCrosstab#getColumnGroups() */ public void addColumnGroup(int index, JRDesignCrosstabColumnGroup group) throws JRException { String groupName = group.getName(); if (rowGroupsMap.containsKey(groupName) || columnGroupsMap.containsKey(groupName) || measuresMap.containsKey(groupName)) { throw new JRException(EXCEPTION_MESSAGE_KEY_DUPLICATE_GROUP_OR_MEASURE, (Object[]) null); } columnGroups.add(index, group); for (ListIterator<JRCrosstabColumnGroup> it = columnGroups.listIterator(index); it.hasNext();) { JRCrosstabColumnGroup columnGroup = it.next(); columnGroupsMap.put(columnGroup.getName(), it.previousIndex()); } addColGroupVars(group); setParent(group); getEventSupport().fireCollectionElementAddedEvent(PROPERTY_COLUMN_GROUPS, group, index); } protected void addColGroupVars(JRDesignCrosstabColumnGroup colGroup) { addVariable(colGroup.getVariable()); for (Iterator<JRCrosstabMeasure> measureIt = measures.iterator(); measureIt.hasNext();) { JRCrosstabMeasure measure = measureIt.next(); addTotalVar(measure, null, colGroup); for (Iterator<JRCrosstabRowGroup> rowIt = rowGroups.iterator(); rowIt.hasNext();) { JRCrosstabRowGroup rowGroup = rowIt.next(); addTotalVar(measure, rowGroup, colGroup); } } } /** * Adds a measure to the crosstab. * * @param measure the measure * @throws JRException * @see JRCrosstab#getMeasures() */ public void addMeasure(JRDesignCrosstabMeasure measure) throws JRException { String measureName = measure.getName(); if (rowGroupsMap.containsKey(measureName) || columnGroupsMap.containsKey(measureName) || measuresMap.containsKey(measureName)) { throw new JRException(EXCEPTION_MESSAGE_KEY_DUPLICATE_GROUP_OR_MEASURE, (Object[]) null); } measure.addPropertyChangeListener(JRDesignCrosstabMeasure.PROPERTY_VALUE_CLASS, measureClassChangeListener); measuresMap.put(measureName, measures.size()); measures.add(measure); addMeasureVars(measure); getEventSupport().fireCollectionElementAddedEvent(PROPERTY_MEASURES, measure, measures.size() - 1); } /** * Adds a measure to the crosstab. * * @param measure the measure * @throws JRException * @see JRCrosstab#getMeasures() */ public void addMeasure(int index, JRDesignCrosstabMeasure measure) throws JRException { String measureName = measure.getName(); if (rowGroupsMap.containsKey(measureName) || columnGroupsMap.containsKey(measureName) || measuresMap.containsKey(measureName)) { throw new JRException(EXCEPTION_MESSAGE_KEY_DUPLICATE_GROUP_OR_MEASURE, (Object[]) null); } measure.addPropertyChangeListener(JRDesignCrosstabMeasure.PROPERTY_VALUE_CLASS, measureClassChangeListener); measures.add(index, measure); for (ListIterator<JRCrosstabMeasure> it = measures.listIterator(index); it.hasNext();) { JRCrosstabMeasure itMeasure = it.next(); measuresMap.put(itMeasure.getName(), it.previousIndex()); } addMeasureVars(measure); getEventSupport().fireCollectionElementAddedEvent(PROPERTY_MEASURES, measure, index); } protected void addMeasureVars(JRDesignCrosstabMeasure measure) { addVariable(measure.getVariable()); for (Iterator<JRCrosstabColumnGroup> colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); addTotalVar(measure, null, colGroup); } for (Iterator<JRCrosstabRowGroup> rowIt = rowGroups.iterator(); rowIt.hasNext();) { JRCrosstabRowGroup rowGroup = rowIt.next(); addTotalVar(measure, rowGroup, null); for (Iterator<JRCrosstabColumnGroup> colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); addTotalVar(measure, rowGroup, colGroup); } } } protected void addTotalVar(JRCrosstabMeasure measure, JRCrosstabRowGroup rowGroup, JRCrosstabColumnGroup colGroup) { JRDesignVariable var = new JRDesignVariable(); var.setCalculation(CalculationEnum.SYSTEM); var.setSystemDefined(true); var.setName(getTotalVariableName(measure, rowGroup, colGroup)); var.setValueClassName(measure.getValueClassName()); addVariable(var); } protected void removeTotalVar(JRCrosstabMeasure measure, JRCrosstabRowGroup rowGroup, JRCrosstabColumnGroup colGroup) { String varName = getTotalVariableName(measure, rowGroup, colGroup); removeVariable(varName); } public static String getTotalVariableName(JRCrosstabMeasure measure, JRCrosstabRowGroup rowGroup, JRCrosstabColumnGroup colGroup) { StringBuilder name = new StringBuilder(); name.append(measure.getName()); if (rowGroup != null) { name.append('_'); name.append(rowGroup.getName()); } if (colGroup != null) { name.append('_'); name.append(colGroup.getName()); } name.append("_ALL"); return name.toString(); } /** * Removes a row group. * * @param groupName the group name * @return the removed group */ public JRCrosstabRowGroup removeRowGroup(String groupName) { JRCrosstabRowGroup removed = null; Integer idx = rowGroupsMap.remove(groupName); if (idx != null) { removed = rowGroups.remove((int) idx); for (ListIterator<JRCrosstabRowGroup> it = rowGroups.listIterator(idx); it.hasNext();) { JRCrosstabRowGroup group = it.next(); rowGroupsMap.put(group.getName(), it.previousIndex()); } for (Iterator<JRCrosstabCell> it = cellsList.iterator(); it.hasNext();) { JRCrosstabCell cell = it.next(); String rowTotalGroup = cell.getRowTotalGroup(); if (rowTotalGroup != null && rowTotalGroup.equals(groupName)) { it.remove(); cellsMap.remove(new Pair<String, String>(rowTotalGroup, cell.getColumnTotalGroup())); getEventSupport().fireCollectionElementRemovedEvent(PROPERTY_CELLS, cell, -1); } } removeRowGroupVars(removed); getEventSupport().fireCollectionElementRemovedEvent(PROPERTY_ROW_GROUPS, removed, idx); } return removed; } protected void removeRowGroupVars(JRCrosstabRowGroup rowGroup) { removeVariable(rowGroup.getVariable()); for (Iterator<JRCrosstabMeasure> measureIt = measures.iterator(); measureIt.hasNext();) { JRCrosstabMeasure measure = measureIt.next(); removeTotalVar(measure, rowGroup, null); for (Iterator<JRCrosstabColumnGroup> colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); removeTotalVar(measure, rowGroup, colGroup); } } } /** * Removes a row group. * * @param group the group to be removed * @return the removed group */ public JRCrosstabRowGroup removeRowGroup(JRCrosstabRowGroup group) { return removeRowGroup(group.getName()); } /** * Removes a column group. * * @param groupName the group name * @return the removed group */ public JRCrosstabColumnGroup removeColumnGroup(String groupName) { JRCrosstabColumnGroup removed = null; Integer idx = columnGroupsMap.remove(groupName); if (idx != null) { removed = columnGroups.remove((int) idx); for (ListIterator<JRCrosstabColumnGroup> it = columnGroups.listIterator(idx); it.hasNext();) { JRCrosstabColumnGroup group = it.next(); columnGroupsMap.put(group.getName(), it.previousIndex()); } for (Iterator<JRCrosstabCell> it = cellsList.iterator(); it.hasNext();) { JRCrosstabCell cell = it.next(); String columnTotalGroup = cell.getColumnTotalGroup(); if (columnTotalGroup != null && columnTotalGroup.equals(groupName)) { it.remove(); cellsMap.remove(new Pair<String, String>(cell.getRowTotalGroup(), columnTotalGroup)); getEventSupport().fireCollectionElementRemovedEvent(PROPERTY_CELLS, cell, -1); } } removeColGroupVars(removed); getEventSupport().fireCollectionElementRemovedEvent(PROPERTY_COLUMN_GROUPS, removed, idx); } return removed; } protected void removeColGroupVars(JRCrosstabColumnGroup colGroup) { removeVariable(colGroup.getVariable()); for (Iterator<JRCrosstabMeasure> measureIt = measures.iterator(); measureIt.hasNext();) { JRCrosstabMeasure measure = measureIt.next(); removeTotalVar(measure, null, colGroup); for (Iterator<JRCrosstabRowGroup> rowIt = rowGroups.iterator(); rowIt.hasNext();) { JRCrosstabRowGroup rowGroup = rowIt.next(); removeTotalVar(measure, rowGroup, colGroup); } } } /** * Removes a column group. * * @param group the group * @return the removed group */ public JRCrosstabColumnGroup removeColumnGroup(JRCrosstabColumnGroup group) { return removeColumnGroup(group.getName()); } /** * Removes a measure. * * @param measureName the measure name * @return the removed measure */ public JRCrosstabMeasure removeMeasure(String measureName) { JRDesignCrosstabMeasure removed = null; Integer idx = measuresMap.remove(measureName); if (idx != null) { removed = (JRDesignCrosstabMeasure) measures.remove((int) idx); for (ListIterator<JRCrosstabMeasure> it = measures.listIterator(idx); it.hasNext();) { JRCrosstabMeasure group = it.next(); measuresMap.put(group.getName(), it.previousIndex()); } removeMeasureVars(removed); removed.removePropertyChangeListener(JRDesignCrosstabMeasure.PROPERTY_VALUE_CLASS, measureClassChangeListener); getEventSupport().fireCollectionElementRemovedEvent(PROPERTY_MEASURES, removed, idx); } return removed; } protected void removeMeasureVars(JRDesignCrosstabMeasure measure) { removeVariable(measure.getVariable()); for (Iterator<JRCrosstabColumnGroup> colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); removeTotalVar(measure, null, colGroup); } for (Iterator<JRCrosstabRowGroup> rowIt = rowGroups.iterator(); rowIt.hasNext();) { JRCrosstabRowGroup rowGroup = rowIt.next(); removeTotalVar(measure, rowGroup, null); for (Iterator<JRCrosstabColumnGroup> colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); removeTotalVar(measure, rowGroup, colGroup); } } } /** * Removes a measure. * * @param measure the measure * @return the removed measure */ public JRCrosstabMeasure removeMeasure(JRCrosstabMeasure measure) { return removeMeasure(measure.getName()); } @Override public boolean isRepeatColumnHeaders() { return repeatColumnHeaders; } /** * Sets the repeat column headers flag. * * @param repeatColumnHeaders whether to repeat the column headers on row breaks * @see JRCrosstab#isRepeatColumnHeaders() */ public void setRepeatColumnHeaders(boolean repeatColumnHeaders) { boolean old = this.repeatColumnHeaders; this.repeatColumnHeaders = repeatColumnHeaders; getEventSupport().firePropertyChange(PROPERTY_REPEAT_COLUMN_HEADERS, old, this.repeatColumnHeaders); } @Override public boolean isRepeatRowHeaders() { return repeatRowHeaders; } /** * Sets the repeat row headers flag. * * @param repeatRowHeaders whether to repeat the row headers on column breaks * @see JRCrosstab#isRepeatRowHeaders() */ public void setRepeatRowHeaders(boolean repeatRowHeaders) { boolean old = this.repeatRowHeaders; this.repeatRowHeaders = repeatRowHeaders; getEventSupport().firePropertyChange(PROPERTY_REPEAT_ROW_HEADERS, old, this.repeatRowHeaders); } @Override public JRCrosstabCell[][] getCells() { return crossCells; } /** * Returns the data cells list. * * @return the data cells list * @see #addCell(JRDesignCrosstabCell) */ public List<JRCrosstabCell> getCellsList() { return cellsList; } /** * Returns the crosstab cells indexed by corresponding row total group/ * column total group {@link Pair pairs}. * * @return the crosstab cells indexed by row/column total groups * @see JRCrosstabCell#getRowTotalGroup() * @see JRCrosstabCell#getColumnTotalGroup() */ public Map<Pair<String, String>, JRCrosstabCell> getCellsMap() { return cellsMap; } /** * Adds a data cell to the crosstab. * * @param cell the cell * @throws JRException * @see JRCrosstab#getCells() */ public void addCell(JRDesignCrosstabCell cell) throws JRException { String rowTotalGroup = cell.getRowTotalGroup(); if (rowTotalGroup != null && !rowGroupsMap.containsKey(rowTotalGroup)) { throw new JRException(EXCEPTION_MESSAGE_KEY_ROW_GROUP_DOES_NOT_EXIST, new Object[] { rowTotalGroup }); } String columnTotalGroup = cell.getColumnTotalGroup(); if (columnTotalGroup != null && !columnGroupsMap.containsKey(columnTotalGroup)) { throw new JRException(EXCEPTION_MESSAGE_KEY_ROW_GROUP_DOES_NOT_EXIST, new Object[] { columnTotalGroup }); } Pair<String, String> cellKey = new Pair<String, String>(rowTotalGroup, columnTotalGroup); if (cellsMap.containsKey(cellKey)) { throw new JRException(EXCEPTION_MESSAGE_KEY_DUPLICATE_CELL, (Object[]) null); } cellsMap.put(cellKey, cell); cellsList.add(cell); setCellOrigin(cell.getContents(), new JRCrosstabOrigin(this, JRCrosstabOrigin.TYPE_DATA_CELL, rowTotalGroup, columnTotalGroup)); getEventSupport().fireCollectionElementAddedEvent(PROPERTY_CELLS, cell, cellsList.size() - 1); } /** * Removes a data cell. * * @param rowTotalGroup the cell's total row group * @param columnTotalGroup the cell's total column group * @return the removed cell */ public JRCrosstabCell removeCell(String rowTotalGroup, String columnTotalGroup) { Object cellKey = new Pair<String, String>(rowTotalGroup, columnTotalGroup); JRCrosstabCell cell = cellsMap.remove(cellKey); if (cell != null) { cellsList.remove(cell); getEventSupport().fireCollectionElementRemovedEvent(PROPERTY_CELLS, cell, -1); } return cell; } /** * Removes a data cell. * * @param cell the cell to be removed * @return the removed cell */ public JRCrosstabCell removeCell(JRCrosstabCell cell) { return removeCell(cell.getRowTotalGroup(), cell.getColumnTotalGroup()); } @Override public JRCrosstabParameter[] getParameters() { JRCrosstabParameter[] parameters = new JRCrosstabParameter[parametersList.size()]; parametersList.toArray(parameters); return parameters; } /** * Returns the paremeters list. * * @return the paremeters list */ public List<JRCrosstabParameter> getParametersList() { return parametersList; } /** * Returns the parameters indexed by names. * * @return the parameters indexed by names */ public Map<String, JRCrosstabParameter> getParametersMap() { return parametersMap; } @Override public JRExpression getParametersMapExpression() { return parametersMapExpression; } /** * Adds a parameter to the crosstab. * * @param parameter the parameter * @throws JRException * @see JRCrosstab#getMeasures() */ public void addParameter(JRCrosstabParameter parameter) throws JRException { if (parametersMap.containsKey(parameter.getName())) { if (parametersMap.containsKey(parameter.getName())) { throw new JRException(EXCEPTION_MESSAGE_KEY_DUPLICATE_PARAMETER, new Object[] { parameter.getName() }); } } parametersMap.put(parameter.getName(), parameter); parametersList.add(parameter); getEventSupport().fireCollectionElementAddedEvent(PROPERTY_PARAMETERS, parameter, parametersList.size() - 1); } /** * Adds a parameter to the crosstab. * * @param parameter the parameter * @throws JRException * @see JRCrosstab#getMeasures() */ public void addParameter(int index, JRCrosstabParameter parameter) throws JRException { if (parametersMap.containsKey(parameter.getName())) { if (parametersMap.containsKey(parameter.getName())) { throw new JRException(EXCEPTION_MESSAGE_KEY_DUPLICATE_PARAMETER, new Object[] { parameter.getName() }); } } parametersMap.put(parameter.getName(), parameter); parametersList.add(index, parameter); getEventSupport().fireCollectionElementAddedEvent(PROPERTY_PARAMETERS, parameter, index); } /** * Removes a parameter. * * @param parameterName the name of the parameter to be removed * @return the removed parameter */ public JRCrosstabParameter removeParameter(String parameterName) { JRCrosstabParameter param = parametersMap.remove(parameterName); if (param != null) { int idx = parametersList.indexOf(param); if (idx >= 0) { parametersList.remove(idx); } getEventSupport().fireCollectionElementRemovedEvent(PROPERTY_PARAMETERS, param, idx); } return param; } /** * Removes a parameter. * * @param parameter the parameter to be removed * @return the removed parameter */ public JRCrosstabParameter removeParameter(JRCrosstabParameter parameter) { return removeParameter(parameter.getName()); } /** * Sets the parameters map expression. * * @param expression the parameters map expression * @see JRCrosstab#getParametersMapExpression() */ public void setParametersMapExpression(JRExpression expression) { Object old = this.parametersMapExpression; this.parametersMapExpression = expression; getEventSupport().firePropertyChange(PROPERTY_PARAMETERS_MAP_EXPRESSION, old, this.parametersMapExpression); } /** * Returns the variables of this crosstab indexed by name. * * @return the variables of this crosstab indexed by name */ public Map<String, JRVariable> getVariablesMap() { JRVariable[] variables = getVariables(); Map<String, JRVariable> variablesMap = new HashMap<String, JRVariable>(); for (int i = 0; i < variables.length; i++) { variablesMap.put(variables[i].getName(), variables[i]); } return variablesMap; } /** * Returns the list of variables created for this crosstab. * * @return the list of variables created for this crosstab * @see JRCrosstabGroup#getVariable() * @see JRCrosstabMeasure#getVariable() * @see JRCrosstab#VARIABLE_ROW_COUNT * @see JRCrosstab#VARIABLE_COLUMN_COUNT */ @Override public JRVariable[] getVariables() { JRVariable[] variables = new JRVariable[variablesList.size()]; variablesList.values().toArray(variables); return variables; } @Override public int getColumnBreakOffset() { return columnBreakOffset; } /** * Sets the column break offset. * * @param columnBreakOffset the offset * @see JRCrosstab#getColumnBreakOffset() */ public void setColumnBreakOffset(int columnBreakOffset) { int old = this.columnBreakOffset; this.columnBreakOffset = columnBreakOffset; getEventSupport().firePropertyChange(PROPERTY_COLUMN_BREAK_OFFSET, old, this.columnBreakOffset); } /** * Performs all the calculations required for report compilation. */ public void preprocess() { setGroupVariablesClass(rowGroups); setGroupVariablesClass(columnGroups); calculateSizes(); } protected <T> void setGroupVariablesClass(List<T> groups) { for (Iterator<T> it = groups.iterator(); it.hasNext();) { JRDesignCrosstabGroup group = (JRDesignCrosstabGroup) it.next(); JRCrosstabBucket bucket = group.getBucket(); if (bucket != null) { JRExpression expression = bucket.getExpression(); if (expression != null) { group.designVariable.setValueClassName(bucket.getValueClassName()); } } } } protected void calculateSizes() { setWhenNoDataCellSize(); createCellMatrix(); int rowHeadersWidth = calculateRowHeadersSizes(); int colHeadersHeight = calculateColumnHeadersSizes(rowHeadersWidth); if (headerCell != null) { headerCell.setWidth(rowHeadersWidth); headerCell.setHeight(colHeadersHeight); } setTitleSize(rowHeadersWidth); } protected void setWhenNoDataCellSize() { if (whenNoDataCell != null) { whenNoDataCell.setWidth(getWidth()); whenNoDataCell.setHeight(getHeight()); } } protected void createCellMatrix() { crossCells = new JRDesignCrosstabCell[rowGroups.size() + 1][columnGroups.size() + 1]; for (Iterator<JRCrosstabCell> it = cellsList.iterator(); it.hasNext();) { JRDesignCrosstabCell crosstabCell = (JRDesignCrosstabCell) it.next(); JRDesignCellContents contents = (JRDesignCellContents) crosstabCell.getContents(); String rowTotalGroup = crosstabCell.getRowTotalGroup(); int rowGroupIndex = rowTotalGroup == null ? rowGroups.size() : rowGroupsMap.get(rowTotalGroup); Integer cellWidth = crosstabCell.getWidth(); if (cellWidth != null) { contents.setWidth(cellWidth); } String columnTotalGroup = crosstabCell.getColumnTotalGroup(); int columnGroupIndex = columnTotalGroup == null ? columnGroups.size() : columnGroupsMap.get(columnTotalGroup); Integer cellHeight = crosstabCell.getHeight(); if (cellHeight != null) { contents.setHeight(cellHeight); } crossCells[rowGroupIndex][columnGroupIndex] = crosstabCell; } inheritCells(); } protected JRDesignCrosstabRowGroup getRowGroup(int rowGroupIndex) { return (JRDesignCrosstabRowGroup) rowGroups.get(rowGroupIndex); } protected JRDesignCrosstabColumnGroup getColumnGroup(int columnGroupIndex) { return (JRDesignCrosstabColumnGroup) columnGroups.get(columnGroupIndex); } protected void inheritCells() { for (int i = rowGroups.size(); i >= 0; --i) { for (int j = columnGroups.size(); j >= 0; --j) { boolean used = (i == rowGroups.size() || getRowGroup(i).hasTotal()) && (j == columnGroups.size() || getColumnGroup(j).hasTotal()); if (used) { if (crossCells[i][j] == null) { inheritCell(i, j); if (crossCells[i][j] == null) { crossCells[i][j] = emptyCell(i, j); inheritCellSize(i, j); } } else { inheritCellSize(i, j); } } else { crossCells[i][j] = null; } } } } private JRDesignCrosstabCell emptyCell(int i, int j) { JRDesignCrosstabCell emptyCell = new JRDesignCrosstabCell(); if (i < rowGroups.size()) { emptyCell.setRowTotalGroup((rowGroups.get(i)).getName()); } if (j < columnGroups.size()) { emptyCell.setColumnTotalGroup((columnGroups.get(j)).getName()); } return emptyCell; } protected void inheritCellSize(int i, int j) { JRDesignCrosstabCell cell = crossCells[i][j]; JRDesignCellContents contents = (JRDesignCellContents) cell.getContents(); if (contents.getWidth() == JRCellContents.NOT_CALCULATED) { if (i < rowGroups.size()) { JRDesignCrosstabCell rowCell = crossCells[rowGroups.size()][j]; if (rowCell != null) { contents.setWidth(rowCell.getContents().getWidth()); } } else { for (int k = j + 1; k <= columnGroups.size(); ++k) { if (crossCells[i][k] != null) { contents.setWidth(crossCells[i][k].getContents().getWidth()); break; } } } } if (contents.getHeight() == JRCellContents.NOT_CALCULATED) { if (j < columnGroups.size()) { JRDesignCrosstabCell colCell = crossCells[i][columnGroups.size()]; if (colCell != null) { contents.setHeight(colCell.getContents().getHeight()); } } else { for (int k = i + 1; k <= rowGroups.size(); ++k) { if (crossCells[k][j] != null) { contents.setHeight(crossCells[k][j].getContents().getHeight()); } } } } } protected void inheritCell(int i, int j) { JRDesignCrosstabCell inheritedCell = null; if (j < columnGroups.size()) { JRDesignCrosstabCell colCell = crossCells[rowGroups.size()][j]; JRDesignCellContents colContents = colCell == null ? null : (JRDesignCellContents) colCell.getContents(); for (int k = j + 1; inheritedCell == null && k <= columnGroups.size(); ++k) { JRDesignCrosstabCell cell = crossCells[i][k]; if (cell != null) { JRDesignCellContents contents = (JRDesignCellContents) cell.getContents(); if (colContents == null || contents.getWidth() == colContents.getWidth()) { inheritedCell = cell; } } } } if (inheritedCell == null && i < rowGroups.size()) { JRDesignCrosstabCell rowCell = crossCells[i][columnGroups.size()]; JRDesignCellContents rowContents = rowCell == null ? null : (JRDesignCellContents) rowCell.getContents(); for (int k = i + 1; inheritedCell == null && k <= rowGroups.size(); ++k) { JRDesignCrosstabCell cell = crossCells[k][j]; if (cell != null) { JRDesignCellContents contents = (JRDesignCellContents) cell.getContents(); if (rowContents == null || contents.getHeight() == rowContents.getHeight()) { inheritedCell = cell; } } } } crossCells[i][j] = inheritedCell; } protected int calculateRowHeadersSizes() { int widthSum = 0; for (int i = rowGroups.size() - 1, heightSum = 0; i >= 0; --i) { JRDesignCrosstabRowGroup group = (JRDesignCrosstabRowGroup) rowGroups.get(i); widthSum += group.getWidth(); JRDesignCrosstabCell cell = crossCells[i + 1][columnGroups.size()]; if (cell != null) { heightSum += cell.getContents().getHeight(); } JRDesignCellContents header = (JRDesignCellContents) group.getHeader(); header.setHeight(heightSum); header.setWidth(group.getWidth()); if (group.hasTotal()) { JRDesignCellContents totalHeader = (JRDesignCellContents) group.getTotalHeader(); totalHeader.setWidth(widthSum); JRDesignCrosstabCell totalCell = crossCells[i][columnGroups.size()]; if (totalCell != null) { totalHeader.setHeight(totalCell.getContents().getHeight()); } } } return widthSum; } protected int calculateColumnHeadersSizes(int rowHeadersWidth) { int heightSum = 0; for (int i = columnGroups.size() - 1, widthSum = 0; i >= 0; --i) { JRDesignCrosstabColumnGroup group = (JRDesignCrosstabColumnGroup) columnGroups.get(i); heightSum += group.getHeight(); JRDesignCrosstabCell cell = crossCells[rowGroups.size()][i + 1]; if (cell != null) { widthSum += cell.getContents().getWidth(); } JRDesignCellContents crosstabHeader = (JRDesignCellContents) group.getCrosstabHeader(); if (crosstabHeader != null) { crosstabHeader.setWidth(rowHeadersWidth); crosstabHeader.setHeight(group.getHeight()); } JRDesignCellContents header = (JRDesignCellContents) group.getHeader(); header.setHeight(group.getHeight()); header.setWidth(widthSum); if (group.hasTotal()) { JRDesignCellContents totalHeader = (JRDesignCellContents) group.getTotalHeader(); totalHeader.setHeight(heightSum); JRDesignCrosstabCell totalCell = crossCells[rowGroups.size()][i]; if (totalCell != null) { totalHeader.setWidth(totalCell.getContents().getWidth()); } } } return heightSum; } protected void setTitleSize(int rowHeadersWidth) { if (titleCell != null && titleCell.getDesignCellContents() != null) { JRDesignCellContents titleContents = titleCell.getDesignCellContents(); titleContents.setHeight(titleCell.getHeight()); int titleWidth = rowHeadersWidth; if (!columnGroups.isEmpty()) { JRCrosstabColumnGroup firstGroup = columnGroups.get(0); titleWidth += firstGroup.getHeader().getWidth(); if (firstGroup.hasTotal()) { titleWidth += firstGroup.getTotalHeader().getWidth(); } } titleContents.setWidth(titleWidth); } } @Override public JRCellContents getWhenNoDataCell() { return whenNoDataCell; } /** * Sets the "No data" cell. * * @param whenNoDataCell the cell * @see JRCrosstab#getWhenNoDataCell() */ public void setWhenNoDataCell(JRDesignCellContents whenNoDataCell) { Object old = this.whenNoDataCell; this.whenNoDataCell = whenNoDataCell; setCellOrigin(this.whenNoDataCell, new JRCrosstabOrigin(this, JRCrosstabOrigin.TYPE_WHEN_NO_DATA_CELL)); getEventSupport().firePropertyChange(PROPERTY_WHEN_NO_DATA_CELL, old, this.whenNoDataCell); } @Override public JRElement getElementByKey(String elementKey) { return JRBaseCrosstab.getElementByKey(this, elementKey); } @Override public ModeEnum getModeValue() { return getStyleResolver().getMode(this, ModeEnum.TRANSPARENT); } @Override public CrosstabColumnCell getTitleCell() { return titleCell; } public void setTitleCell(DesignCrosstabColumnCell titleCell) { Object old = this.titleCell; this.titleCell = titleCell; if (this.titleCell != null) { setCellOrigin(this.titleCell.getCellContents(), new JRCrosstabOrigin(this, JRCrosstabOrigin.TYPE_TITLE_CELL)); } getEventSupport().firePropertyChange(PROPERTY_TITLE_CELL, old, this.titleCell); } @Override public JRCellContents getHeaderCell() { return headerCell; } /** * Sets the crosstab header cell (this cell will be rendered at the upper-left corder of the crosstab). * * @param headerCell the cell * @see JRCrosstab#getHeaderCell() */ public void setHeaderCell(JRDesignCellContents headerCell) { Object old = this.headerCell; this.headerCell = headerCell; setCellOrigin(this.headerCell, new JRCrosstabOrigin(this, JRCrosstabOrigin.TYPE_HEADER_CELL)); getEventSupport().firePropertyChange(PROPERTY_HEADER_CELL, old, this.headerCell); } protected void measureClassChanged(JRDesignCrosstabMeasure measure, String valueClassName) { for (Iterator<JRCrosstabColumnGroup> colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); setTotalVarClass(measure, null, colGroup, valueClassName); } for (Iterator<JRCrosstabRowGroup> rowIt = rowGroups.iterator(); rowIt.hasNext();) { JRCrosstabRowGroup rowGroup = rowIt.next(); setTotalVarClass(measure, rowGroup, null, valueClassName); for (Iterator<JRCrosstabColumnGroup> colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); setTotalVarClass(measure, rowGroup, colGroup, valueClassName); } } } protected void setTotalVarClass(JRCrosstabMeasure measure, JRCrosstabRowGroup rowGroup, JRCrosstabColumnGroup colGroup, String valueClassName) { JRDesignVariable variable = getVariable(getTotalVariableName(measure, rowGroup, colGroup)); variable.setValueClassName(valueClassName); } private void addVariable(JRVariable variable) { variablesList.put(variable.getName(), variable); } private void removeVariable(JRVariable variable) { removeVariable(variable.getName()); } private void removeVariable(String varName) { variablesList.remove(varName); } private JRDesignVariable getVariable(String varName) { return (JRDesignVariable) variablesList.get(varName); } @Override public RunDirectionEnum getRunDirectionValue() { return this.runDirectionValue; } @Override public void setRunDirection(RunDirectionEnum runDirectionValue) { RunDirectionEnum old = this.runDirectionValue; this.runDirectionValue = runDirectionValue; getEventSupport().firePropertyChange(JRBaseCrosstab.PROPERTY_RUN_DIRECTION, old, this.runDirectionValue); } @Override public HorizontalPosition getHorizontalPosition() { return horizontalPosition; } @Override public void setHorizontalPosition(HorizontalPosition horizontalPosition) { HorizontalPosition old = this.horizontalPosition; this.horizontalPosition = horizontalPosition; getEventSupport().firePropertyChange(JRBaseCrosstab.PROPERTY_HORIZONTAL_POSITION, old, this.horizontalPosition); } protected void setCellOrigin(JRCellContents cell, JRCrosstabOrigin origin) { if (cell instanceof JRDesignCellContents) { setCellOrigin((JRDesignCellContents) cell, origin); } } protected void setCellOrigin(JRDesignCellContents cell, JRCrosstabOrigin origin) { if (cell != null) { cell.setOrigin(origin); } } protected void setParent(JRDesignCrosstabGroup group) { if (group != null) { group.setParent(this); } } @Override public Object clone() { JRDesignCrosstab clone = (JRDesignCrosstab) super.clone(); if (parametersList != null) { clone.parametersList = new ArrayList<JRCrosstabParameter>(parametersList.size()); clone.parametersMap = new HashMap<String, JRCrosstabParameter>(parametersList.size()); for (int i = 0; i < parametersList.size(); i++) { JRCrosstabParameter parameter = JRCloneUtils.nullSafeClone(parametersList.get(i)); clone.parametersList.add(parameter); clone.parametersMap.put(parameter.getName(), parameter); } } clone.parametersMapExpression = JRCloneUtils.nullSafeClone(parametersMapExpression); clone.dataset = JRCloneUtils.nullSafeClone(dataset); clone.lineBox = lineBox.clone(clone); // keep group and measure cloned variables to reuse the clone instances // in the variables list Map<JRVariable, JRVariable> clonedVariables = new HashMap<JRVariable, JRVariable>(); if (rowGroups != null) { clone.rowGroups = new ArrayList<JRCrosstabRowGroup>(rowGroups.size()); clone.rowGroupsMap = new HashMap<String, Integer>(rowGroups.size()); for (int i = 0; i < rowGroups.size(); i++) { JRDesignCrosstabRowGroup group = (JRDesignCrosstabRowGroup) rowGroups.get(i); JRDesignCrosstabRowGroup groupClone = (JRDesignCrosstabRowGroup) group.clone(clone); clone.rowGroups.add(groupClone); clone.rowGroupsMap.put(groupClone.getName(), i); adjustCrosstabReference(clone, (JRDesignCellContents) groupClone.getTotalHeader()); adjustCrosstabReference(clone, (JRDesignCellContents) groupClone.getHeader()); if (group.designVariable != null) { clonedVariables.put(group.designVariable, groupClone.designVariable); } } } if (columnGroups != null) { clone.columnGroups = new ArrayList<JRCrosstabColumnGroup>(columnGroups.size()); clone.columnGroupsMap = new HashMap<String, Integer>(columnGroups.size()); for (int i = 0; i < columnGroups.size(); i++) { JRDesignCrosstabColumnGroup group = (JRDesignCrosstabColumnGroup) columnGroups.get(i); JRDesignCrosstabColumnGroup groupClone = (JRDesignCrosstabColumnGroup) group.clone(clone); clone.columnGroups.add(groupClone); clone.columnGroupsMap.put(groupClone.getName(), i); adjustCrosstabReference(clone, (JRDesignCellContents) groupClone.getCrosstabHeader()); adjustCrosstabReference(clone, (JRDesignCellContents) groupClone.getTotalHeader()); adjustCrosstabReference(clone, (JRDesignCellContents) groupClone.getHeader()); if (group.designVariable != null) { clonedVariables.put(group.designVariable, groupClone.designVariable); } } } if (measures != null) { clone.measures = new ArrayList<JRCrosstabMeasure>(measures.size()); clone.measuresMap = new HashMap<String, Integer>(measures.size()); for (int i = 0; i < measures.size(); i++) { JRDesignCrosstabMeasure measure = (JRDesignCrosstabMeasure) measures.get(i); JRDesignCrosstabMeasure clonedMeasure = JRCloneUtils.nullSafeClone(measure); clone.measures.add(clonedMeasure); clone.measuresMap.put(clonedMeasure.getName(), i); if (clonedMeasure.designVariable != null) { clonedVariables.put(measure.designVariable, clonedMeasure.designVariable); } } } if (variablesList != null) { clone.variablesList = new LinkedMap<String, JRVariable>(variablesList.size()); for (Iterator<?> it = variablesList.values().iterator(); it.hasNext();) { JRVariable variable = (JRVariable) it.next(); // check whether the variable was already cloned as part of a group or measure JRVariable variableClone = clonedVariables.get(variable); if (variableClone == null) { variableClone = JRCloneUtils.nullSafeClone(variable); } clone.variablesList.put(variableClone.getName(), variableClone); } } if (cellsList != null) { clone.cellsList = new ArrayList<JRCrosstabCell>(cellsList.size()); clone.cellsMap = new HashMap<Pair<String, String>, JRCrosstabCell>(cellsList.size()); for (int i = 0; i < cellsList.size(); i++) { JRCrosstabCell cell = JRCloneUtils.nullSafeClone(cellsList.get(i)); adjustCrosstabReference(clone, (JRDesignCellContents) cell.getContents()); clone.cellsList.add(cell); clone.cellsMap.put(new Pair<String, String>(cell.getRowTotalGroup(), cell.getColumnTotalGroup()), cell); } } // clone not preprocessed clone.crossCells = null; clone.whenNoDataCell = JRCloneUtils.nullSafeClone(whenNoDataCell); adjustCrosstabReference(clone, clone.whenNoDataCell); clone.titleCell = JRCloneUtils.nullSafeClone(titleCell); if (clone.titleCell != null) { adjustCrosstabReference(clone, clone.titleCell.getDesignCellContents()); } clone.headerCell = JRCloneUtils.nullSafeClone(headerCell); adjustCrosstabReference(clone, clone.headerCell); return clone; } /** * Adjust the crosstab reference inside the origin to point to this * crosstab. Used in the clone method. * @param contents */ private void adjustCrosstabReference(JRDesignCrosstab clone, JRDesignCellContents contents) { if (contents == null) { return; } contents.setOrigin(new JRCrosstabOrigin(clone, contents.getOrigin().getType(), contents.getOrigin().getRowGroupName(), contents.getOrigin().getColumnGroupName())); } public List<JRCrosstabRowGroup> getRowGroupsList() { return rowGroups; } public Map<String, Integer> getRowGroupIndicesMap() { return rowGroupsMap; } public List<JRCrosstabColumnGroup> getColumnGroupsList() { return columnGroups; } public Map<String, Integer> getColumnGroupIndicesMap() { return columnGroupsMap; } public List<JRCrosstabMeasure> getMesuresList() { return measures; } public Map<String, Integer> getMeasureIndicesMap() { return measuresMap; } @Override public Boolean getIgnoreWidth() { return ignoreWidth; } @Override public void setIgnoreWidth(Boolean ignoreWidth) { Object old = this.ignoreWidth; this.ignoreWidth = ignoreWidth; getEventSupport().firePropertyChange(PROPERTY_IGNORE_WIDTH, old, this.ignoreWidth); } /** * @deprecated Replaced by {@link #setIgnoreWidth(Boolean)}. */ @Override public void setIgnoreWidth(boolean ignoreWidth) { setIgnoreWidth((Boolean) ignoreWidth); } @Override public Color getDefaultLineColor() { return getForecolor(); } @Override public JRLineBox getLineBox() { return lineBox; } /* * These fields are only for serialization backward compatibility. */ private int PSEUDO_SERIAL_VERSION_UID = JRConstants.PSEUDO_SERIAL_VERSION_UID; //NOPMD /** * @deprecated */ private byte runDirection; @SuppressWarnings("deprecation") private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); if (PSEUDO_SERIAL_VERSION_UID < JRConstants.PSEUDO_SERIAL_VERSION_UID_3_7_2) { runDirectionValue = RunDirectionEnum.getByValue(runDirection); } if (lineBox == null) { lineBox = new JRBaseLineBox(this); } // this will work as long as SequencedHashMap is part of commons collections // we could also look at PSEUDO_SERIAL_VERSION_UID if (variablesList.getClass().getName().equals("org.apache.commons.collections.SequencedHashMap")) { // converting to the new type variablesList = new LinkedMap<String, JRVariable>(variablesList); } } }