All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jasperreports.crosstabs.design.JRDesignCrosstab Maven / Gradle / Ivy

/*
 * JasperReports - Free Java Reporting Library.
 * Copyright (C) 2001 - 2022 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 .
 */
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 ([email protected])
 */
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 parametersList;
	protected Map parametersMap;
	// used to be a org.apache.commons.collections.SequencedHashMap, we're now using LinkedMap
	protected Map variablesList;
	protected JRExpression parametersMapExpression;
	protected JRDesignCrosstabDataset dataset;
	protected List rowGroups;
	protected List columnGroups;
	protected List measures;
	protected Map rowGroupsMap;
	protected Map columnGroupsMap;
	protected Map measuresMap;
	protected int columnBreakOffset = DEFAULT_COLUMN_BREAK_OFFSET;
	protected boolean repeatColumnHeaders = true;
	protected boolean repeatRowHeaders = true;
	protected RunDirectionEnum runDirectionValue;
	protected HorizontalPosition horizontalPosition;
	protected List cellsList;
	protected Map,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<>();
		parametersMap = new HashMap<>();
		rowGroupsMap = new HashMap<>();
		rowGroups = new ArrayList<>();
		columnGroupsMap = new HashMap<>();
		columnGroups = new ArrayList<>();
		measuresMap = new HashMap<>();
		measures = new ArrayList<>();
		
		cellsMap = new HashMap<>();
		cellsList = new ArrayList<>();
		
		addBuiltinParameters();
		
		variablesList = new LinkedMap<>();
		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.
	 * 

* 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. *

* 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 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 measureIt = measures.iterator(); measureIt.hasNext();) { JRCrosstabMeasure measure = measureIt.next(); addTotalVar(measure, rowGroup, null); for (Iterator colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); addTotalVar(measure, rowGroup, colGroup); } } } /** * Adds a column group. *

* 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. *

* 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 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 measureIt = measures.iterator(); measureIt.hasNext();) { JRCrosstabMeasure measure = measureIt.next(); addTotalVar(measure, null, colGroup); for (Iterator 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 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 colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); addTotalVar(measure, null, colGroup); } for (Iterator rowIt = rowGroups.iterator(); rowIt.hasNext();) { JRCrosstabRowGroup rowGroup = rowIt.next(); addTotalVar(measure, rowGroup, null); for (Iterator 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 it = rowGroups.listIterator(idx); it.hasNext();) { JRCrosstabRowGroup group = it.next(); rowGroupsMap.put(group.getName(), it.previousIndex()); } for (Iterator 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(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 measureIt = measures.iterator(); measureIt.hasNext();) { JRCrosstabMeasure measure = measureIt.next(); removeTotalVar(measure, rowGroup, null); for (Iterator 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 it = columnGroups.listIterator(idx); it.hasNext();) { JRCrosstabColumnGroup group = it.next(); columnGroupsMap.put(group.getName(), it.previousIndex()); } for (Iterator 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(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 measureIt = measures.iterator(); measureIt.hasNext();) { JRCrosstabMeasure measure = measureIt.next(); removeTotalVar(measure, null, colGroup); for (Iterator 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 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 colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); removeTotalVar(measure, null, colGroup); } for (Iterator rowIt = rowGroups.iterator(); rowIt.hasNext();) { JRCrosstabRowGroup rowGroup = rowIt.next(); removeTotalVar(measure, rowGroup, null); for (Iterator 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 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,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_COLUMN_GROUP_DOES_NOT_EXIST, new Object[]{columnTotalGroup}); } Pair cellKey = new Pair<>(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(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 getParametersList() { return parametersList; } /** * Returns the parameters indexed by names. * * @return the parameters indexed by names */ public Map 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 getVariablesMap() { JRVariable[] variables = getVariables(); Map variablesMap = new HashMap<>(); 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 void setGroupVariablesClass(List groups) { for (Iterator 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 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 colIt = columnGroups.iterator(); colIt.hasNext();) { JRCrosstabColumnGroup colGroup = colIt.next(); setTotalVarClass(measure, null, colGroup, valueClassName); } for (Iterator rowIt = rowGroups.iterator(); rowIt.hasNext();) { JRCrosstabRowGroup rowGroup = rowIt.next(); setTotalVarClass(measure, rowGroup, null, valueClassName); for (Iterator 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<>(parametersList.size()); clone.parametersMap = new HashMap<>(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 clonedVariables = new HashMap<>(); if (rowGroups != null) { clone.rowGroups = new ArrayList<>(rowGroups.size()); clone.rowGroupsMap = new HashMap<>(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<>(columnGroups.size()); clone.columnGroupsMap = new HashMap<>(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<>(measures.size()); clone.measuresMap = new HashMap<>(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<>(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<>(cellsList.size()); clone.cellsMap = new HashMap<>(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<>(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 getRowGroupsList() { return rowGroups; } public Map getRowGroupIndicesMap() { return rowGroupsMap; } public List getColumnGroupsList() { return columnGroups; } public Map getColumnGroupIndicesMap() { return columnGroupsMap; } public List getMesuresList() { return measures; } public Map 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); } @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<>(variablesList); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy