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