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