/*! * 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 ); } } }