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 * AbstractCategoryItemLabelGenerator.java
029 * ---------------------------------------
030 * (C) Copyright 2005-2007, by Object Refinery Limited.
031 *
032 * Original Author: David Gilbert (for Object Refinery Limited);
033 * Contributor(s): -;
034 *
035 * Changes
036 * -------
037 * 11-May-2004 : Version 1, distilled from StandardCategoryLabelGenerator (DG);
038 * 31-Jan-2005 : Added methods to return row and column labels (DG);
039 * 17-May-2005 : Added percentage to item array (DG);
040 * ------------- JFREECHART 1.0.x ---------------------------------------------
041 * 03-May-2006 : Added new constructor (DG);
042 * 23-Nov-2007 : Implemented hashCode() (DG);
043 *
044 */
045
046 package org.jfree.chart.labels;
047
048 import java.io.Serializable;
049 import java.text.DateFormat;
050 import java.text.MessageFormat;
051 import java.text.NumberFormat;
052
053 import org.jfree.chart.HashUtilities;
054 import org.jfree.data.DataUtilities;
055 import org.jfree.data.category.CategoryDataset;
056 import org.jfree.util.ObjectUtilities;
057 import org.jfree.util.PublicCloneable;
058
059 /**
060 * A base class that can be used to create a label or tooltip generator that
061 * can be assigned to a
062 * {@link org.jfree.chart.renderer.category.CategoryItemRenderer}.
063 */
064 public abstract class AbstractCategoryItemLabelGenerator
065 implements PublicCloneable, Cloneable, Serializable {
066
067 /** For serialization. */
068 private static final long serialVersionUID = -7108591260223293197L;
069
070 /**
071 * The label format string used by a <code>MessageFormat</code> object to
072 * combine the standard items: {0} = series name, {1} = category,
073 * {2} = value, {3} = value as a percentage of the column total.
074 */
075 private String labelFormat;
076
077 /** The string used to represent a null value. */
078 private String nullValueString;
079
080 /**
081 * A number formatter used to preformat the value before it is passed to
082 * the MessageFormat object.
083 */
084 private NumberFormat numberFormat;
085
086 /**
087 * A date formatter used to preformat the value before it is passed to the
088 * MessageFormat object.
089 */
090 private DateFormat dateFormat;
091
092 /**
093 * A number formatter used to preformat the percentage value before it is
094 * passed to the MessageFormat object.
095 */
096 private NumberFormat percentFormat;
097
098 /**
099 * Creates a label generator with the specified number formatter.
100 *
101 * @param labelFormat the label format string (<code>null</code> not
102 * permitted).
103 * @param formatter the number formatter (<code>null</code> not permitted).
104 */
105 protected AbstractCategoryItemLabelGenerator(String labelFormat,
106 NumberFormat formatter) {
107 this(labelFormat, formatter, NumberFormat.getPercentInstance());
108 }
109
110 /**
111 * Creates a label generator with the specified number formatter.
112 *
113 * @param labelFormat the label format string (<code>null</code> not
114 * permitted).
115 * @param formatter the number formatter (<code>null</code> not permitted).
116 * @param percentFormatter the percent formatter (<code>null</code> not
117 * permitted).
118 *
119 * @since 1.0.2
120 */
121 protected AbstractCategoryItemLabelGenerator(String labelFormat,
122 NumberFormat formatter, NumberFormat percentFormatter) {
123 if (labelFormat == null) {
124 throw new IllegalArgumentException("Null 'labelFormat' argument.");
125 }
126 if (formatter == null) {
127 throw new IllegalArgumentException("Null 'formatter' argument.");
128 }
129 if (percentFormatter == null) {
130 throw new IllegalArgumentException(
131 "Null 'percentFormatter' argument.");
132 }
133 this.labelFormat = labelFormat;
134 this.numberFormat = formatter;
135 this.percentFormat = percentFormatter;
136 this.dateFormat = null;
137 this.nullValueString = "-";
138 }
139
140 /**
141 * Creates a label generator with the specified date formatter.
142 *
143 * @param labelFormat the label format string (<code>null</code> not
144 * permitted).
145 * @param formatter the date formatter (<code>null</code> not permitted).
146 */
147 protected AbstractCategoryItemLabelGenerator(String labelFormat,
148 DateFormat formatter) {
149 if (labelFormat == null) {
150 throw new IllegalArgumentException("Null 'labelFormat' argument.");
151 }
152 if (formatter == null) {
153 throw new IllegalArgumentException("Null 'formatter' argument.");
154 }
155 this.labelFormat = labelFormat;
156 this.numberFormat = null;
157 this.percentFormat = NumberFormat.getPercentInstance();
158 this.dateFormat = formatter;
159 this.nullValueString = "-";
160 }
161
162 /**
163 * Generates a label for the specified row.
164 *
165 * @param dataset the dataset (<code>null</code> not permitted).
166 * @param row the row index (zero-based).
167 *
168 * @return The label.
169 */
170 public String generateRowLabel(CategoryDataset dataset, int row) {
171 return dataset.getRowKey(row).toString();
172 }
173
174 /**
175 * Generates a label for the specified row.
176 *
177 * @param dataset the dataset (<code>null</code> not permitted).
178 * @param column the column index (zero-based).
179 *
180 * @return The label.
181 */
182 public String generateColumnLabel(CategoryDataset dataset, int column) {
183 return dataset.getColumnKey(column).toString();
184 }
185
186 /**
187 * Returns the label format string.
188 *
189 * @return The label format string (never <code>null</code>).
190 */
191 public String getLabelFormat() {
192 return this.labelFormat;
193 }
194
195 /**
196 * Returns the number formatter.
197 *
198 * @return The number formatter (possibly <code>null</code>).
199 */
200 public NumberFormat getNumberFormat() {
201 return this.numberFormat;
202 }
203
204 /**
205 * Returns the date formatter.
206 *
207 * @return The date formatter (possibly <code>null</code>).
208 */
209 public DateFormat getDateFormat() {
210 return this.dateFormat;
211 }
212
213 /**
214 * Generates a for the specified item.
215 *
216 * @param dataset the dataset (<code>null</code> not permitted).
217 * @param row the row index (zero-based).
218 * @param column the column index (zero-based).
219 *
220 * @return The label (possibly <code>null</code>).
221 */
222 protected String generateLabelString(CategoryDataset dataset,
223 int row, int column) {
224 if (dataset == null) {
225 throw new IllegalArgumentException("Null 'dataset' argument.");
226 }
227 String result = null;
228 Object[] items = createItemArray(dataset, row, column);
229 result = MessageFormat.format(this.labelFormat, items);
230 return result;
231
232 }
233
234 /**
235 * Creates the array of items that can be passed to the
236 * {@link MessageFormat} class for creating labels.
237 *
238 * @param dataset the dataset (<code>null</code> not permitted).
239 * @param row the row index (zero-based).
240 * @param column the column index (zero-based).
241 *
242 * @return The items (never <code>null</code>).
243 */
244 protected Object[] createItemArray(CategoryDataset dataset,
245 int row, int column) {
246 Object[] result = new Object[4];
247 result[0] = dataset.getRowKey(row).toString();
248 result[1] = dataset.getColumnKey(column).toString();
249 Number value = dataset.getValue(row, column);
250 if (value != null) {
251 if (this.numberFormat != null) {
252 result[2] = this.numberFormat.format(value);
253 }
254 else if (this.dateFormat != null) {
255 result[2] = this.dateFormat.format(value);
256 }
257 }
258 else {
259 result[2] = this.nullValueString;
260 }
261 if (value != null) {
262 double total = DataUtilities.calculateColumnTotal(dataset, column);
263 double percent = value.doubleValue() / total;
264 result[3] = this.percentFormat.format(percent);
265 }
266
267 return result;
268 }
269
270 /**
271 * Tests this object for equality with an arbitrary object.
272 *
273 * @param obj the other object (<code>null</code> permitted).
274 *
275 * @return A boolean.
276 */
277 public boolean equals(Object obj) {
278 if (obj == this) {
279 return true;
280 }
281 if (!(obj instanceof AbstractCategoryItemLabelGenerator)) {
282 return false;
283 }
284
285 AbstractCategoryItemLabelGenerator that
286 = (AbstractCategoryItemLabelGenerator) obj;
287 if (!this.labelFormat.equals(that.labelFormat)) {
288 return false;
289 }
290 if (!ObjectUtilities.equal(this.dateFormat, that.dateFormat)) {
291 return false;
292 }
293 if (!ObjectUtilities.equal(this.numberFormat, that.numberFormat)) {
294 return false;
295 }
296 return true;
297 }
298
299 /**
300 * Returns a hash code for this instance.
301 *
302 * @return A hash code.
303 */
304 public int hashCode() {
305 int result = 127;
306 result = HashUtilities.hashCode(result, this.labelFormat);
307 result = HashUtilities.hashCode(result, this.nullValueString);
308 result = HashUtilities.hashCode(result, this.dateFormat);
309 result = HashUtilities.hashCode(result, this.numberFormat);
310 result = HashUtilities.hashCode(result, this.percentFormat);
311 return result;
312 }
313
314 /**
315 * Returns an independent copy of the generator.
316 *
317 * @return A clone.
318 *
319 * @throws CloneNotSupportedException should not happen.
320 */
321 public Object clone() throws CloneNotSupportedException {
322 AbstractCategoryItemLabelGenerator clone
323 = (AbstractCategoryItemLabelGenerator) super.clone();
324 if (this.numberFormat != null) {
325 clone.numberFormat = (NumberFormat) this.numberFormat.clone();
326 }
327 if (this.dateFormat != null) {
328 clone.dateFormat = (DateFormat) this.dateFormat.clone();
329 }
330 return clone;
331 }
332
333 }