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    }