001/* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2020, 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 * DefaultCategoryDataset.java 029 * --------------------------- 030 * (C) Copyright 2002-2016, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * Changes 036 * ------- 037 * 21-Jan-2003 : Added standard header, and renamed DefaultCategoryDataset (DG); 038 * 13-Mar-2003 : Inserted DefaultKeyedValues2DDataset into class hierarchy (DG); 039 * 06-Oct-2003 : Added incrementValue() method (DG); 040 * 05-Apr-2004 : Added clear() method (DG); 041 * 18-Aug-2004 : Moved from org.jfree.data --> org.jfree.data.category (DG); 042 * ------------- JFREECHART 1.0.x --------------------------------------------- 043 * 26-Feb-2007 : Updated API docs (DG); 044 * 08-Mar-2007 : Implemented clone() (DG); 045 * 09-May-2008 : Implemented PublicCloneable (DG); 046 * 047 */ 048 049package org.jfree.data.category; 050 051import java.io.Serializable; 052import java.util.List; 053import org.jfree.chart.util.PublicCloneable; 054 055import org.jfree.data.DefaultKeyedValues2D; 056import org.jfree.data.UnknownKeyException; 057import org.jfree.data.general.AbstractDataset; 058import org.jfree.data.general.DatasetChangeEvent; 059 060/** 061 * A default implementation of the {@link CategoryDataset} interface. 062 */ 063public class DefaultCategoryDataset extends AbstractDataset 064 implements CategoryDataset, PublicCloneable, Serializable { 065 066 /** For serialization. */ 067 private static final long serialVersionUID = -8168173757291644622L; 068 069 /** A storage structure for the data. */ 070 private DefaultKeyedValues2D data; 071 072 /** 073 * Creates a new (empty) dataset. 074 */ 075 public DefaultCategoryDataset() { 076 this.data = new DefaultKeyedValues2D(); 077 } 078 079 /** 080 * Returns the number of rows in the table. 081 * 082 * @return The row count. 083 * 084 * @see #getColumnCount() 085 */ 086 @Override 087 public int getRowCount() { 088 return this.data.getRowCount(); 089 } 090 091 /** 092 * Returns the number of columns in the table. 093 * 094 * @return The column count. 095 * 096 * @see #getRowCount() 097 */ 098 @Override 099 public int getColumnCount() { 100 return this.data.getColumnCount(); 101 } 102 103 /** 104 * Returns a value from the table. 105 * 106 * @param row the row index (zero-based). 107 * @param column the column index (zero-based). 108 * 109 * @return The value (possibly {@code null}). 110 * 111 * @see #addValue(Number, Comparable, Comparable) 112 * @see #removeValue(Comparable, Comparable) 113 */ 114 @Override 115 public Number getValue(int row, int column) { 116 return this.data.getValue(row, column); 117 } 118 119 /** 120 * Returns the key for the specified row. 121 * 122 * @param row the row index (zero-based). 123 * 124 * @return The row key. 125 * 126 * @see #getRowIndex(Comparable) 127 * @see #getRowKeys() 128 * @see #getColumnKey(int) 129 */ 130 @Override 131 public Comparable getRowKey(int row) { 132 return this.data.getRowKey(row); 133 } 134 135 /** 136 * Returns the row index for a given key. 137 * 138 * @param key the row key ({@code null} not permitted). 139 * 140 * @return The row index. 141 * 142 * @see #getRowKey(int) 143 */ 144 @Override 145 public int getRowIndex(Comparable key) { 146 // defer null argument check 147 return this.data.getRowIndex(key); 148 } 149 150 /** 151 * Returns the row keys. 152 * 153 * @return The keys. 154 * 155 * @see #getRowKey(int) 156 */ 157 @Override 158 public List getRowKeys() { 159 return this.data.getRowKeys(); 160 } 161 162 /** 163 * Returns a column key. 164 * 165 * @param column the column index (zero-based). 166 * 167 * @return The column key. 168 * 169 * @see #getColumnIndex(Comparable) 170 */ 171 @Override 172 public Comparable getColumnKey(int column) { 173 return this.data.getColumnKey(column); 174 } 175 176 /** 177 * Returns the column index for a given key. 178 * 179 * @param key the column key ({@code null} not permitted). 180 * 181 * @return The column index. 182 * 183 * @see #getColumnKey(int) 184 */ 185 @Override 186 public int getColumnIndex(Comparable key) { 187 // defer null argument check 188 return this.data.getColumnIndex(key); 189 } 190 191 /** 192 * Returns the column keys. 193 * 194 * @return The keys. 195 * 196 * @see #getColumnKey(int) 197 */ 198 @Override 199 public List getColumnKeys() { 200 return this.data.getColumnKeys(); 201 } 202 203 /** 204 * Returns the value for a pair of keys. 205 * 206 * @param rowKey the row key ({@code null} not permitted). 207 * @param columnKey the column key ({@code null} not permitted). 208 * 209 * @return The value (possibly {@code null}). 210 * 211 * @throws UnknownKeyException if either key is not defined in the dataset. 212 * 213 * @see #addValue(Number, Comparable, Comparable) 214 */ 215 @Override 216 public Number getValue(Comparable rowKey, Comparable columnKey) { 217 return this.data.getValue(rowKey, columnKey); 218 } 219 220 /** 221 * Adds a value to the table. Performs the same function as setValue(). 222 * 223 * @param value the value. 224 * @param rowKey the row key. 225 * @param columnKey the column key. 226 * 227 * @see #getValue(Comparable, Comparable) 228 * @see #removeValue(Comparable, Comparable) 229 */ 230 public void addValue(Number value, Comparable rowKey, 231 Comparable columnKey) { 232 this.data.addValue(value, rowKey, columnKey); 233 fireDatasetChanged(); 234 } 235 236 /** 237 * Adds a value to the table. 238 * 239 * @param value the value. 240 * @param rowKey the row key. 241 * @param columnKey the column key. 242 * 243 * @see #getValue(Comparable, Comparable) 244 */ 245 public void addValue(double value, Comparable rowKey, 246 Comparable columnKey) { 247 addValue(Double.valueOf(value), rowKey, columnKey); 248 } 249 250 /** 251 * Adds or updates a value in the table and sends a 252 * {@link DatasetChangeEvent} to all registered listeners. 253 * 254 * @param value the value ({@code null} permitted). 255 * @param rowKey the row key ({@code null} not permitted). 256 * @param columnKey the column key ({@code null} not permitted). 257 * 258 * @see #getValue(Comparable, Comparable) 259 */ 260 public void setValue(Number value, Comparable rowKey, 261 Comparable columnKey) { 262 this.data.setValue(value, rowKey, columnKey); 263 fireDatasetChanged(); 264 } 265 266 /** 267 * Adds or updates a value in the table and sends a 268 * {@link DatasetChangeEvent} to all registered listeners. 269 * 270 * @param value the value. 271 * @param rowKey the row key ({@code null} not permitted). 272 * @param columnKey the column key ({@code null} not permitted). 273 * 274 * @see #getValue(Comparable, Comparable) 275 */ 276 public void setValue(double value, Comparable rowKey, 277 Comparable columnKey) { 278 setValue(Double.valueOf(value), rowKey, columnKey); 279 } 280 281 /** 282 * Adds the specified value to an existing value in the dataset (if the 283 * existing value is {@code null}, it is treated as if it were 0.0). 284 * 285 * @param value the value. 286 * @param rowKey the row key ({@code null} not permitted). 287 * @param columnKey the column key ({@code null} not permitted). 288 * 289 * @throws UnknownKeyException if either key is not defined in the dataset. 290 */ 291 public void incrementValue(double value, 292 Comparable rowKey, 293 Comparable columnKey) { 294 double existing = 0.0; 295 Number n = getValue(rowKey, columnKey); 296 if (n != null) { 297 existing = n.doubleValue(); 298 } 299 setValue(existing + value, rowKey, columnKey); 300 } 301 302 /** 303 * Removes a value from the dataset and sends a {@link DatasetChangeEvent} 304 * to all registered listeners. 305 * 306 * @param rowKey the row key. 307 * @param columnKey the column key. 308 * 309 * @see #addValue(Number, Comparable, Comparable) 310 */ 311 public void removeValue(Comparable rowKey, Comparable columnKey) { 312 this.data.removeValue(rowKey, columnKey); 313 fireDatasetChanged(); 314 } 315 316 /** 317 * Removes a row from the dataset and sends a {@link DatasetChangeEvent} 318 * to all registered listeners. 319 * 320 * @param rowIndex the row index. 321 * 322 * @see #removeColumn(int) 323 */ 324 public void removeRow(int rowIndex) { 325 this.data.removeRow(rowIndex); 326 fireDatasetChanged(); 327 } 328 329 /** 330 * Removes a row from the dataset and sends a {@link DatasetChangeEvent} 331 * to all registered listeners. 332 * 333 * @param rowKey the row key. 334 * 335 * @see #removeColumn(Comparable) 336 */ 337 public void removeRow(Comparable rowKey) { 338 this.data.removeRow(rowKey); 339 fireDatasetChanged(); 340 } 341 342 /** 343 * Removes a column from the dataset and sends a {@link DatasetChangeEvent} 344 * to all registered listeners. 345 * 346 * @param columnIndex the column index. 347 * 348 * @see #removeRow(int) 349 */ 350 public void removeColumn(int columnIndex) { 351 this.data.removeColumn(columnIndex); 352 fireDatasetChanged(); 353 } 354 355 /** 356 * Removes a column from the dataset and sends a {@link DatasetChangeEvent} 357 * to all registered listeners. 358 * 359 * @param columnKey the column key ({@code null} not permitted). 360 * 361 * @see #removeRow(Comparable) 362 * 363 * @throws UnknownKeyException if {@code columnKey} is not defined 364 * in the dataset. 365 */ 366 public void removeColumn(Comparable columnKey) { 367 this.data.removeColumn(columnKey); 368 fireDatasetChanged(); 369 } 370 371 /** 372 * Clears all data from the dataset and sends a {@link DatasetChangeEvent} 373 * to all registered listeners. 374 */ 375 public void clear() { 376 this.data.clear(); 377 fireDatasetChanged(); 378 } 379 380 /** 381 * Tests this dataset for equality with an arbitrary object. 382 * 383 * @param obj the object ({@code null} permitted). 384 * 385 * @return A boolean. 386 */ 387 @Override 388 public boolean equals(Object obj) { 389 if (obj == this) { 390 return true; 391 } 392 if (!(obj instanceof CategoryDataset)) { 393 return false; 394 } 395 CategoryDataset that = (CategoryDataset) obj; 396 if (!getRowKeys().equals(that.getRowKeys())) { 397 return false; 398 } 399 if (!getColumnKeys().equals(that.getColumnKeys())) { 400 return false; 401 } 402 int rowCount = getRowCount(); 403 int colCount = getColumnCount(); 404 for (int r = 0; r < rowCount; r++) { 405 for (int c = 0; c < colCount; c++) { 406 Number v1 = getValue(r, c); 407 Number v2 = that.getValue(r, c); 408 if (v1 == null) { 409 if (v2 != null) { 410 return false; 411 } 412 } 413 else if (!v1.equals(v2)) { 414 return false; 415 } 416 } 417 } 418 return true; 419 } 420 421 /** 422 * Returns a hash code for the dataset. 423 * 424 * @return A hash code. 425 */ 426 @Override 427 public int hashCode() { 428 return this.data.hashCode(); 429 } 430 431 /** 432 * Returns a clone of the dataset. 433 * 434 * @return A clone. 435 * 436 * @throws CloneNotSupportedException if there is a problem cloning the 437 * dataset. 438 */ 439 @Override 440 public Object clone() throws CloneNotSupportedException { 441 DefaultCategoryDataset clone = (DefaultCategoryDataset) super.clone(); 442 clone.data = (DefaultKeyedValues2D) this.data.clone(); 443 return clone; 444 } 445 446}