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     * DefaultIntervalCategoryDataset.java
029     * -----------------------------------
030     * (C) Copyright 2002-2008, by Jeremy Bowman and Contributors.
031     *
032     * Original Author:  Jeremy Bowman;
033     * Contributor(s):   David Gilbert (for Object Refinery Limited);
034     *
035     * Changes
036     * -------
037     * 29-Apr-2002 : Version 1, contributed by Jeremy Bowman (DG);
038     * 24-Oct-2002 : Amendments for changes made to the dataset interface (DG);
039     * ------------- JFREECHART 1.0.x ---------------------------------------------
040     * 08-Mar-2007 : Added equals() and clone() overrides (DG);
041     * 25-Feb-2008 : Fix for the special case where the dataset is empty, see bug 
042     *               1897580 (DG)
043     *
044     */
045    
046    package org.jfree.data.category;
047    
048    import java.util.ArrayList;
049    import java.util.Arrays;
050    import java.util.Collections;
051    import java.util.List;
052    import java.util.ResourceBundle;
053    
054    import org.jfree.data.DataUtilities;
055    import org.jfree.data.UnknownKeyException;
056    import org.jfree.data.general.AbstractSeriesDataset;
057    
058    /**
059     * A convenience class that provides a default implementation of the
060     * {@link IntervalCategoryDataset} interface.
061     * <p>
062     * The standard constructor accepts data in a two dimensional array where the
063     * first dimension is the series, and the second dimension is the category.
064     */
065    public class DefaultIntervalCategoryDataset extends AbstractSeriesDataset
066            implements IntervalCategoryDataset {
067    
068        /** The series keys. */
069        private Comparable[] seriesKeys;
070    
071        /** The category keys. */
072        private Comparable[] categoryKeys;
073    
074        /** Storage for the start value data. */
075        private Number[][] startData;
076    
077        /** Storage for the end value data. */
078        private Number[][] endData;
079    
080        /**
081         * Creates a new dataset using the specified data values and automatically
082         * generated series and category keys.
083         *
084         * @param starts  the starting values for the intervals (<code>null</code>
085         *                not permitted).
086         * @param ends  the ending values for the intervals (<code>null</code> not
087         *                permitted).
088         */
089        public DefaultIntervalCategoryDataset(double[][] starts, double[][] ends) {
090            this(DataUtilities.createNumberArray2D(starts),
091                    DataUtilities.createNumberArray2D(ends));
092        }
093    
094        /**
095         * Constructs a dataset and populates it with data from the array.
096         * <p>
097         * The arrays are indexed as data[series][category].  Series and category
098         * names are automatically generated - you can change them using the
099         * {@link #setSeriesKeys(Comparable[])} and 
100         * {@link #setCategoryKeys(Comparable[])} methods.
101         *
102         * @param starts  the start values data.
103         * @param ends  the end values data.
104         */
105        public DefaultIntervalCategoryDataset(Number[][] starts, Number[][] ends) {
106            this(null, null, starts, ends);
107        }
108    
109        /**
110         * Constructs a DefaultIntervalCategoryDataset, populates it with data
111         * from the arrays, and uses the supplied names for the series.
112         * <p>
113         * Category names are generated automatically ("Category 1", "Category 2",
114         * etc).
115         *
116         * @param seriesNames  the series names (if <code>null</code>, series names
117         *         will be generated automatically).
118         * @param starts  the start values data, indexed as data[series][category].
119         * @param ends  the end values data, indexed as data[series][category].
120         */
121        public DefaultIntervalCategoryDataset(String[] seriesNames,
122                                              Number[][] starts,
123                                              Number[][] ends) {
124    
125            this(seriesNames, null, starts, ends);
126    
127        }
128    
129        /**
130         * Constructs a DefaultIntervalCategoryDataset, populates it with data
131         * from the arrays, and uses the supplied names for the series and the
132         * supplied objects for the categories.
133         *
134         * @param seriesKeys  the series keys (if <code>null</code>, series keys
135         *         will be generated automatically).
136         * @param categoryKeys  the category keys (if <code>null</code>, category 
137         *         keys will be generated automatically).
138         * @param starts  the start values data, indexed as data[series][category].
139         * @param ends  the end values data, indexed as data[series][category].
140         */
141        public DefaultIntervalCategoryDataset(Comparable[] seriesKeys,
142                                              Comparable[] categoryKeys,
143                                              Number[][] starts,
144                                              Number[][] ends) {
145    
146            this.startData = starts;
147            this.endData = ends;
148    
149            if (starts != null && ends != null) {
150    
151                String baseName = "org.jfree.data.resources.DataPackageResources";
152                ResourceBundle resources = ResourceBundle.getBundle(baseName);
153    
154                int seriesCount = starts.length;
155                if (seriesCount != ends.length) {
156                    String errMsg = "DefaultIntervalCategoryDataset: the number "
157                        + "of series in the start value dataset does "
158                        + "not match the number of series in the end "
159                        + "value dataset.";
160                    throw new IllegalArgumentException(errMsg);
161                }
162                if (seriesCount > 0) {
163    
164                    // set up the series names...
165                    if (seriesKeys != null) {
166    
167                        if (seriesKeys.length != seriesCount) {
168                            throw new IllegalArgumentException(
169                                    "The number of series keys does not "
170                                    + "match the number of series in the data.");
171                        }
172    
173                        this.seriesKeys = seriesKeys;
174                    }
175                    else {
176                        String prefix = resources.getString(
177                                "series.default-prefix") + " ";
178                        this.seriesKeys = generateKeys(seriesCount, prefix);
179                    }
180    
181                    // set up the category names...
182                    int categoryCount = starts[0].length;
183                    if (categoryCount != ends[0].length) {
184                        String errMsg = "DefaultIntervalCategoryDataset: the "
185                                    + "number of categories in the start value "
186                                    + "dataset does not match the number of "
187                                    + "categories in the end value dataset.";
188                        throw new IllegalArgumentException(errMsg);
189                    }
190                    if (categoryKeys != null) {
191                        if (categoryKeys.length != categoryCount) {
192                            throw new IllegalArgumentException(
193                                    "The number of category keys does not match "
194                                    + "the number of categories in the data.");
195                        }
196                        this.categoryKeys = categoryKeys;
197                    }
198                    else {
199                        String prefix = resources.getString(
200                                "categories.default-prefix") + " ";
201                        this.categoryKeys = generateKeys(categoryCount, prefix);
202                    }
203    
204                }
205                else {
206                    this.seriesKeys = new Comparable[0];
207                    this.categoryKeys = new Comparable[0];
208                }
209            }
210    
211        }
212    
213        /**
214         * Returns the number of series in the dataset (possibly zero).
215         *
216         * @return The number of series in the dataset.
217         * 
218         * @see #getRowCount()
219         * @see #getCategoryCount()
220         */
221        public int getSeriesCount() {
222            int result = 0;
223            if (this.startData != null) {
224                result = this.startData.length;
225            }
226            return result;
227        }
228    
229        /**
230         * Returns a series index.
231         *
232         * @param seriesKey  the series key.
233         *
234         * @return The series index.
235         * 
236         * @see #getRowIndex(Comparable)
237         * @see #getSeriesKey(int)
238         */
239        public int getSeriesIndex(Comparable seriesKey) {
240            int result = -1;
241            for (int i = 0; i < this.seriesKeys.length; i++) {
242                if (seriesKey.equals(this.seriesKeys[i])) {
243                    result = i;
244                    break;
245                }
246            }
247            return result;
248        }
249    
250        /**
251         * Returns the name of the specified series.
252         *
253         * @param series  the index of the required series (zero-based).
254         *
255         * @return The name of the specified series.
256         * 
257         * @see #getSeriesIndex(Comparable)
258         */
259        public Comparable getSeriesKey(int series) {
260            if ((series >= getSeriesCount()) || (series < 0)) {
261                throw new IllegalArgumentException("No such series : " + series);
262            }
263            return this.seriesKeys[series];
264        }
265    
266        /**
267         * Sets the names of the series in the dataset.
268         *
269         * @param seriesKeys  the new keys (<code>null</code> not permitted, the 
270         *         length of the array must match the number of series in the 
271         *         dataset).
272         *         
273         * @see #setCategoryKeys(Comparable[])
274         */
275        public void setSeriesKeys(Comparable[] seriesKeys) {
276            if (seriesKeys == null) {
277                throw new IllegalArgumentException("Null 'seriesKeys' argument.");
278            }
279            if (seriesKeys.length != getSeriesCount()) {
280                throw new IllegalArgumentException(
281                        "The number of series keys does not match the data.");
282            }
283            this.seriesKeys = seriesKeys;
284            fireDatasetChanged();
285        }
286    
287        /**
288         * Returns the number of categories in the dataset.
289         *
290         * @return The number of categories in the dataset.
291         * 
292         * @see #getColumnCount()
293         */
294        public int getCategoryCount() {
295            int result = 0;
296            if (this.startData != null) {
297                if (getSeriesCount() > 0) {
298                    result = this.startData[0].length;
299                }
300            }
301            return result;
302        }
303        
304        /**
305         * Returns a list of the categories in the dataset.  This method supports 
306         * the {@link CategoryDataset} interface.
307         *
308         * @return A list of the categories in the dataset.
309         * 
310         * @see #getRowKeys()
311         */
312        public List getColumnKeys() {
313            // the CategoryDataset interface expects a list of categories, but
314            // we've stored them in an array...
315            if (this.categoryKeys == null) {
316                return new ArrayList();
317            }
318            else {
319                return Collections.unmodifiableList(Arrays.asList(
320                        this.categoryKeys));
321            }
322        }
323    
324        /**
325         * Sets the categories for the dataset.
326         *
327         * @param categoryKeys  an array of objects representing the categories in 
328         *                      the dataset.
329         *                      
330         * @see #getRowKeys()
331         * @see #setSeriesKeys(Comparable[])
332         */
333        public void setCategoryKeys(Comparable[] categoryKeys) {
334            if (categoryKeys == null) {
335                throw new IllegalArgumentException("Null 'categoryKeys' argument.");
336            }
337            if (categoryKeys.length != getCategoryCount()) {
338                throw new IllegalArgumentException(
339                        "The number of categories does not match the data.");
340            }
341            for (int i = 0; i < categoryKeys.length; i++) {
342                if (categoryKeys[i] == null) {
343                    throw new IllegalArgumentException(
344                        "DefaultIntervalCategoryDataset.setCategoryKeys(): "
345                        + "null category not permitted.");
346                }
347            }
348            this.categoryKeys = categoryKeys;
349            fireDatasetChanged();
350        }
351    
352        /**
353         * Returns the data value for one category in a series.
354         * <P>
355         * This method is part of the CategoryDataset interface.  Not particularly
356         * meaningful for this class...returns the end value.
357         * 
358         * @param series    The required series (zero based index).
359         * @param category  The required category.
360         * 
361         * @return The data value for one category in a series (null possible).
362         * 
363         * @see #getEndValue(Comparable, Comparable)
364         */
365        public Number getValue(Comparable series, Comparable category) {
366            int seriesIndex = getSeriesIndex(series);
367            if (seriesIndex < 0) {
368                throw new UnknownKeyException("Unknown 'series' key.");
369            }
370            int itemIndex = getColumnIndex(category);
371            if (itemIndex < 0) {
372                throw new UnknownKeyException("Unknown 'category' key.");
373            }
374            return getValue(seriesIndex, itemIndex);
375        }
376    
377        /**
378         * Returns the data value for one category in a series.
379         * <P>
380         * This method is part of the CategoryDataset interface.  Not particularly
381         * meaningful for this class...returns the end value.
382         *
383         * @param series  the required series (zero based index).
384         * @param category  the required category.
385         *
386         * @return The data value for one category in a series (null possible).
387         * 
388         * @see #getEndValue(int, int)
389         */
390        public Number getValue(int series, int category) {
391            return getEndValue(series, category);
392        }
393    
394        /**
395         * Returns the start data value for one category in a series.
396         *
397         * @param series  the required series.
398         * @param category  the required category.
399         *
400         * @return The start data value for one category in a series 
401         *         (possibly <code>null</code>).
402         *         
403         * @see #getStartValue(int, int)
404         */
405        public Number getStartValue(Comparable series, Comparable category) {
406            int seriesIndex = getSeriesIndex(series);
407            if (seriesIndex < 0) {
408                throw new UnknownKeyException("Unknown 'series' key.");
409            }
410            int itemIndex = getColumnIndex(category);
411            if (itemIndex < 0) {
412                throw new UnknownKeyException("Unknown 'category' key.");
413            }
414            return getStartValue(seriesIndex, itemIndex);
415        }
416    
417        /**
418         * Returns the start data value for one category in a series.
419         *
420         * @param series  the required series (zero based index).
421         * @param category  the required category.
422         *
423         * @return The start data value for one category in a series 
424         *         (possibly <code>null</code>).
425         *         
426         * @see #getStartValue(Comparable, Comparable)
427         */
428        public Number getStartValue(int series, int category) {
429    
430            // check arguments...
431            if ((series < 0) || (series >= getSeriesCount())) {
432                throw new IllegalArgumentException(
433                    "DefaultIntervalCategoryDataset.getValue(): "
434                    + "series index out of range.");
435            }
436    
437            if ((category < 0) || (category >= getCategoryCount())) {
438                throw new IllegalArgumentException(
439                    "DefaultIntervalCategoryDataset.getValue(): "
440                    + "category index out of range.");
441            }
442    
443            // fetch the value...
444            return this.startData[series][category];
445    
446        }
447    
448        /**
449         * Returns the end data value for one category in a series.
450         *
451         * @param series  the required series.
452         * @param category  the required category.
453         *
454         * @return The end data value for one category in a series (null possible).
455         * 
456         * @see #getEndValue(int, int)
457         */
458        public Number getEndValue(Comparable series, Comparable category) {
459            int seriesIndex = getSeriesIndex(series);
460            if (seriesIndex < 0) {
461                throw new UnknownKeyException("Unknown 'series' key.");
462            }
463            int itemIndex = getColumnIndex(category);
464            if (itemIndex < 0) {
465                throw new UnknownKeyException("Unknown 'category' key.");
466            }
467            return getEndValue(seriesIndex, itemIndex);
468        }
469    
470        /**
471         * Returns the end data value for one category in a series.
472         *
473         * @param series  the required series (zero based index).
474         * @param category  the required category.
475         *
476         * @return The end data value for one category in a series (null possible).
477         * 
478         * @see #getEndValue(Comparable, Comparable)
479         */
480        public Number getEndValue(int series, int category) {
481            if ((series < 0) || (series >= getSeriesCount())) {
482                throw new IllegalArgumentException(
483                    "DefaultIntervalCategoryDataset.getValue(): "
484                    + "series index out of range.");
485            }
486    
487            if ((category < 0) || (category >= getCategoryCount())) {
488                throw new IllegalArgumentException(
489                    "DefaultIntervalCategoryDataset.getValue(): "
490                    + "category index out of range.");
491            }
492    
493            return this.endData[series][category];
494        }
495    
496        /**
497         * Sets the start data value for one category in a series.
498         * 
499         * @param series  the series (zero-based index).
500         * @param category  the category.
501         * 
502         * @param value The value.
503         * 
504         * @see #setEndValue(int, Comparable, Number)
505         */
506        public void setStartValue(int series, Comparable category, Number value) {
507    
508            // does the series exist?
509            if ((series < 0) || (series > getSeriesCount() - 1)) {
510                throw new IllegalArgumentException(
511                    "DefaultIntervalCategoryDataset.setValue: "
512                    + "series outside valid range.");
513            }
514    
515            // is the category valid?
516            int categoryIndex = getCategoryIndex(category);
517            if (categoryIndex < 0) {
518                throw new IllegalArgumentException(
519                    "DefaultIntervalCategoryDataset.setValue: "
520                    + "unrecognised category.");
521            }
522    
523            // update the data...
524            this.startData[series][categoryIndex] = value;
525            fireDatasetChanged();
526    
527        }
528    
529        /**
530         * Sets the end data value for one category in a series.
531         *
532         * @param series  the series (zero-based index).
533         * @param category  the category.
534         *
535         * @param value the value.
536         * 
537         * @see #setStartValue(int, Comparable, Number)
538         */
539        public void setEndValue(int series, Comparable category, Number value) {
540    
541            // does the series exist?
542            if ((series < 0) || (series > getSeriesCount() - 1)) {
543                throw new IllegalArgumentException(
544                    "DefaultIntervalCategoryDataset.setValue: "
545                    + "series outside valid range.");
546            }
547    
548            // is the category valid?
549            int categoryIndex = getCategoryIndex(category);
550            if (categoryIndex < 0) {
551                throw new IllegalArgumentException(
552                    "DefaultIntervalCategoryDataset.setValue: "
553                    + "unrecognised category.");
554            }
555    
556            // update the data...
557            this.endData[series][categoryIndex] = value;
558            fireDatasetChanged();
559    
560        }
561    
562        /**
563         * Returns the index for the given category.
564         *
565         * @param category  the category (<code>null</code> not permitted).
566         *
567         * @return The index.
568         * 
569         * @see #getColumnIndex(Comparable)
570         */
571        public int getCategoryIndex(Comparable category) {
572            int result = -1;
573            for (int i = 0; i < this.categoryKeys.length; i++) {
574                if (category.equals(this.categoryKeys[i])) {
575                    result = i;
576                    break;
577                }
578            }
579            return result;
580        }
581    
582        /**
583         * Generates an array of keys, by appending a space plus an integer
584         * (starting with 1) to the supplied prefix string.
585         *
586         * @param count  the number of keys required.
587         * @param prefix  the name prefix.
588         *
589         * @return An array of <i>prefixN</i> with N = { 1 .. count}.
590         */
591        private Comparable[] generateKeys(int count, String prefix) {
592            Comparable[] result = new Comparable[count];
593            String name;
594            for (int i = 0; i < count; i++) {
595                name = prefix + (i + 1);
596                result[i] = name;
597            }
598            return result;
599        }
600    
601        /**
602         * Returns a column key.
603         *
604         * @param column  the column index.
605         *
606         * @return The column key.
607         * 
608         * @see #getRowKey(int)
609         */
610        public Comparable getColumnKey(int column) {
611            return this.categoryKeys[column];
612        }
613    
614        /**
615         * Returns a column index.
616         *
617         * @param columnKey  the column key (<code>null</code> not permitted).
618         *
619         * @return The column index.
620         * 
621         * @see #getCategoryIndex(Comparable)
622         */
623        public int getColumnIndex(Comparable columnKey) {
624            if (columnKey == null) {
625                throw new IllegalArgumentException("Null 'columnKey' argument.");
626            }
627            return getCategoryIndex(columnKey);
628        }
629    
630        /**
631         * Returns a row index.
632         *
633         * @param rowKey  the row key.
634         *
635         * @return The row index.
636         * 
637         * @see #getSeriesIndex(Comparable)
638         */
639        public int getRowIndex(Comparable rowKey) {
640            return getSeriesIndex(rowKey);
641        }
642    
643        /**
644         * Returns a list of the series in the dataset.  This method supports the 
645         * {@link CategoryDataset} interface.
646         *
647         * @return A list of the series in the dataset.
648         * 
649         * @see #getColumnKeys()
650         */
651        public List getRowKeys() {
652            // the CategoryDataset interface expects a list of series, but
653            // we've stored them in an array...
654            if (this.seriesKeys == null) {
655                return new java.util.ArrayList();
656            }
657            else {
658                return Collections.unmodifiableList(Arrays.asList(this.seriesKeys));
659            }
660        }
661    
662        /**
663         * Returns the name of the specified series.
664         *
665         * @param row  the index of the required row/series (zero-based).
666         *
667         * @return The name of the specified series.
668         * 
669         * @see #getColumnKey(int)
670         */
671        public Comparable getRowKey(int row) {
672            if ((row >= getRowCount()) || (row < 0)) {
673                throw new IllegalArgumentException(
674                        "The 'row' argument is out of bounds.");
675            }
676            return this.seriesKeys[row];
677        }
678    
679        /**
680         * Returns the number of categories in the dataset.  This method is part of 
681         * the {@link CategoryDataset} interface.
682         *
683         * @return The number of categories in the dataset.
684         * 
685         * @see #getCategoryCount()
686         * @see #getRowCount()
687         */
688        public int getColumnCount() {
689            return this.categoryKeys.length;
690        }
691    
692        /**
693         * Returns the number of series in the dataset (possibly zero).
694         *
695         * @return The number of series in the dataset.
696         * 
697         * @see #getSeriesCount()
698         * @see #getColumnCount()
699         */
700        public int getRowCount() {
701            return this.seriesKeys.length;
702        }
703        
704        /**
705         * Tests this dataset for equality with an arbitrary object.
706         * 
707         * @param obj  the object (<code>null</code> permitted).
708         * 
709         * @return A boolean.
710         */
711        public boolean equals(Object obj) {
712            if (obj == this) {
713                return true;
714            }
715            if (!(obj instanceof DefaultIntervalCategoryDataset)) {
716                return false;
717            }
718            DefaultIntervalCategoryDataset that 
719                    = (DefaultIntervalCategoryDataset) obj;
720            if (!Arrays.equals(this.seriesKeys, that.seriesKeys)) {
721                return false;
722            }
723            if (!Arrays.equals(this.categoryKeys, that.categoryKeys)) {
724                return false;
725            }
726            if (!equal(this.startData, that.startData)) {
727                return false;
728            }
729            if (!equal(this.endData, that.endData)) {
730                return false;
731            }
732            // seem to be the same...
733            return true;
734        }
735    
736        /**
737         * Returns a clone of this dataset.
738         * 
739         * @return A clone.
740         * 
741         * @throws CloneNotSupportedException if there is a problem cloning the
742         *         dataset.
743         */
744        public Object clone() throws CloneNotSupportedException {
745            DefaultIntervalCategoryDataset clone 
746                    = (DefaultIntervalCategoryDataset) super.clone();
747            clone.categoryKeys = (Comparable[]) this.categoryKeys.clone();
748            clone.seriesKeys = (Comparable[]) this.seriesKeys.clone();
749            clone.startData = clone(this.startData);
750            clone.endData = clone(this.endData);
751            return clone;
752        }
753        
754        /**
755         * Tests two double[][] arrays for equality.
756         * 
757         * @param array1  the first array (<code>null</code> permitted).
758         * @param array2  the second arrray (<code>null</code> permitted).
759         * 
760         * @return A boolean.
761         */
762        private static boolean equal(Number[][] array1, Number[][] array2) {
763            if (array1 == null) {
764                return (array2 == null);
765            }
766            if (array2 == null) {
767                return false;
768            }
769            if (array1.length != array2.length) {
770                return false;
771            }
772            for (int i = 0; i < array1.length; i++) {
773                if (!Arrays.equals(array1[i], array2[i])) {
774                    return false;
775                }
776            }
777            return true;
778        }
779        
780        /**
781         * Clones a two dimensional array of <code>Number</code> objects.
782         * 
783         * @param array  the array (<code>null</code> not permitted).
784         * 
785         * @return A clone of the array.
786         */
787        private static Number[][] clone(Number[][] array) {
788            if (array == null) {
789                throw new IllegalArgumentException("Null 'array' argument.");
790            }
791            Number[][] result = new Number[array.length][];
792            for (int i = 0; i < array.length; i++) {
793                Number[] child = array[i];
794                Number[] copychild = new Number[child.length];
795                System.arraycopy(child, 0, copychild, 0, child.length);
796                result[i] = copychild;
797            }
798            return result;
799        }
800    
801        /**
802         * Returns a list of the series in the dataset.
803         *
804         * @return A list of the series in the dataset.
805         * 
806         * @deprecated Use {@link #getRowKeys()} instead.
807         */
808        public List getSeries() {
809            if (this.seriesKeys == null) {
810                return new java.util.ArrayList();
811            }
812            else {
813                return Collections.unmodifiableList(Arrays.asList(this.seriesKeys));
814            }
815        }
816    
817        /**
818         * Returns a list of the categories in the dataset.
819         *
820         * @return A list of the categories in the dataset.
821         * 
822         * @deprecated Use {@link #getColumnKeys()} instead.
823         */
824        public List getCategories() {
825            return getColumnKeys();
826        }
827    
828        /**
829         * Returns the item count.
830         *
831         * @return The item count.
832         * 
833         * @deprecated Use {@link #getCategoryCount()} instead.
834         */
835        public int getItemCount() {
836            return this.categoryKeys.length;
837        }
838    
839    }