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 }