001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2006, 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-2006, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * $Id: AbstractPieItemLabelGenerator.java,v 1.5.2.2 2006/05/03 10:46:36 mungady Exp $
036     *
037     * Changes
038     * -------
039     * 09-Nov-2004 : Version 1, draws out code from StandardPieItemLabelGenerator 
040     *               and StandardPieToolTipGenerator (DG);
041     * ------------- JFREECHART 1.0.0 ---------------------------------------------
042     * 03-May-2006 : Fixed bug 1480978, a problem in the clone() method (DG);
043     * 
044     */
045    
046    package org.jfree.chart.labels;
047    
048    import java.io.Serializable;
049    import java.text.MessageFormat;
050    import java.text.NumberFormat;
051    
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            }
097            this.labelFormat = labelFormat;
098            this.numberFormat = numberFormat;
099            this.percentFormat = percentFormat;
100    
101        }
102    
103        /**
104         * Returns the label format string.
105         * 
106         * @return The label format string (never <code>null</code>).
107         */
108        public String getLabelFormat() {
109            return this.labelFormat;
110        }
111        
112        /**
113         * Returns the number formatter.
114         *
115         * @return The formatter (never <code>null</code>).
116         */
117        public NumberFormat getNumberFormat() {
118            return this.numberFormat;
119        }
120    
121        /**
122         * Returns the percent formatter.
123         *
124         * @return The formatter (never <code>null</code>).
125         */
126        public NumberFormat getPercentFormat() {
127            return this.percentFormat;
128        }
129    
130        /**
131         * Creates the array of items that can be passed to the 
132         * {@link MessageFormat} class for creating labels.  The returned array
133         * contains four values:
134         * <ul>
135         * <li>result[0] = the section key converted to a <code>String</code>;</li>
136         * <li>result[1] = the formatted data value;</li>
137         * <li>result[2] = the formatted percentage (of the total);</li>
138         * <li>result[3] = the formatted total value.</li>
139         * </ul>
140         *
141         * @param dataset  the dataset (<code>null</code> not permitted).
142         * @param key  the key (<code>null</code> not permitted).
143         *
144         * @return The items (never <code>null</code>).
145         */
146        protected Object[] createItemArray(PieDataset dataset, Comparable key) {
147            Object[] result = new Object[4];
148            double total = DatasetUtilities.calculatePieDatasetTotal(dataset);
149            result[0] = key.toString();
150            Number value = dataset.getValue(key);
151            if (value != null) {
152                result[1] = this.numberFormat.format(value);  
153            }
154            else {
155                result[1] = "null";
156            }
157            double percent = 0.0;
158            if (value != null) {
159                double v = value.doubleValue();
160                if (v > 0.0) {
161                    percent = v / total; 
162                }
163            }       
164            result[2] = this.percentFormat.format(percent);
165            result[3] = this.numberFormat.format(total);
166            return result;
167        }
168        
169        /**
170         * Generates a label for a pie section.
171         * 
172         * @param dataset  the dataset (<code>null</code> not permitted).
173         * @param key  the section key (<code>null</code> not permitted).
174         * 
175         * @return The label (possibly <code>null</code>).
176         */
177        protected String generateSectionLabel(PieDataset dataset, Comparable key) {
178            String result = null;    
179            if (dataset != null) {
180                Object[] items = createItemArray(dataset, key);
181                result = MessageFormat.format(this.labelFormat, items);
182            }
183            return result;
184        }
185    
186        /**
187         * Tests the generator for equality with an arbitrary object.
188         *
189         * @param obj  the object to test against (<code>null</code> permitted).
190         *
191         * @return A boolean.
192         */
193        public boolean equals(Object obj) {
194            if (obj == this) {
195                return true;
196            }
197            if (!(obj instanceof AbstractPieItemLabelGenerator)) {
198                return false;
199            }
200            
201            AbstractPieItemLabelGenerator that 
202                = (AbstractPieItemLabelGenerator) obj;
203            if (!this.labelFormat.equals(that.labelFormat)) {
204                return false;
205            }
206            if (!this.numberFormat.equals(that.numberFormat)) {
207                return false;   
208            }
209            if (!this.percentFormat.equals(that.percentFormat)) {
210                return false;   
211            }
212            return true;
213    
214        }
215        
216        /**
217         * Returns an independent copy of the generator.
218         * 
219         * @return A clone.
220         * 
221         * @throws CloneNotSupportedException  should not happen.
222         */
223        public Object clone() throws CloneNotSupportedException {      
224            AbstractPieItemLabelGenerator clone 
225                = (AbstractPieItemLabelGenerator) super.clone();
226            if (this.numberFormat != null) {
227                clone.numberFormat = (NumberFormat) this.numberFormat.clone();
228            }
229            if (this.percentFormat != null) {
230                clone.percentFormat = (NumberFormat) this.percentFormat.clone();
231            }
232            return clone;
233        }
234    
235    }