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
049package org.jfree.data.category;
050
051import java.io.Serializable;
052import java.util.List;
053
054import org.jfree.data.DefaultKeyedValues2D;
055import org.jfree.data.UnknownKeyException;
056import org.jfree.data.general.AbstractDataset;
057import org.jfree.data.general.DatasetChangeEvent;
058import org.jfree.util.PublicCloneable;
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    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}