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}