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