    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
    045    package org.jfree.chart.labels;
    046
    047    import java.io.Serializable;
    048    import java.text.MessageFormat;
    049    import java.text.NumberFormat;
    050
    051    import org.jfree.chart.HashUtilities;
    052    import org.jfree.data.general.DatasetUtilities;
    053    import org.jfree.data.general.PieDataset;
    054
    055    /**
    056     * A base class used for generating pie chart item labels.
    057     */
    058    public 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    }