001 /* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-2007, 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-2007, 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 }