    001/* ===========================================================
    002 * JFreeChart : a free chart library for the Java(tm) platform
    003 * ===========================================================
    004 *
    005 * (C) Copyright 2000-2011, by Object Refinery Limited and Contributors.
    006 *
    007 * Project Info:  http://www.jfree.org/jfreechart/index.html
    008 *
    009 * This library is free software; you can redistribute it and/or modify it
    010 * under the terms of the GNU Lesser General Public License as published by
    011 * the Free Software Foundation; either version 2.1 of the License, or
    012 * (at your option) any later version.
    013 *
    014 * This library is distributed in the hope that it will be useful, but
    015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    017 * License for more details.
    018 *
    019 * You should have received a copy of the GNU Lesser General Public
    020 * License along with this library; if not, write to the Free Software
    021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
    022 * USA.
    023 *
    024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    025 * Other names may be trademarks of their respective owners.]
    026 *
    027 * ----------------------------------
    028 * AbstractPieItemLabelGenerator.java
    029 * ----------------------------------
    030 * (C) Copyright 2004-2008, by Object Refinery Limited.
    031 *
    032 * Original Author:  David Gilbert (for Object Refinery Limited);
    033 * Contributor(s):   -;
    034 *
    035 * Changes
    036 * -------
    037 * 09-Nov-2004 : Version 1, draws out code from StandardPieItemLabelGenerator
    038 *               and StandardPieToolTipGenerator (DG);
    039 * ------------- JFREECHART 1.0.x ---------------------------------------------
    040 * 03-May-2006 : Fixed bug 1480978, a problem in the clone() method (DG);
    041 * 23-Nov-2007 : Implemented hashCode() (DG);
    042 *
    043 */
    044
    045package org.jfree.chart.labels;
    046
    047import java.io.Serializable;
    048import java.text.MessageFormat;
    049import java.text.NumberFormat;
    050
    051import org.jfree.chart.HashUtilities;
    052import org.jfree.data.general.DatasetUtilities;
    053import org.jfree.data.general.PieDataset;
    054
    055/**
    056 * A base class used for generating pie chart item labels.
    057 */
    058public class AbstractPieItemLabelGenerator implements Serializable {
    059
    060    /** For serialization. */
    061    private static final long serialVersionUID = 7347703325267846275L;
    062
    063    /** The label format string. */
    064    private String labelFormat;
    065
    066    /** A number formatter for the value. */
    067    private NumberFormat numberFormat;
    068
    069    /** A number formatter for the percentage. */
    070    private NumberFormat percentFormat;
    071
    072    /**
    073     * Creates an item label generator using the specified number formatters.
    074     *
    075     * @param labelFormat  the label format string (<code>null</code> not
    076     *                     permitted).
    077     * @param numberFormat  the format object for the values (<code>null</code>
    078     *                      not permitted).
    079     * @param percentFormat  the format object for the percentages
    080     *                       (<code>null</code> not permitted).
    081     */
    082    protected AbstractPieItemLabelGenerator(String labelFormat,
    083                                            NumberFormat numberFormat,
    084                                            NumberFormat percentFormat) {
    085
    086        if (labelFormat == null) {
    087            throw new IllegalArgumentException("Null 'labelFormat' argument.");
    088        }
    089        if (numberFormat == null) {
    090            throw new IllegalArgumentException("Null 'numberFormat' argument.");
    091        }
    092        if (percentFormat == null) {
    093            throw new IllegalArgumentException(
    094                    "Null 'percentFormat' argument.");
    095        }
    096        this.labelFormat = labelFormat;
    097        this.numberFormat = numberFormat;
    098        this.percentFormat = percentFormat;
    099
    100    }
    101
    102    /**
    103     * Returns the label format string.
    104     *
    105     * @return The label format string (never <code>null</code>).
    106     */
    107    public String getLabelFormat() {
    108        return this.labelFormat;
    109    }
    110
    111    /**
    112     * Returns the number formatter.
    113     *
    114     * @return The formatter (never <code>null</code>).
    115     */
    116    public NumberFormat getNumberFormat() {
    117        return this.numberFormat;
    118    }
    119
    120    /**
    121     * Returns the percent formatter.
    122     *
    123     * @return The formatter (never <code>null</code>).
    124     */
    125    public NumberFormat getPercentFormat() {
    126        return this.percentFormat;
    127    }
    128
    129    /**
    130     * Creates the array of items that can be passed to the
    131     * {@link MessageFormat} class for creating labels.  The returned array
    132     * contains four values:
    133     * <ul>
    134     * <li>result[0] = the section key converted to a <code>String</code>;</li>
    135     * <li>result[1] = the formatted data value;</li>
    136     * <li>result[2] = the formatted percentage (of the total);</li>
    137     * <li>result[3] = the formatted total value.</li>
    138     * </ul>
    139     *
    140     * @param dataset  the dataset (<code>null</code> not permitted).
    141     * @param key  the key (<code>null</code> not permitted).
    142     *
    143     * @return The items (never <code>null</code>).
    144     */
    145    protected Object[] createItemArray(PieDataset dataset, Comparable key) {
    146        Object[] result = new Object[4];
    147        double total = DatasetUtilities.calculatePieDatasetTotal(dataset);
    148        result[0] = key.toString();
    149        Number value = dataset.getValue(key);
    150        if (value != null) {
    151            result[1] = this.numberFormat.format(value);
    152        }
    153        else {
    154            result[1] = "null";
    155        }
    156        double percent = 0.0;
    157        if (value != null) {
    158            double v = value.doubleValue();
    159            if (v > 0.0) {
    160                percent = v / total;
    161            }
    162        }
    163        result[2] = this.percentFormat.format(percent);
    164        result[3] = this.numberFormat.format(total);
    165        return result;
    166    }
    167
    168    /**
    169     * Generates a label for a pie section.
    170     *
    171     * @param dataset  the dataset (<code>null</code> not permitted).
    172     * @param key  the section key (<code>null</code> not permitted).
    173     *
    174     * @return The label (possibly <code>null</code>).
    175     */
    176    protected String generateSectionLabel(PieDataset dataset, Comparable key) {
    177        String result = null;
    178        if (dataset != null) {
    179            Object[] items = createItemArray(dataset, key);
    180            result = MessageFormat.format(this.labelFormat, items);
    181        }
    182        return result;
    183    }
    184
    185    /**
    186     * Tests the generator for equality with an arbitrary object.
    187     *
    188     * @param obj  the object to test against (<code>null</code> permitted).
    189     *
    190     * @return A boolean.
    191     */
    192    public boolean equals(Object obj) {
    193        if (obj == this) {
    194            return true;
    195        }
    196        if (!(obj instanceof AbstractPieItemLabelGenerator)) {
    197            return false;
    198        }
    199
    200        AbstractPieItemLabelGenerator that
    201                = (AbstractPieItemLabelGenerator) obj;
    202        if (!this.labelFormat.equals(that.labelFormat)) {
    203            return false;
    204        }
    205        if (!this.numberFormat.equals(that.numberFormat)) {
    206            return false;
    207        }
    208        if (!this.percentFormat.equals(that.percentFormat)) {
    209            return false;
    210        }
    211        return true;
    212
    213    }
    214
    215    /**
    216     * Returns a hash code for this instance.
    217     *
    218     * @return A hash code.
    219     */
    220    public int hashCode() {
    221        int result = 127;
    222        result = HashUtilities.hashCode(result, this.labelFormat);
    223        result = HashUtilities.hashCode(result, this.numberFormat);
    224        result = HashUtilities.hashCode(result, this.percentFormat);
    225        return result;
    226    }
    227
    228    /**
    229     * Returns an independent copy of the generator.
    230     *
    231     * @return A clone.
    232     *
    233     * @throws CloneNotSupportedException  should not happen.
    234     */
    235    public Object clone() throws CloneNotSupportedException {
    236        AbstractPieItemLabelGenerator clone
    237                = (AbstractPieItemLabelGenerator) super.clone();
    238        if (this.numberFormat != null) {
    239            clone.numberFormat = (NumberFormat) this.numberFormat.clone();
    240        }
    241        if (this.percentFormat != null) {
    242            clone.percentFormat = (NumberFormat) this.percentFormat.clone();
    243        }
    244        return clone;
    245    }
    246
    247}