001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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     * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025     * in the United States and other countries.]
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    }