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

net.sf.jasperreports.engine.fill.JRFillChart Maven / Gradle / Ivy

There is a newer version: 6.21.3
Show newest version
/*
 * 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.engine.fill;

import java.awt.Color;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.SortedSet;
import java.util.TimeZone;

import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.MeterInterval;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.Range;
import org.jfree.data.general.Dataset;

import net.sf.jasperreports.charts.ChartContext;
import net.sf.jasperreports.charts.ChartTheme;
import net.sf.jasperreports.charts.JRAreaPlot;
import net.sf.jasperreports.charts.JRBar3DPlot;
import net.sf.jasperreports.charts.JRBarPlot;
import net.sf.jasperreports.charts.JRBubblePlot;
import net.sf.jasperreports.charts.JRCandlestickPlot;
import net.sf.jasperreports.charts.JRCategoryDataset;
import net.sf.jasperreports.charts.JRChartAxis;
import net.sf.jasperreports.charts.JRDataRange;
import net.sf.jasperreports.charts.JRGanttDataset;
import net.sf.jasperreports.charts.JRHighLowDataset;
import net.sf.jasperreports.charts.JRHighLowPlot;
import net.sf.jasperreports.charts.JRLinePlot;
import net.sf.jasperreports.charts.JRMeterPlot;
import net.sf.jasperreports.charts.JRMultiAxisPlot;
import net.sf.jasperreports.charts.JRPie3DPlot;
import net.sf.jasperreports.charts.JRPieDataset;
import net.sf.jasperreports.charts.JRPiePlot;
import net.sf.jasperreports.charts.JRScatterPlot;
import net.sf.jasperreports.charts.JRThermometerPlot;
import net.sf.jasperreports.charts.JRTimePeriodDataset;
import net.sf.jasperreports.charts.JRTimeSeriesDataset;
import net.sf.jasperreports.charts.JRTimeSeriesPlot;
import net.sf.jasperreports.charts.JRValueDataset;
import net.sf.jasperreports.charts.JRXyDataset;
import net.sf.jasperreports.charts.JRXyzDataset;
import net.sf.jasperreports.charts.fill.JRFillCategoryDataset;
import net.sf.jasperreports.charts.fill.JRFillChartAxis;
import net.sf.jasperreports.charts.fill.JRFillGanttDataset;
import net.sf.jasperreports.charts.fill.JRFillHighLowDataset;
import net.sf.jasperreports.charts.fill.JRFillMultiAxisPlot;
import net.sf.jasperreports.charts.fill.JRFillPieDataset;
import net.sf.jasperreports.charts.fill.JRFillTimePeriodDataset;
import net.sf.jasperreports.charts.fill.JRFillTimeSeriesDataset;
import net.sf.jasperreports.charts.fill.JRFillXyDataset;
import net.sf.jasperreports.charts.fill.JRFillXyzDataset;
import net.sf.jasperreports.charts.type.AxisPositionEnum;
import net.sf.jasperreports.charts.type.EdgeEnum;
import net.sf.jasperreports.charts.util.CategoryChartHyperlinkProvider;
import net.sf.jasperreports.charts.util.ChartHyperlinkProvider;
import net.sf.jasperreports.charts.util.ChartUtil;
import net.sf.jasperreports.charts.util.HighLowChartHyperlinkProvider;
import net.sf.jasperreports.charts.util.JRMeterInterval;
import net.sf.jasperreports.charts.util.MultiAxisChartHyperlinkProvider;
import net.sf.jasperreports.charts.util.PieChartHyperlinkProvider;
import net.sf.jasperreports.charts.util.TimePeriodChartHyperlinkProvider;
import net.sf.jasperreports.charts.util.TimeSeriesChartHyperlinkProvider;
import net.sf.jasperreports.charts.util.XYChartHyperlinkProvider;
import net.sf.jasperreports.engine.JRAbstractChartCustomizer;
import net.sf.jasperreports.engine.JRChart;
import net.sf.jasperreports.engine.JRChartCustomizer;
import net.sf.jasperreports.engine.JRChartDataset;
import net.sf.jasperreports.engine.JRChartPlot;
import net.sf.jasperreports.engine.JRChartPlot.JRSeriesColor;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRExpressionCollector;
import net.sf.jasperreports.engine.JRFont;
import net.sf.jasperreports.engine.JRGroup;
import net.sf.jasperreports.engine.JRHyperlinkParameter;
import net.sf.jasperreports.engine.JRLineBox;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPrintHyperlinkParameters;
import net.sf.jasperreports.engine.JRPrintImage;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.JRVisitor;
import net.sf.jasperreports.engine.JasperReportsContext;
import net.sf.jasperreports.engine.NamedChartCustomizer;
import net.sf.jasperreports.engine.base.JRBaseChart;
import net.sf.jasperreports.engine.type.EvaluationTimeEnum;
import net.sf.jasperreports.engine.type.HyperlinkTypeEnum;
import net.sf.jasperreports.engine.type.ModeEnum;
import net.sf.jasperreports.engine.util.JRClassLoader;
import net.sf.jasperreports.engine.util.JRStringUtil;
import net.sf.jasperreports.engine.util.StyleUtil;
import net.sf.jasperreports.export.HtmlReportConfiguration;
import net.sf.jasperreports.renderers.Renderable;


/**
 * @author Teodor Danciu ([email protected])
 * @author Some enhancements by Barry Klawans ([email protected])
 */
public class JRFillChart extends JRFillElement implements JRChart
{
	public static final String EXCEPTION_MESSAGE_KEY_CUSTOMIZER_INSTANCE_ERROR = "charts.customizer.instance.error";
	public static final String EXCEPTION_MESSAGE_KEY_MULTIAXIS_PLOT_TYPES_MIX_NOT_ALLOWED = "charts.multiaxis.plot.types.mix.not.allowed";
	public static final String EXCEPTION_MESSAGE_KEY_MULTIAXIS_PLOT_NOT_SUPPORTED = "charts.multiaxis.plot.not.supported";

	/**
	 *
	 */
	protected byte chartType;

	/**
	 *
	 */
	protected JRFont titleFont;
	protected JRFont subtitleFont;
	protected JRFont legendFont;

	protected final JRLineBox initLineBox;
	protected JRLineBox lineBox;

	/**
	 *
	 */
	protected JRGroup evaluationGroup;

	protected JRFillChartDataset dataset;
	protected JRChartPlot plot;

	protected Renderable renderer;
	private String anchorName;
	private Integer bookmarkLevel;
	private String hyperlinkReference;
	private Boolean hyperlinkWhen;
	private String hyperlinkAnchor;
	private Integer hyperlinkPage;
	private String hyperlinkTooltip;
	private JRPrintHyperlinkParameters hyperlinkParameters;

	protected List chartCustomizers;
	
	protected String renderType;
	protected ChartTheme theme;

	protected JFreeChart jfreeChart;
	protected ChartHyperlinkProvider chartHyperlinkProvider;

	/**
	 *
	 */
	protected JRFillChart(
		JRBaseFiller filler,
		JRChart chart,
		JRFillObjectFactory factory
		)
	{
		super(filler, chart, factory);

		/*   */
		chartType = chart.getChartType();

		switch(chartType) {
			case CHART_TYPE_AREA:
				dataset = (JRFillChartDataset) factory.getCategoryDataset((JRCategoryDataset) chart.getDataset());
				plot = factory.getAreaPlot((JRAreaPlot) chart.getPlot());
				break;
			case CHART_TYPE_BAR:
				dataset = (JRFillChartDataset) factory.getCategoryDataset((JRCategoryDataset) chart.getDataset());
				plot = factory.getBarPlot((JRBarPlot) chart.getPlot());
				break;
			case CHART_TYPE_BAR3D:
				dataset = (JRFillChartDataset) factory.getCategoryDataset((JRCategoryDataset) chart.getDataset());
				plot = factory.getBar3DPlot((JRBar3DPlot) chart.getPlot());
				break;
			case CHART_TYPE_BUBBLE:
				dataset = (JRFillChartDataset) factory.getXyzDataset((JRXyzDataset) chart.getDataset());
				plot = factory.getBubblePlot((JRBubblePlot) chart.getPlot());
				break;
			case CHART_TYPE_CANDLESTICK:
				dataset = (JRFillChartDataset) factory.getHighLowDataset((JRHighLowDataset) chart.getDataset());
				plot = factory.getCandlestickPlot((JRCandlestickPlot) chart.getPlot());
				break;
			case CHART_TYPE_HIGHLOW:
				dataset = (JRFillChartDataset) factory.getHighLowDataset((JRHighLowDataset) chart.getDataset());
				plot = factory.getHighLowPlot((JRHighLowPlot) chart.getPlot());
				break;
			case CHART_TYPE_LINE:
				dataset = (JRFillChartDataset) factory.getCategoryDataset((JRCategoryDataset) chart.getDataset());
				plot = factory.getLinePlot((JRLinePlot) chart.getPlot());
				break;
			case CHART_TYPE_METER:
				dataset = (JRFillChartDataset) factory.getValueDataset((JRValueDataset) chart.getDataset());
				plot = factory.getMeterPlot((JRMeterPlot) chart.getPlot());
				break;
			case CHART_TYPE_MULTI_AXIS:
				plot = factory.getMultiAxisPlot((JRMultiAxisPlot) chart.getPlot());
				dataset = ((JRFillMultiAxisPlot)plot).getMainDataset();
				break;
			case CHART_TYPE_PIE:
				dataset = (JRFillChartDataset) factory.getPieDataset((JRPieDataset) chart.getDataset());
				plot = factory.getPiePlot((JRPiePlot) chart.getPlot());
				break;
			case CHART_TYPE_PIE3D:
				dataset = (JRFillChartDataset) factory.getPieDataset((JRPieDataset) chart.getDataset());
				plot = factory.getPie3DPlot((JRPie3DPlot) chart.getPlot());
				break;
			case CHART_TYPE_SCATTER:
				dataset = (JRFillChartDataset) factory.getXyDataset((JRXyDataset) chart.getDataset());
				plot = factory.getScatterPlot((JRScatterPlot) chart.getPlot());
				break;
			case CHART_TYPE_STACKEDBAR:
				dataset = (JRFillChartDataset) factory.getCategoryDataset((JRCategoryDataset) chart.getDataset());
				plot = factory.getBarPlot((JRBarPlot) chart.getPlot());
				break;
			case CHART_TYPE_STACKEDBAR3D:
				dataset = (JRFillChartDataset) factory.getCategoryDataset((JRCategoryDataset) chart.getDataset());
				plot = factory.getBar3DPlot((JRBar3DPlot) chart.getPlot());
				break;
			case CHART_TYPE_THERMOMETER:
				dataset = (JRFillChartDataset) factory.getValueDataset((JRValueDataset) chart.getDataset());
				plot = factory.getThermometerPlot((JRThermometerPlot) chart.getPlot());
				break;
			case CHART_TYPE_TIMESERIES:
				dataset = (JRFillChartDataset) factory.getTimeSeriesDataset((JRTimeSeriesDataset)chart.getDataset());
				plot = factory.getTimeSeriesPlot((JRTimeSeriesPlot)chart.getPlot());
				break;
			case CHART_TYPE_XYAREA:
				dataset = (JRFillChartDataset) factory.getXyDataset((JRXyDataset) chart.getDataset());
				plot = factory.getAreaPlot((JRAreaPlot) chart.getPlot());
				break;
			case CHART_TYPE_XYBAR:
				switch (chart.getDataset().getDatasetType()){
					case JRChartDataset.TIMESERIES_DATASET:
						dataset = (JRFillChartDataset) factory.getTimeSeriesDataset( (JRTimeSeriesDataset)chart.getDataset() );
						break;
					case JRChartDataset.TIMEPERIOD_DATASET:
						dataset = (JRFillChartDataset) factory.getTimePeriodDataset((JRTimePeriodDataset) chart.getDataset() );
						break;
					case JRChartDataset.XY_DATASET:
						dataset = (JRFillChartDataset) factory.getXyDataset( (JRXyDataset)chart.getDataset() );
						break;
					default:
				}

				plot = factory.getBarPlot((JRBarPlot) chart.getPlot());
				break;
			case CHART_TYPE_XYLINE:
				dataset = (JRFillChartDataset) factory.getXyDataset((JRXyDataset) chart.getDataset());
				plot = factory.getLinePlot((JRLinePlot) chart.getPlot());
				break;
			case CHART_TYPE_STACKEDAREA:
				dataset = (JRFillChartDataset) factory.getCategoryDataset((JRCategoryDataset) chart.getDataset());
				plot = factory.getAreaPlot((JRAreaPlot) chart.getPlot());
				break;
			case CHART_TYPE_GANTT:
				dataset = (JRFillChartDataset) factory.getGanttDataset((JRGanttDataset) chart.getDataset());
				plot = factory.getBarPlot((JRBarPlot) chart.getPlot());
				break;
			default:
				throw 
					new JRRuntimeException(
						JRBaseChart.EXCEPTION_MESSAGE_KEY_CHART_TYPE_NOT_SUPPORTED,  
						new Object[]{getChartType()} 
						);
		}

		titleFont = factory.getFont(chart, chart.getTitleFont());
		subtitleFont = factory.getFont(chart, chart.getSubtitleFont());
		//FIXME this is inconsistent with the lines above
		legendFont =  factory.getFont(this, chart.getLegendFont());
		
		initLineBox = chart.getLineBox().clone(this);

		evaluationGroup = factory.getGroup(chart.getEvaluationGroup());

		chartCustomizers = new ArrayList<>();
		JRChartCustomizer chartCustomizer = createAndInitCustomizer(chart.getCustomizerClass(), null);
		if (chartCustomizer != null)
		{
			chartCustomizers.add(chartCustomizer);
		}

		List properties = 
			JRPropertiesUtil.getProperties(
				chart.getPropertiesMap(), 
				NamedChartCustomizer.CUSTOMIZER_CLASS_PROPERTY_PREFIX
				);
		for (JRPropertiesUtil.PropertySuffix prop : properties) 
		{
			chartCustomizer = createAndInitCustomizer(prop.getValue(), prop.getSuffix());
			if (chartCustomizer != null)
			{
				chartCustomizers.add(chartCustomizer);
			}
		}
		
		renderType = chart.getRenderType();
		if(renderType == null)
		{
			renderType = filler.getPropertiesUtil().getProperty(getParentProperties(), JRChart.PROPERTY_CHART_RENDER_TYPE);
		}
	}

	/**
	 *
	 */
	protected JRChartCustomizer createAndInitCustomizer(
		String customizerClassName,
		String customizerName
		)
	{
		JRChartCustomizer customizer = null;

		if (customizerClassName != null && customizerClassName.length() > 0) 
		{
			try 
			{
				Class customizerClass = JRClassLoader.loadClassForName(customizerClassName);
				customizer = (JRChartCustomizer) customizerClass.getDeclaredConstructor().newInstance();
			}
			catch (ClassNotFoundException | InstantiationException | IllegalAccessException 
				| NoSuchMethodException | InvocationTargetException e) 
			{
				throw 
					new JRRuntimeException(
						EXCEPTION_MESSAGE_KEY_CUSTOMIZER_INSTANCE_ERROR,
						(Object[])null,
						e);
			}

			if (customizer instanceof JRAbstractChartCustomizer)
			{
				((JRAbstractChartCustomizer) customizer).init(this);
			}

			if (customizer instanceof NamedChartCustomizer)
			{
				((NamedChartCustomizer) customizer).setName(customizerName);
			}
		}
		
		return customizer;
	}

	@Override
	public void setBand(JRFillBand band)
	{
		super.setBand(band);
		
		dataset.setBand(band);
		((JRFillChartPlot) plot).setBand(band);
	}


	@Override
	protected void evaluateStyle(
		byte evaluation
		) throws JRException
	{
		super.evaluateStyle(evaluation);

		lineBox = null;
		
		if (providerStyle != null)
		{
			lineBox = initLineBox.clone(this);
			StyleUtil.appendBox(lineBox, providerStyle.getLineBox());
		}
	}


	@Override
	public ModeEnum getModeValue()
	{
		return getStyleResolver().getMode(this, ModeEnum.TRANSPARENT);
	}

	@Override
	public Boolean getShowLegend()
	{
		return ((JRChart)parent).getShowLegend();
	}

	@Override
	public void setShowLegend(Boolean isShowLegend)
	{
	}

	@Override
	public String getRenderType()
	{
		return renderType;
	}

	@Override
	public void setRenderType(String renderType)
	{
	}

	@Override
	public String getTheme()
	{
		return ((JRChart)parent).getTheme();
	}

	@Override
	public void setTheme(String theme)
	{
	}

	@Override
	public EvaluationTimeEnum getEvaluationTimeValue()
	{
		return ((JRChart)parent).getEvaluationTimeValue();
	}

	@Override
	public JRGroup getEvaluationGroup()
	{
		return evaluationGroup;
	}

	@Override
	public JRLineBox getLineBox()
	{
		return lineBox == null ? initLineBox : lineBox;
	}

	@Override
	public JRFont getTitleFont()
	{
		return titleFont;
	}

	@Override
	public EdgeEnum getTitlePositionValue()
	{
		return ((JRChart)parent).getTitlePositionValue();
	}

	@Override
	public void setTitlePosition(EdgeEnum titlePosition)
	{
		throw new UnsupportedOperationException();
	}

	@Override
	public Color getTitleColor()
	{
		return getStyleResolver().getTitleColor(this);
	}

	@Override
	public Color getOwnTitleColor()
	{
		return ((JRChart)parent).getOwnTitleColor();
	}

	@Override
	public void setTitleColor(Color titleColor)
	{
	}

	@Override
	public JRFont getSubtitleFont()
	{
		return subtitleFont;
	}

	@Override
	public Color getOwnSubtitleColor()
	{
		return ((JRChart)parent).getOwnSubtitleColor();
	}

	@Override
	public Color getSubtitleColor()
	{
		return getStyleResolver().getSubtitleColor(this);
	}

	@Override
	public void setSubtitleColor(Color subtitleColor)
	{
	}

	/**
	 * Returns the color to use for text in the legend.
	 *
	 * @return the color to use for text in the legend
	 */
	@Override
	public Color getOwnLegendColor()
	{
		return ((JRChart)parent).getOwnLegendColor();
	}

	/**
	 * Returns the inherited color to use for text in the legend.
	 *
	 * @return the color to use for text in the legend
	 */
	@Override
	public Color getLegendColor()
	{
		return getStyleResolver().getLegendColor(this);
	}

	/**
	 * Sets the color to use for text in the legend.
	 *
	 * @param legendColor the color to use for text in the legend
	 */
	@Override
	public void setLegendColor(Color legendColor)
	{
	}

	/**
	 * Returns the color to use as the background of the legend.
	 *
	 * @return the color to use as the background of the legend
	 */
	@Override
	public Color getOwnLegendBackgroundColor()
	{
		return ((JRChart)parent).getOwnLegendBackgroundColor();
	}

	/**
	 * Returns the color to use as the background of the legend.
	 *
	 * @return the color to use as the background of the legend
	 */
	@Override
	public Color getLegendBackgroundColor()
	{
		return getStyleResolver().getLegendBackgroundColor(this);
	}

	/**
	 * Sets the color to use for the background of the legend.
	 *
	 * @param legendBackgroundColor the color to use for the background of the legend
	 */
	@Override
	public void setLegendBackgroundColor(Color legendBackgroundColor)
	{
	}

	/**
	 * Returns the font to use in the legend.
	 *
	 * @return the font to use in the legend
	 */
	@Override
	public JRFont getLegendFont()
	{
		return legendFont;
	}

	@Override
	public EdgeEnum getLegendPositionValue()
	{
		return ((JRChart)parent).getLegendPositionValue();
	}

	@Override
	public void setLegendPosition(EdgeEnum legendPosition)
	{
		throw new UnsupportedOperationException();
	}

	@Override
	public JRExpression getTitleExpression()
	{
		return ((JRChart)parent).getTitleExpression();
	}

	@Override
	public JRExpression getSubtitleExpression()
	{
		return ((JRChart)parent).getSubtitleExpression();
	}

	@Override
	public HyperlinkTypeEnum getHyperlinkTypeValue()
	{
		return ((JRChart)parent).getHyperlinkTypeValue();
	}

	@Override
	public byte getHyperlinkTarget()
	{
		return ((JRChart)parent).getHyperlinkTarget();
	}

	@Override
	public JRExpression getAnchorNameExpression()
	{
		return ((JRChart)parent).getAnchorNameExpression();
	}
	
	@Override
	public JRExpression getBookmarkLevelExpression()
	{
		return ((JRChart)parent).getBookmarkLevelExpression();
	}

	@Override
	public JRExpression getHyperlinkReferenceExpression()
	{
		return ((JRChart)parent).getHyperlinkReferenceExpression();
	}

	@Override
	public JRExpression getHyperlinkWhenExpression()
	{
		return ((JRChart)parent).getHyperlinkWhenExpression();
	}

	@Override
	public JRExpression getHyperlinkAnchorExpression()
	{
		return ((JRChart)parent).getHyperlinkAnchorExpression();
	}

	@Override
	public JRExpression getHyperlinkPageExpression()
	{
		return ((JRChart)parent).getHyperlinkPageExpression();
	}


	/**
	 *
	 */
	public Locale getLocale()
	{
		return filler.getLocale();
	}

	@Override
	public TimeZone getTimeZone()
	{
		return super.getTimeZone();
	}

	@Override
	public JRChartDataset getDataset()
	{
		return dataset;
	}

	/**
	 *
	 */
	public void setDataset(JRFillChartDataset dataset)
	{
		this.dataset = dataset;
	}

	@Override
	public JRChartPlot getPlot()
	{
		return plot;
	}

	/**
	 *
	 */
	protected Renderable getRenderable()
	{
		return renderer;
	}

	/**
	 *
	 */
	protected String getAnchorName()
	{
		return anchorName;
	}

	/**
	 *
	 */
	protected String getHyperlinkReference()
	{
		return hyperlinkReference;
	}

	/**
	 *
	 */
	protected String getHyperlinkAnchor()
	{
		return hyperlinkAnchor;
	}

	/**
	 *
	 */
	protected Integer getHyperlinkPage()
	{
		return hyperlinkPage;
	}

	protected String getHyperlinkTooltip()
	{
		return hyperlinkTooltip;
	}

	@Override
	public Color getDefaultLineColor() 
	{
		return getForecolor();
	}


	/**
	 *
	 */
	protected JRTemplateImage getJRTemplateImage()
	{
		return (JRTemplateImage) getElementTemplate();
	}

	@Override
	protected JRTemplateElement createElementTemplate()
	{
		JRTemplateImage templateImage = new JRTemplateImage(getElementOrigin(), 
				filler.getJasperPrint().getDefaultStyleProvider(), this);
		templateImage.setUsingCache(false);
		return templateImage;
	}


	@Override
	protected void rewind()
	{
	}


	@Override
	protected void evaluate(byte evaluation) throws JRException
	{
		reset();

		evaluatePrintWhenExpression(evaluation);

		if (isPrintWhenExpressionNull() || isPrintWhenTrue())
		{
			bookmarkLevel = getBookmarkLevel(evaluateExpression(getBookmarkLevelExpression(), evaluation));

			if (getEvaluationTimeValue() == EvaluationTimeEnum.NOW)
			{
				evaluateRenderer(evaluation);
			}
		}
	}


	/**
	 *
	 */
	protected void evaluateRenderer(byte evaluation) throws JRException
	{
		JFreeChart chart = evaluateChart(evaluation);
		
		Rectangle2D rectangle = new Rectangle2D.Double(0,0,getWidth(),getHeight());

		renderer = 
			ChartUtil.getInstance(filler.getJasperReportsContext()).getChartRenderableFactory(getRenderType()).getRenderable(
				filler.getJasperReportsContext(),
				chart, 
				chartHyperlinkProvider,
				rectangle
				);
	}
	
	protected ChartHyperlinkProvider getHyperlinkProvider()
	{
		return chartHyperlinkProvider;
	}
	
	/**
	 *
	 */
	protected JFreeChart evaluateChart(byte evaluation) throws JRException
	{
		evaluateProperties(evaluation);
		evaluateDatasetRun(evaluation);
		evaluateStyle(evaluation);

		// needs to be lazy loaded here because in the JRFillChart constructor above, the parent properties could return null,
		// as the filler main dataset is not yet set, if the current band is a group band
		if (theme == null)
		{
			String themeName = getTheme();
			if(themeName == null)
			{
				themeName = filler.getPropertiesUtil().getProperty(getParentProperties(), JRChart.PROPERTY_CHART_THEME);
			}

			theme = ChartUtil.getInstance(filler.getJasperReportsContext()).getTheme(themeName);
		}
		
		if (getChartType() == JRChart.CHART_TYPE_MULTI_AXIS)
		{
			//FIXMECHARTTHEME multi axis charts do not support themes
			createMultiAxisChart(evaluation);
		}
		else
		{
			jfreeChart = theme.createChart(new FillChartContext(evaluation));

			chartHyperlinkProvider = createChartHyperlinkProvider();
		}

		for (JRChartCustomizer chartCustomizer : chartCustomizers)
		{
			chartCustomizer.customize(jfreeChart, this);
		}

		anchorName = (String) evaluateExpression(getAnchorNameExpression(), evaluation);
		hyperlinkReference = (String) evaluateExpression(getHyperlinkReferenceExpression(), evaluation);
		hyperlinkWhen = (Boolean) evaluateExpression(getHyperlinkWhenExpression(), evaluation);
		hyperlinkAnchor = (String) evaluateExpression(getHyperlinkAnchorExpression(), evaluation);
		hyperlinkPage = (Integer) evaluateExpression(getHyperlinkPageExpression(), evaluation);
		hyperlinkTooltip = (String) evaluateExpression(getHyperlinkTooltipExpression(), evaluation);
		hyperlinkParameters = JRFillHyperlinkHelper.evaluateHyperlinkParameters(this, expressionEvaluator, evaluation);

		return jfreeChart;
	}


	@Override
	protected boolean prepare(
		int availableHeight,
		boolean isOverflow
		)
	{
		boolean willOverflow = false;

		if (
			isPrintWhenExpressionNull() ||
			( !isPrintWhenExpressionNull() &&
			isPrintWhenTrue() )
			)
		{
			setToPrint(true);
		}
		else
		{
			setToPrint(false);
		}

		if (!isToPrint())
		{
			return willOverflow;
		}

		boolean isToPrint = true;
		boolean isReprinted = false;

		if (getEvaluationTimeValue() == EvaluationTimeEnum.NOW)
		{
			if (isOverflow && isAlreadyPrinted() && !isPrintWhenDetailOverflows())
			{
				isToPrint = false;
			}

			if (
				isToPrint &&
				availableHeight < getRelativeY() + getHeight()
				)
			{
				isToPrint = false;
				willOverflow = true;
			}

			if (
				isToPrint &&
				isOverflow &&
				//(this.isAlreadyPrinted() || !this.isPrintRepeatedValues())
				(isPrintWhenDetailOverflows() && (isAlreadyPrinted() || (!isAlreadyPrinted() && !isPrintRepeatedValues())))
				)
			{
				isReprinted = true;
			}

			if (
				isToPrint &&
				isRemoveLineWhenBlank() &&
				getRenderable() == null
				)
			{
				isToPrint = false;
			}
		}
		else
		{
			if (isOverflow && isAlreadyPrinted() && !isPrintWhenDetailOverflows())
			{
				isToPrint = false;
			}

			if (
				isToPrint &&
				availableHeight < getRelativeY() + getHeight()
				)
			{
				isToPrint = false;
				willOverflow = true;
			}

			if (
				isToPrint &&
				isOverflow &&
				//(this.isAlreadyPrinted() || !this.isPrintRepeatedValues())
				(isPrintWhenDetailOverflows() && (isAlreadyPrinted() || (!isAlreadyPrinted() && !isPrintRepeatedValues())))
				)
			{
				isReprinted = true;
			}
		}

		setToPrint(isToPrint);
		setReprinted(isReprinted);

		return willOverflow;
	}


	@Override
	protected JRPrintElement fill()
	{
		JRTemplatePrintImage printImage = new JRTemplatePrintImage(getJRTemplateImage(), printElementOriginator);

		printImage.setUUID(getUUID());
		printImage.setX(getX());
		printImage.setY(getRelativeY());
		printImage.setWidth(getWidth());
		printImage.setHeight(getStretchHeight());
		printImage.setBookmarkLevel(getBookmarkLevel());
		printImage.getPropertiesMap().setProperty(HtmlReportConfiguration.PROPERTY_EMBED_IMAGE, Boolean.TRUE.toString());
		printImage.getPropertiesMap().setProperty(HtmlReportConfiguration.PROPERTY_EMBEDDED_SVG_USE_FONTS, Boolean.TRUE.toString());

		EvaluationTimeEnum evaluationTime = getEvaluationTimeValue();
		if (evaluationTime == EvaluationTimeEnum.NOW)
		{
			copy(printImage);
		}
		else
		{
			filler.addBoundElement(this, printImage, evaluationTime, getEvaluationGroup(), band);
		}

		return printImage;
	}


	/**
	 *
	 */
	protected void copy(JRPrintImage printImage)
	{
		printImage.setRenderer(getRenderable());
		printImage.setAnchorName(getAnchorName());
		if (getHyperlinkWhenExpression() == null || Boolean.TRUE.equals(hyperlinkWhen))
		{
			printImage.setHyperlinkReference(getHyperlinkReference());
			printImage.setHyperlinkAnchor(getHyperlinkAnchor());
			printImage.setHyperlinkPage(getHyperlinkPage());
			printImage.setHyperlinkTooltip(getHyperlinkTooltip());
			printImage.setHyperlinkParameters(hyperlinkParameters);
		}
		else
		{
			if (printImage instanceof JRTemplatePrintImage)//this is normally the case
			{
				((JRTemplatePrintImage) printImage).setHyperlinkOmitted(true);
			}
			
			printImage.setHyperlinkReference(null);
		}
		transferProperties(printImage);
	}

	@Override
	public byte getChartType()
	{
		return chartType;
	}


	@Override
	public void collectExpressions(JRExpressionCollector collector)
	{
		collector.collect(this);
	}


	@Override
	public void visit(JRVisitor visitor)
	{
		visitor.visitChart(this);
	}

	
	/**
	 *
	 */
	protected ChartHyperlinkProvider createChartHyperlinkProvider()
	{
		ChartHyperlinkProvider chartHyperlinkProvider = null;
		
		switch(getChartType()) 
		{
			case JRChart.CHART_TYPE_AREA:
			case JRChart.CHART_TYPE_BAR:
			case JRChart.CHART_TYPE_BAR3D:
			case JRChart.CHART_TYPE_LINE:
			case JRChart.CHART_TYPE_STACKEDBAR3D:
			case JRChart.CHART_TYPE_STACKEDBAR:
			case JRChart.CHART_TYPE_STACKEDAREA:
				chartHyperlinkProvider = new CategoryChartHyperlinkProvider(((JRFillCategoryDataset)getDataset()).getItemHyperlinks());
				break;
			case JRChart.CHART_TYPE_BUBBLE:
				chartHyperlinkProvider = new XYChartHyperlinkProvider(((JRFillXyzDataset)getDataset()).getItemHyperlinks());
				break;
			case JRChart.CHART_TYPE_SCATTER:
			case JRChart.CHART_TYPE_XYAREA:
			case JRChart.CHART_TYPE_XYLINE:
				chartHyperlinkProvider = new XYChartHyperlinkProvider(((JRFillXyDataset)getDataset()).getItemHyperlinks());
				break;
			case JRChart.CHART_TYPE_CANDLESTICK:
			case JRChart.CHART_TYPE_HIGHLOW:
				chartHyperlinkProvider = new HighLowChartHyperlinkProvider(((JRFillHighLowDataset)getDataset()).getItemHyperlinks());
				break;
			case JRChart.CHART_TYPE_MULTI_AXIS:
				//multi-axis charts are dealt with in createMultiAxisChart
				break;
			case JRChart.CHART_TYPE_PIE:
			case JRChart.CHART_TYPE_PIE3D:
				chartHyperlinkProvider = new PieChartHyperlinkProvider(((JRFillPieDataset)getDataset()).getSectionHyperlinks());
				break;
			case JRChart.CHART_TYPE_TIMESERIES:
				chartHyperlinkProvider = new TimeSeriesChartHyperlinkProvider(((JRFillTimeSeriesDataset)getDataset()).getItemHyperlinks());
				break;
			case JRChart.CHART_TYPE_XYBAR:
				switch(getDataset().getDatasetType())
				{
					case JRChartDataset.TIMESERIES_DATASET :
						chartHyperlinkProvider = new TimeSeriesChartHyperlinkProvider(((JRFillTimeSeriesDataset)getDataset()).getItemHyperlinks());
						break;
					case JRChartDataset.TIMEPERIOD_DATASET :
						chartHyperlinkProvider = new TimePeriodChartHyperlinkProvider(((JRFillTimePeriodDataset)getDataset()).getItemHyperlinks());
						break;
					case JRChartDataset.XY_DATASET :
						chartHyperlinkProvider = new XYChartHyperlinkProvider(((JRFillXyDataset)getDataset()).getItemHyperlinks());
						break;
					default:
						break;
				}
				break;
			case JRChart.CHART_TYPE_GANTT:
				chartHyperlinkProvider = new XYChartHyperlinkProvider(((JRFillGanttDataset)getDataset()).getItemHyperlinks());
				break;
			case JRChart.CHART_TYPE_METER:
			case JRChart.CHART_TYPE_THERMOMETER:
				//no item hyperlinks
				break;
			default:
				throw 
					new JRRuntimeException(
						JRBaseChart.EXCEPTION_MESSAGE_KEY_CHART_TYPE_NOT_SUPPORTED,  
						new Object[]{getChartType()} 
						);
		}

		return chartHyperlinkProvider;
	}



	/**
	 * Build and configure a multiple axis chart.  A multiple axis chart support more than
	 * one range axis.  Multiple datasets using different ranges can be displayed as long as
	 * they share a common domain axis.  Each dataset can be rendered differently, so one chart
	 * can contain (for example) two line charts, a bar chart and an area chart.
	 * 

* Multiple axis charts are handled differently than the other chart types. They do not * have a dataset, as each chart that is added to the multiple axis chart has its own * dataset. For simplicity, each dataset is treated as its own chart, and in fact we * reuse the design of all the chart types and let JFreeChart actually run them. Then * we pull out the bits we need and add it to the common chart. All the plot and chart * options on the nested charts is ignored, and all formatting is controlled by the plot * attached to the multiAxisChart. The one exception is seriesColor, which can be used in * a nested report to specify a color for a specific series in that report. * * @param evaluation current expression evaluation phase * @throws JRException */ protected void createMultiAxisChart(byte evaluation) throws JRException { // A multi axis chart has to have at least one axis and chart specified. // Create the first axis as the base plot, and then go ahead and create the // charts for any additional axes. Just take the renderer and data series // from those charts and add them to the first one. Plot mainPlot = null; JRFillMultiAxisPlot jrPlot = (JRFillMultiAxisPlot)getPlot(); // create a multi axis hyperlink provider MultiAxisChartHyperlinkProvider multiHyperlinkProvider = new MultiAxisChartHyperlinkProvider(); // Generate the main plot from the first axes specified. Iterator iter = jrPlot.getAxes().iterator(); if (iter.hasNext()) { JRFillChartAxis axis = (JRFillChartAxis)iter.next(); JRFillChart fillChart = axis.getFillChart(); //a JFreeChart object should be obtained first; the rendering type should be always "vector" jfreeChart = fillChart.evaluateChart(evaluation); //FIXME honor printWhenExpression // Override the plot from the first axis with the plot for the multi-axis // chart. //FIXME is the above comment true? //configureChart(jfreeChart, getPlot(), evaluation); mainPlot = jfreeChart.getPlot(); ChartHyperlinkProvider axisHyperlinkProvider = fillChart.getHyperlinkProvider(); if (mainPlot instanceof CategoryPlot) { CategoryPlot categoryPlot = (CategoryPlot) mainPlot; categoryPlot.setRangeAxisLocation(0, getChartAxisLocation(axis)); if (axisHyperlinkProvider != null) { multiHyperlinkProvider.addHyperlinkProvider(categoryPlot.getDataset(), axisHyperlinkProvider); } } else if (mainPlot instanceof XYPlot) { XYPlot xyPlot = (XYPlot) mainPlot; xyPlot.setRangeAxisLocation(0, getChartAxisLocation(axis)); if (axisHyperlinkProvider != null) { multiHyperlinkProvider.addHyperlinkProvider(xyPlot.getDataset(), axisHyperlinkProvider); } } } // Now handle all the extra axes, if any. int axisNumber = 0; while (iter.hasNext()) { JRFillChartAxis chartAxis = (JRFillChartAxis)iter.next(); JRFillChart fillChart = chartAxis.getFillChart(); fillChart.evaluatePrintWhenExpression(evaluation); if (!(fillChart.isPrintWhenExpressionNull() || fillChart.isPrintWhenTrue())) { continue; } axisNumber++; JFreeChart axisChart = fillChart.evaluateChart(evaluation); ChartHyperlinkProvider axisHyperlinkProvider = fillChart.getHyperlinkProvider(); // In JFreeChart to add a second chart type to an existing chart // you need to add an axis, a data series and a renderer. To // leverage existing code we simply create a new chart for the // axis and then pull out the bits we need and add them to the multi // chart. Currently JFree only supports category plots and xy plots // in a multi-axis chart, and you can not mix the two. if (mainPlot instanceof CategoryPlot) { CategoryPlot mainCatPlot = (CategoryPlot)mainPlot; if (!(axisChart.getPlot() instanceof CategoryPlot)) { throw new JRException( EXCEPTION_MESSAGE_KEY_MULTIAXIS_PLOT_TYPES_MIX_NOT_ALLOWED, (Object[])null ); } // Get the axis and add it to the multi axis chart plot CategoryPlot axisPlot = (CategoryPlot)axisChart.getPlot(); mainCatPlot.setRangeAxis(axisNumber, axisPlot.getRangeAxis()); mainCatPlot.setRangeAxisLocation(axisNumber, getChartAxisLocation(chartAxis)); // Add the data set and map it to the recently added axis mainCatPlot.setDataset(axisNumber, axisPlot.getDataset()); mainCatPlot.mapDatasetToRangeAxis(axisNumber, axisNumber); // Set the renderer to use to draw the dataset. mainCatPlot.setRenderer(axisNumber, axisPlot.getRenderer()); // Handle any color series for this chart configureAxisSeriesColors(axisPlot.getRenderer(), fillChart.getPlot()); if (axisHyperlinkProvider != null) { multiHyperlinkProvider.addHyperlinkProvider(axisPlot.getDataset(), axisHyperlinkProvider); } } else if (mainPlot instanceof XYPlot) { XYPlot mainXyPlot = (XYPlot)mainPlot; if (!(axisChart.getPlot() instanceof XYPlot)) { throw new JRException( EXCEPTION_MESSAGE_KEY_MULTIAXIS_PLOT_TYPES_MIX_NOT_ALLOWED, (Object[])null ); } // Get the axis and add it to the multi axis chart plot XYPlot axisPlot = (XYPlot)axisChart.getPlot(); mainXyPlot.setRangeAxis(axisNumber, axisPlot.getRangeAxis()); mainXyPlot.setRangeAxisLocation(axisNumber, getChartAxisLocation(chartAxis)); // Add the data set and map it to the recently added axis mainXyPlot.setDataset(axisNumber, axisPlot.getDataset()); mainXyPlot.mapDatasetToRangeAxis(axisNumber, axisNumber); // Set the renderer to use to draw the dataset. mainXyPlot.setRenderer(axisNumber, axisPlot.getRenderer()); // Handle any color series for this chart configureAxisSeriesColors(axisPlot.getRenderer(), fillChart.getPlot()); if (axisHyperlinkProvider != null) { multiHyperlinkProvider.addHyperlinkProvider(axisPlot.getDataset(), axisHyperlinkProvider); } } else { throw new JRException( EXCEPTION_MESSAGE_KEY_MULTIAXIS_PLOT_NOT_SUPPORTED, (Object[])null ); } } //set the multi hyperlink provider chartHyperlinkProvider = multiHyperlinkProvider; } /** * The series colors set in the main plot of a multiple axis chart are used for * all the rendered charts in the plot. This is a problem with multiple line * charts, using different scales and thus different axis. All the lines will * be drawn using the first series color (since they are the first series for that * rendered) and it will be impossible to tell them apart. *

* For this reason we interpret series colors for charts included in a multiple * axis chart as specify absolute series colors for that renderer. * * @param renderer the renderer of the chart being created * @param jrPlot the Jasper view of that plot */ private void configureAxisSeriesColors(CategoryItemRenderer renderer, JRChartPlot jrPlot) { SortedSet seriesColors = jrPlot.getSeriesColors(); if (seriesColors != null) { Iterator iter = seriesColors.iterator(); while (iter.hasNext()) { JRSeriesColor seriesColor = iter.next(); renderer.setSeriesPaint(seriesColor.getSeriesOrder(), seriesColor.getColor()); } } } /** * The series colors set in the main plot of a multiple axis chart are used for * all the rendered charts in the plot. This is a problem with multiple line * charts, using different scales and thus different axis. All the lines will * be drawn using the first series color (since they are the first series for that * rendered) and it will be impossible to tell them apart. *
* For this reason we interpret series colors for charts included in a multiple * axis chart as specify absolute series colors for that renderer. * * @param renderer the renderer of the chart being created * @param jrPlot the Jasper view of that plot */ private void configureAxisSeriesColors(XYItemRenderer renderer, JRChartPlot jrPlot) { SortedSet seriesColors = jrPlot.getSeriesColors(); if (seriesColors != null) { Iterator iter = seriesColors.iterator(); while (iter.hasNext()) { JRSeriesColor seriesColor = iter.next(); renderer.setSeriesPaint(seriesColor.getSeriesOrder(), seriesColor.getColor()); } } } /** * Converts a JasperReport data range into one understood by JFreeChart. * * @param dataRange the JasperReport version of the range * @param evaluation current expression evaluation phase * @return the JFreeChart version of the range * @throws JRException thrown when the low value of the range is greater than the * high value */ protected Range convertRange(JRDataRange dataRange, byte evaluation) throws JRException { if (dataRange == null) { return null; } Number low = (Number)evaluateExpression(dataRange.getLowExpression(), evaluation); Number high = (Number)evaluateExpression(dataRange.getHighExpression(), evaluation); return new Range( low != null ? low.doubleValue() : 0.0, high != null ? high.doubleValue() : 100.0); } /** * Converts a JasperReports meter interval to one that JFreeChart understands. * * @param interval the JasperReports definition of an interval * @param evaluation current evaluation time * @return the JFreeChart version of the same interval * @throws JRException thrown when the interval contains an invalid range */ protected MeterInterval convertInterval(JRMeterInterval interval, byte evaluation) throws JRException { String label = interval.getLabel(); if (label == null) { label = ""; } Range range = convertRange(interval.getDataRange(), evaluation); Color color = interval.getBackgroundColor(); float[] components = color.getRGBColorComponents(null); float alpha = (float)(interval.getAlphaDouble() == null ? JRMeterInterval.DEFAULT_TRANSPARENCY : interval.getAlphaDouble()); Color alphaColor = new Color(components[0], components[1], components[2], alpha); return new MeterInterval(label, range, alphaColor, null, alphaColor); } protected AxisLocation getChartAxisLocation(JRFillChartAxis chartAxis) { return chartAxis.getPositionValue() != null && chartAxis.getPositionValue() == AxisPositionEnum.RIGHT_OR_BOTTOM ? AxisLocation.BOTTOM_OR_RIGHT : AxisLocation.TOP_OR_LEFT; } @Override protected void resolveElement(JRPrintElement element, byte evaluation) throws JRException { evaluateRenderer(evaluation); copy((JRPrintImage) element); filler.updateBookmark(element); } @Override public int getBookmarkLevel() { return this.bookmarkLevel == null ? ((JRChart)parent).getBookmarkLevel() : this.bookmarkLevel; } @Override public String getCustomizerClass() { return ((JRChart)parent).getCustomizerClass(); } private void evaluateDatasetRun(byte evaluation) throws JRException { dataset.evaluateDatasetRun(evaluation); } @Override public JRFillCloneable createClone(JRFillCloneFactory factory) { //not needed return null; } @Override public JRHyperlinkParameter[] getHyperlinkParameters() { return ((JRChart) parent).getHyperlinkParameters(); } @Override public String getLinkType() { return ((JRChart) parent).getLinkType(); } @Override public String getLinkTarget() { return ((JRChart) parent).getLinkTarget(); } @Override public JRExpression getHyperlinkTooltipExpression() { return ((JRChart) parent).getHyperlinkTooltipExpression(); } class FillChartContext implements ChartContext { private final byte evaluation; protected FillChartContext(byte evaluation) { this.evaluation = evaluation; JRFillChart.this.filler.getJasperReportsContext(); } @Override public JasperReportsContext getJasperReportsContext() { return JRFillChart.this.filler.getJasperReportsContext(); } @Override public String evaluateTextExpression(JRExpression expression) throws JRException { return JRStringUtil.getString(JRFillChart.this.evaluateExpression(expression, evaluation)); } @Override public Object evaluateExpression(JRExpression expression) throws JRException { return JRFillChart.this.evaluateExpression(expression, evaluation); } @Override public JRChart getChart() { return JRFillChart.this; } @Override public Dataset getDataset() { return ((JRFillChartDataset)JRFillChart.this.getDataset()).getDataset(); } @Override public Object getLabelGenerator() { return ((JRFillChartDataset)JRFillChart.this.getDataset()).getLabelGenerator(); } @Override public Locale getLocale() { return JRFillChart.this.getLocale(); } @Override public TimeZone getTimeZone() { return JRFillChart.this.getTimeZone(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy