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 * DefaultCategoryDataset.java
029 * ---------------------------
030 * (C) Copyright 2002-2008, 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
049 package org.jfree.data.category;
050
051 import java.io.Serializable;
052 import java.util.List;
053
054 import org.jfree.data.DefaultKeyedValues2D;
055 import org.jfree.data.UnknownKeyException;
056 import org.jfree.data.general.AbstractDataset;
057 import org.jfree.data.general.DatasetChangeEvent;
058 import org.jfree.util.PublicCloneable;
059
060 /**
061 * A default implementation of the {@link CategoryDataset} interface.
062 */
063 public 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 public int getRowCount() {
087 return this.data.getRowCount();
088 }
089
090 /**
091 * Returns the number of columns in the table.
092 *
093 * @return The column count.
094 *
095 * @see #getRowCount()
096 */
097 public int getColumnCount() {
098 return this.data.getColumnCount();
099 }
100
101 /**
102 * Returns a value from the table.
103 *
104 * @param row the row index (zero-based).
105 * @param column the column index (zero-based).
106 *
107 * @return The value (possibly <code>null</code>).
108 *
109 * @see #addValue(Number, Comparable, Comparable)
110 * @see #removeValue(Comparable, Comparable)
111 */
112 public Number getValue(int row, int column) {
113 return this.data.getValue(row, column);
114 }
115
116 /**
117 * Returns the key for the specified row.
118 *
119 * @param row the row index (zero-based).
120 *
121 * @return The row key.
122 *
123 * @see #getRowIndex(Comparable)
124 * @see #getRowKeys()
125 * @see #getColumnKey(int)
126 */
127 public Comparable getRowKey(int row) {
128 return this.data.getRowKey(row);
129 }
130
131 /**
132 * Returns the row index for a given key.
133 *
134 * @param key the row key (<code>null</code> not permitted).
135 *
136 * @return The row index.
137 *
138 * @see #getRowKey(int)
139 */
140 public int getRowIndex(Comparable key) {
141 // defer null argument check
142 return this.data.getRowIndex(key);
143 }
144
145 /**
146 * Returns the row keys.
147 *
148 * @return The keys.
149 *
150 * @see #getRowKey(int)
151 */
152 public List getRowKeys() {
153 return this.data.getRowKeys();
154 }
155
156 /**
157 * Returns a column key.
158 *
159 * @param column the column index (zero-based).
160 *
161 * @return The column key.
162 *
163 * @see #getColumnIndex(Comparable)
164 */
165 public Comparable getColumnKey(int column) {
166 return this.data.getColumnKey(column);
167 }
168
169 /**
170 * Returns the column index for a given key.
171 *
172 * @param key the column key (<code>null</code> not permitted).
173 *
174 * @return The column index.
175 *
176 * @see #getColumnKey(int)
177 */
178 public int getColumnIndex(Comparable key) {
179 // defer null argument check
180 return this.data.getColumnIndex(key);
181 }
182
183 /**
184 * Returns the column keys.
185 *
186 * @return The keys.
187 *
188 * @see #getColumnKey(int)
189 */
190 public List getColumnKeys() {
191 return this.data.getColumnKeys();
192 }
193
194 /**
195 * Returns the value for a pair of keys.
196 *
197 * @param rowKey the row key (<code>null</code> not permitted).
198 * @param columnKey the column key (<code>null</code> not permitted).
199 *
200 * @return The value (possibly <code>null</code>).
201 *
202 * @throws UnknownKeyException if either key is not defined in the dataset.
203 *
204 * @see #addValue(Number, Comparable, Comparable)
205 */
206 public Number getValue(Comparable rowKey, Comparable columnKey) {
207 return this.data.getValue(rowKey, columnKey);
208 }
209
210 /**
211 * Adds a value to the table. Performs the same function as setValue().
212 *
213 * @param value the value.
214 * @param rowKey the row key.
215 * @param columnKey the column key.
216 *
217 * @see #getValue(Comparable, Comparable)
218 * @see #removeValue(Comparable, Comparable)
219 */
220 public void addValue(Number value, Comparable rowKey,
221 Comparable columnKey) {
222 this.data.addValue(value, rowKey, columnKey);
223 fireDatasetChanged();
224 }
225
226 /**
227 * Adds a value to the table.
228 *
229 * @param value the value.
230 * @param rowKey the row key.
231 * @param columnKey the column key.
232 *
233 * @see #getValue(Comparable, Comparable)
234 */
235 public void addValue(double value, Comparable rowKey,
236 Comparable columnKey) {
237 addValue(new Double(value), rowKey, columnKey);
238 }
239
240 /**
241 * Adds or updates a value in the table and sends a
242 * {@link DatasetChangeEvent} to all registered listeners.
243 *
244 * @param value the value (<code>null</code> permitted).
245 * @param rowKey the row key (<code>null</code> not permitted).
246 * @param columnKey the column key (<code>null</code> not permitted).
247 *
248 * @see #getValue(Comparable, Comparable)
249 */
250 public void setValue(Number value, Comparable rowKey,
251 Comparable columnKey) {
252 this.data.setValue(value, rowKey, columnKey);
253 fireDatasetChanged();
254 }
255
256 /**
257 * Adds or updates a value in the table and sends a
258 * {@link DatasetChangeEvent} to all registered listeners.
259 *
260 * @param value the value.
261 * @param rowKey the row key (<code>null</code> not permitted).
262 * @param columnKey the column key (<code>null</code> not permitted).
263 *
264 * @see #getValue(Comparable, Comparable)
265 */
266 public void setValue(double value, Comparable rowKey,
267 Comparable columnKey) {
268 setValue(new Double(value), rowKey, columnKey);
269 }
270
271 /**
272 * Adds the specified value to an existing value in the dataset (if the
273 * existing value is <code>null</code>, it is treated as if it were 0.0).
274 *
275 * @param value the value.
276 * @param rowKey the row key (<code>null</code> not permitted).
277 * @param columnKey the column key (<code>null</code> not permitted).
278 *
279 * @throws UnknownKeyException if either key is not defined in the dataset.
280 */
281 public void incrementValue(double value,
282 Comparable rowKey,
283 Comparable columnKey) {
284 double existing = 0.0;
285 Number n = getValue(rowKey, columnKey);
286 if (n != null) {
287 existing = n.doubleValue();
288 }
289 setValue(existing + value, rowKey, columnKey);
290 }
291
292 /**
293 * Removes a value from the dataset and sends a {@link DatasetChangeEvent}
294 * to all registered listeners.
295 *
296 * @param rowKey the row key.
297 * @param columnKey the column key.
298 *
299 * @see #addValue(Number, Comparable, Comparable)
300 */
301 public void removeValue(Comparable rowKey, Comparable columnKey) {
302 this.data.removeValue(rowKey, columnKey);
303 fireDatasetChanged();
304 }
305
306 /**
307 * Removes a row from the dataset and sends a {@link DatasetChangeEvent}
308 * to all registered listeners.
309 *
310 * @param rowIndex the row index.
311 *
312 * @see #removeColumn(int)
313 */
314 public void removeRow(int rowIndex) {
315 this.data.removeRow(rowIndex);
316 fireDatasetChanged();
317 }
318
319 /**
320 * Removes a row from the dataset and sends a {@link DatasetChangeEvent}
321 * to all registered listeners.
322 *
323 * @param rowKey the row key.
324 *
325 * @see #removeColumn(Comparable)
326 */
327 public void removeRow(Comparable rowKey) {
328 this.data.removeRow(rowKey);
329 fireDatasetChanged();
330 }
331
332 /**
333 * Removes a column from the dataset and sends a {@link DatasetChangeEvent}
334 * to all registered listeners.
335 *
336 * @param columnIndex the column index.
337 *
338 * @see #removeRow(int)
339 */
340 public void removeColumn(int columnIndex) {
341 this.data.removeColumn(columnIndex);
342 fireDatasetChanged();
343 }
344
345 /**
346 * Removes a column from the dataset and sends a {@link DatasetChangeEvent}
347 * to all registered listeners.
348 *
349 * @param columnKey the column key (<code>null</code> not permitted).
350 *
351 * @see #removeRow(Comparable)
352 *
353 * @throws UnknownKeyException if <code>columnKey</code> is not defined
354 * in the dataset.
355 */
356 public void removeColumn(Comparable columnKey) {
357 this.data.removeColumn(columnKey);
358 fireDatasetChanged();
359 }
360
361 /**
362 * Clears all data from the dataset and sends a {@link DatasetChangeEvent}
363 * to all registered listeners.
364 */
365 public void clear() {
366 this.data.clear();
367 fireDatasetChanged();
368 }
369
370 /**
371 * Tests this dataset for equality with an arbitrary object.
372 *
373 * @param obj the object (<code>null</code> permitted).
374 *
375 * @return A boolean.
376 */
377 public boolean equals(Object obj) {
378 if (obj == this) {
379 return true;
380 }
381 if (!(obj instanceof CategoryDataset)) {
382 return false;
383 }
384 CategoryDataset that = (CategoryDataset) obj;
385 if (!getRowKeys().equals(that.getRowKeys())) {
386 return false;
387 }
388 if (!getColumnKeys().equals(that.getColumnKeys())) {
389 return false;
390 }
391 int rowCount = getRowCount();
392 int colCount = getColumnCount();
393 for (int r = 0; r < rowCount; r++) {
394 for (int c = 0; c < colCount; c++) {
395 Number v1 = getValue(r, c);
396 Number v2 = that.getValue(r, c);
397 if (v1 == null) {
398 if (v2 != null) {
399 return false;
400 }
401 }
402 else if (!v1.equals(v2)) {
403 return false;
404 }
405 }
406 }
407 return true;
408 }
409
410 /**
411 * Returns a hash code for the dataset.
412 *
413 * @return A hash code.
414 */
415 public int hashCode() {
416 return this.data.hashCode();
417 }
418
419 /**
420 * Returns a clone of the dataset.
421 *
422 * @return A clone.
423 *
424 * @throws CloneNotSupportedException if there is a problem cloning the
425 * dataset.
426 */
427 public Object clone() throws CloneNotSupportedException {
428 DefaultCategoryDataset clone = (DefaultCategoryDataset) super.clone();
429 clone.data = (DefaultKeyedValues2D) this.data.clone();
430 return clone;
431 }
432
433 }