/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program 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.
*
* Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.plugin.jfreereport.reportcharts;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.Plot;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.PieDataset;
import org.jfree.util.Rotation;
import org.pentaho.reporting.engine.classic.core.function.ExpressionRuntime;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.libraries.formatting.FastDecimalFormat;
import java.awt.*;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
public class PieChartExpression extends AbstractChartExpression {
private static final int EXPLODE_VALUE = 0;
private static final int EXPLODE_MIN = 1;
private static final int EXPLODE_MAX = 2;
private static final long serialVersionUID = 5755617219149952355L;
private boolean rotationClockwise;
private String explodeSegment;
private Double explodePct;
private boolean ignoreNulls;
private boolean ignoreZeros;
private String pieLabelFormat;
private boolean circular;
private String pieLegendLabelFormat;
private Color shadowPaint;
private Double shadowXOffset;
private Double shadowYOffset;
public PieChartExpression() {
rotationClockwise = true;
pieLegendLabelFormat = StandardPieSectionLabelGenerator.DEFAULT_SECTION_LABEL_FORMAT;
pieLabelFormat = "{2}";
ignoreZeros = true;
ignoreNulls = true;
circular = true;
setItemsLabelVisible( Boolean.TRUE );
}
public Color getShadowPaint() {
return shadowPaint;
}
public void setShadowPaint( final Color shadowPaint ) {
this.shadowPaint = shadowPaint;
}
public Double getShadowXOffset() {
return shadowXOffset;
}
public void setShadowXOffset( final Double shadowXOffset ) {
this.shadowXOffset = shadowXOffset;
}
public Double getShadowYOffset() {
return shadowYOffset;
}
public void setShadowYOffset( final Double shadowYOffset ) {
this.shadowYOffset = shadowYOffset;
}
public boolean isRotationClockwise() {
return rotationClockwise;
}
public void setRotationClockwise( final boolean value ) {
rotationClockwise = value;
}
public boolean isIgnoreNulls() {
return ignoreNulls;
}
public void setIgnoreNulls( final boolean value ) {
ignoreNulls = value;
}
public boolean isIgnoreZeros() {
return ignoreZeros;
}
public void setIgnoreZeros( final boolean value ) {
ignoreZeros = value;
}
public String getExplodeSegment() {
return explodeSegment;
}
public void setExplodeSegment( final String value ) {
explodeSegment = value;
}
public Double getExplodePct() {
return explodePct;
}
public void setExplodePct( final Double value ) {
explodePct = value;
}
public String getPieLabelFormat() {
return pieLabelFormat;
}
public void setPieLabelFormat( final String value ) {
pieLabelFormat = value;
}
public String getPieLegendLabelFormat() {
return pieLegendLabelFormat;
}
public void setPieLegendLabelFormat( final String value ) {
pieLegendLabelFormat = value;
}
public boolean getIsCircular() {
return circular;
}
public void setCircular( final boolean value ) {
circular = value;
}
protected JFreeChart computeChart( final Dataset dataset ) {
PieDataset pieDataset = null;
if ( dataset instanceof PieDataset ) {
pieDataset = (PieDataset) dataset;
}
if ( isThreeD() ) {
return ChartFactory.createPieChart3D( computeTitle(), pieDataset, isShowLegend(), false, false );
} else {
return ChartFactory.createPieChart( computeTitle(), pieDataset, isShowLegend(), false, false );
}
}
protected void configureExplode( final PiePlot pp ) {
final PieDataset pieDS = pp.getDataset();
final int explodeType = computeExplodeType();
if ( explodeType == EXPLODE_VALUE ) {
try {
final int actualSegment = Integer.parseInt( explodeSegment );
if ( actualSegment >= 0 ) {
pp.setExplodePercent( pieDS.getKey( actualSegment ), explodePct.doubleValue() );
}
} catch ( Exception ignored ) {
}
return;
}
// Calculate min and max...
if ( pieDS != null ) {
final int itemCount = pieDS.getItemCount();
Number maxNum = new Double( Integer.MIN_VALUE );
Number minNum = new Double( Integer.MAX_VALUE );
int maxSegment = -1;
int minSegment = -1;
for ( int i = 0; i < itemCount; i++ ) {
final Number nbr = pieDS.getValue( i );
if ( nbr.doubleValue() > maxNum.doubleValue() ) {
maxNum = nbr;
maxSegment = i;
}
if ( nbr.doubleValue() < minNum.doubleValue() ) {
minNum = nbr;
minSegment = i;
}
}
if ( explodeType == EXPLODE_MIN ) { //$NON-NLS-1$
if ( minSegment >= 0 ) {
pp.setExplodePercent( pieDS.getKey( minSegment ), explodePct.doubleValue() );
}
} else {
if ( maxSegment >= 0 ) {
pp.setExplodePercent( pieDS.getKey( maxSegment ), explodePct.doubleValue() );
}
}
}
}
private int computeExplodeType() {
if ( "minValue".equals( explodeSegment ) ) {
return EXPLODE_MIN;
} else if ( "maxValue".equals( explodeSegment ) ) {
return EXPLODE_MAX;
}
return EXPLODE_VALUE;
}
protected void configureChart( final JFreeChart chart ) {
super.configureChart( chart );
final Plot plot = chart.getPlot();
final PiePlot pp = (PiePlot) plot;
final PieDataset pieDS = pp.getDataset();
pp.setDirection( rotationClockwise ? Rotation.CLOCKWISE : Rotation.ANTICLOCKWISE );
if ( ( explodeSegment != null ) && ( explodePct != null ) ) {
configureExplode( pp );
}
if ( StringUtils.isEmpty( getTooltipFormula() ) == false ) {
pp.setToolTipGenerator( new FormulaPieTooltipGenerator( getRuntime(), getTooltipFormula() ) );
}
if ( StringUtils.isEmpty( getUrlFormula() ) == false ) {
pp.setURLGenerator( new FormulaPieURLGenerator( getRuntime(), getUrlFormula() ) );
}
pp.setIgnoreNullValues( ignoreNulls );
pp.setIgnoreZeroValues( ignoreZeros );
if ( Boolean.FALSE.equals( getItemsLabelVisible() ) ) {
pp.setLabelGenerator( null );
} else {
final ExpressionRuntime runtime = getRuntime();
final Locale locale = runtime.getResourceBundleFactory().getLocale();
final FastDecimalFormat fastPercent = new FastDecimalFormat( FastDecimalFormat.TYPE_PERCENT, locale );
final FastDecimalFormat fastInteger = new FastDecimalFormat( FastDecimalFormat.TYPE_INTEGER, locale );
final DecimalFormat numFormat = new DecimalFormat( fastInteger.getPattern(), new DecimalFormatSymbols( locale ) );
numFormat.setRoundingMode( RoundingMode.HALF_UP );
final DecimalFormat percentFormat =
new DecimalFormat( fastPercent.getPattern(), new DecimalFormatSymbols( locale ) );
percentFormat.setRoundingMode( RoundingMode.HALF_UP );
final StandardPieSectionLabelGenerator labelGen = new StandardPieSectionLabelGenerator( pieLabelFormat,
numFormat, percentFormat );
pp.setLabelGenerator( labelGen );
final StandardPieSectionLabelGenerator legendGen = new StandardPieSectionLabelGenerator( pieLegendLabelFormat,
numFormat, percentFormat );
pp.setLegendLabelGenerator( legendGen );
}
if ( StringUtils.isEmpty( getLabelFont() ) == false ) {
pp.setLabelFont( Font.decode( getLabelFont() ) );
}
if ( pieDS != null ) {
final String[] colors = getSeriesColor();
for ( int i = 0; i < colors.length; i++ ) {
if ( i < pieDS.getItemCount() ) {
pp.setSectionPaint( pieDS.getKey( i ), parseColorFromString( colors[ i ] ) );
} else {
break;
}
}
}
if ( shadowPaint != null ) {
pp.setShadowPaint( shadowPaint );
}
if ( shadowXOffset != null ) {
pp.setShadowXOffset( shadowXOffset.doubleValue() );
}
if ( shadowYOffset != null ) {
pp.setShadowYOffset( shadowYOffset.doubleValue() );
}
pp.setCircular( circular );
if ( isShowBorder() == false || isChartSectionOutline() == false ) {
chart.setBorderVisible( false );
chart.getPlot().setOutlineVisible( false );
}
}
}