1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2013, by Object Refinery Limited and Contributors.
6  *
7  * Project Info:  http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
22  * USA.
23  *
24  * [Oracle and Java are registered trademarks of Oracle and/or its affiliates.
25  * Other names may be trademarks of their respective owners.]
26  *
27  * -----------------------------------
28  * DefaultIntervalCategoryDataset.java
29  * -----------------------------------
30  * (C) Copyright 2002-2013, by Jeremy Bowman and Contributors.
31  *
32  * Original Author:  Jeremy Bowman;
33  * Contributor(s):   David Gilbert (for Object Refinery Limited);
34  *
35  * Changes
36  * -------
37  * 29-Apr-2002 : Version 1, contributed by Jeremy Bowman (DG);
38  * 24-Oct-2002 : Amendments for changes made to the dataset interface (DG);
39  * ------------- JFREECHART 1.0.x ---------------------------------------------
40  * 08-Mar-2007 : Added equals() and clone() overrides (DG);
41  * 25-Feb-2008 : Fix for the special case where the dataset is empty, see bug
42  *               1897580 (DG)
43  * 18-Dec-2008 : Use ResourceBundleWrapper - see patch 1607918 by
44  *               Jess Thrysoee (DG);
45  * 03-Jul-2013 : Use ParamChecks (DG);
46  *
47  */
48 
49 package org.jfree.data.category;
50 
51 import java.util.ArrayList;
52 import java.util.Arrays;
53 import java.util.Collections;
54 import java.util.List;
55 import java.util.ResourceBundle;
56 import org.jfree.chart.util.ParamChecks;
57 
58 import org.jfree.chart.util.ResourceBundleWrapper;
59 import org.jfree.data.DataUtilities;
60 import org.jfree.data.UnknownKeyException;
61 import org.jfree.data.general.AbstractSeriesDataset;
62 
63 /**
64  * A convenience class that provides a default implementation of the
65  * {@link IntervalCategoryDataset} interface.
66  * <p>
67  * The standard constructor accepts data in a two dimensional array where the
68  * first dimension is the series, and the second dimension is the category.
69  */
70 public class DefaultIntervalCategoryDataset extends AbstractSeriesDataset
71         implements IntervalCategoryDataset {
72 
73     /** The series keys. */
74     private Comparable[] seriesKeys;
75 
76     /** The category keys. */
77     private Comparable[] categoryKeys;
78 
79     /** Storage for the start value data. */
80     private Number[][] startData;
81 
82     /** Storage for the end value data. */
83     private Number[][] endData;
84 
85     /**
86      * Creates a new dataset using the specified data values and automatically
87      * generated series and category keys.
88      *
89      * @param starts  the starting values for the intervals (<code>null</code>
90      *                not permitted).
91      * @param ends  the ending values for the intervals (<code>null</code> not
92      *                permitted).
93      */
DefaultIntervalCategoryDataset(double[][] starts, double[][] ends)94     public DefaultIntervalCategoryDataset(double[][] starts, double[][] ends) {
95         this(DataUtilities.createNumberArray2D(starts),
96                 DataUtilities.createNumberArray2D(ends));
97     }
98 
99     /**
100      * Constructs a dataset and populates it with data from the array.
101      * <p>
102      * The arrays are indexed as data[series][category].  Series and category
103      * names are automatically generated - you can change them using the
104      * {@link #setSeriesKeys(Comparable[])} and
105      * {@link #setCategoryKeys(Comparable[])} methods.
106      *
107      * @param starts  the start values data.
108      * @param ends  the end values data.
109      */
DefaultIntervalCategoryDataset(Number[][] starts, Number[][] ends)110     public DefaultIntervalCategoryDataset(Number[][] starts, Number[][] ends) {
111         this(null, null, starts, ends);
112     }
113 
114     /**
115      * Constructs a DefaultIntervalCategoryDataset, populates it with data
116      * from the arrays, and uses the supplied names for the series.
117      * <p>
118      * Category names are generated automatically ("Category 1", "Category 2",
119      * etc).
120      *
121      * @param seriesNames  the series names (if <code>null</code>, series names
122      *         will be generated automatically).
123      * @param starts  the start values data, indexed as data[series][category].
124      * @param ends  the end values data, indexed as data[series][category].
125      */
DefaultIntervalCategoryDataset(String[] seriesNames, Number[][] starts, Number[][] ends)126     public DefaultIntervalCategoryDataset(String[] seriesNames,
127                                           Number[][] starts,
128                                           Number[][] ends) {
129 
130         this(seriesNames, null, starts, ends);
131 
132     }
133 
134     /**
135      * Constructs a DefaultIntervalCategoryDataset, populates it with data
136      * from the arrays, and uses the supplied names for the series and the
137      * supplied objects for the categories.
138      *
139      * @param seriesKeys  the series keys (if <code>null</code>, series keys
140      *         will be generated automatically).
141      * @param categoryKeys  the category keys (if <code>null</code>, category
142      *         keys will be generated automatically).
143      * @param starts  the start values data, indexed as data[series][category].
144      * @param ends  the end values data, indexed as data[series][category].
145      */
DefaultIntervalCategoryDataset(Comparable[] seriesKeys, Comparable[] categoryKeys, Number[][] starts, Number[][] ends)146     public DefaultIntervalCategoryDataset(Comparable[] seriesKeys,
147                                           Comparable[] categoryKeys,
148                                           Number[][] starts,
149                                           Number[][] ends) {
150 
151         this.startData = starts;
152         this.endData = ends;
153 
154         if (starts != null && ends != null) {
155 
156             String baseName = "org.jfree.data.resources.DataPackageResources";
157             ResourceBundle resources = ResourceBundleWrapper.getBundle(
158                     baseName);
159 
160             int seriesCount = starts.length;
161             if (seriesCount != ends.length) {
162                 String errMsg = "DefaultIntervalCategoryDataset: the number "
163                     + "of series in the start value dataset does "
164                     + "not match the number of series in the end "
165                     + "value dataset.";
166                 throw new IllegalArgumentException(errMsg);
167             }
168             if (seriesCount > 0) {
169 
170                 // set up the series names...
171                 if (seriesKeys != null) {
172 
173                     if (seriesKeys.length != seriesCount) {
174                         throw new IllegalArgumentException(
175                                 "The number of series keys does not "
176                                 + "match the number of series in the data.");
177                     }
178 
179                     this.seriesKeys = seriesKeys;
180                 }
181                 else {
182                     String prefix = resources.getString(
183                             "series.default-prefix") + " ";
184                     this.seriesKeys = generateKeys(seriesCount, prefix);
185                 }
186 
187                 // set up the category names...
188                 int categoryCount = starts[0].length;
189                 if (categoryCount != ends[0].length) {
190                     String errMsg = "DefaultIntervalCategoryDataset: the "
191                                 + "number of categories in the start value "
192                                 + "dataset does not match the number of "
193                                 + "categories in the end value dataset.";
194                     throw new IllegalArgumentException(errMsg);
195                 }
196                 if (categoryKeys != null) {
197                     if (categoryKeys.length != categoryCount) {
198                         throw new IllegalArgumentException(
199                                 "The number of category keys does not match "
200                                 + "the number of categories in the data.");
201                     }
202                     this.categoryKeys = categoryKeys;
203                 }
204                 else {
205                     String prefix = resources.getString(
206                             "categories.default-prefix") + " ";
207                     this.categoryKeys = generateKeys(categoryCount, prefix);
208                 }
209 
210             }
211             else {
212                 this.seriesKeys = new Comparable[0];
213                 this.categoryKeys = new Comparable[0];
214             }
215         }
216 
217     }
218 
219     /**
220      * Returns the number of series in the dataset (possibly zero).
221      *
222      * @return The number of series in the dataset.
223      *
224      * @see #getRowCount()
225      * @see #getCategoryCount()
226      */
227     @Override
getSeriesCount()228     public int getSeriesCount() {
229         int result = 0;
230         if (this.startData != null) {
231             result = this.startData.length;
232         }
233         return result;
234     }
235 
236     /**
237      * Returns a series index.
238      *
239      * @param seriesKey  the series key.
240      *
241      * @return The series index.
242      *
243      * @see #getRowIndex(Comparable)
244      * @see #getSeriesKey(int)
245      */
getSeriesIndex(Comparable seriesKey)246     public int getSeriesIndex(Comparable seriesKey) {
247         int result = -1;
248         for (int i = 0; i < this.seriesKeys.length; i++) {
249             if (seriesKey.equals(this.seriesKeys[i])) {
250                 result = i;
251                 break;
252             }
253         }
254         return result;
255     }
256 
257     /**
258      * Returns the name of the specified series.
259      *
260      * @param series  the index of the required series (zero-based).
261      *
262      * @return The name of the specified series.
263      *
264      * @see #getSeriesIndex(Comparable)
265      */
266     @Override
getSeriesKey(int series)267     public Comparable getSeriesKey(int series) {
268         if ((series >= getSeriesCount()) || (series < 0)) {
269             throw new IllegalArgumentException("No such series : " + series);
270         }
271         return this.seriesKeys[series];
272     }
273 
274     /**
275      * Sets the names of the series in the dataset.
276      *
277      * @param seriesKeys  the new keys (<code>null</code> not permitted, the
278      *         length of the array must match the number of series in the
279      *         dataset).
280      *
281      * @see #setCategoryKeys(Comparable[])
282      */
setSeriesKeys(Comparable[] seriesKeys)283     public void setSeriesKeys(Comparable[] seriesKeys) {
284         ParamChecks.nullNotPermitted(seriesKeys, "seriesKeys");
285         if (seriesKeys.length != getSeriesCount()) {
286             throw new IllegalArgumentException(
287                     "The number of series keys does not match the data.");
288         }
289         this.seriesKeys = seriesKeys;
290         fireDatasetChanged();
291     }
292 
293     /**
294      * Returns the number of categories in the dataset.
295      *
296      * @return The number of categories in the dataset.
297      *
298      * @see #getColumnCount()
299      */
getCategoryCount()300     public int getCategoryCount() {
301         int result = 0;
302         if (this.startData != null) {
303             if (getSeriesCount() > 0) {
304                 result = this.startData[0].length;
305             }
306         }
307         return result;
308     }
309 
310     /**
311      * Returns a list of the categories in the dataset.  This method supports
312      * the {@link CategoryDataset} interface.
313      *
314      * @return A list of the categories in the dataset.
315      *
316      * @see #getRowKeys()
317      */
318     @Override
getColumnKeys()319     public List getColumnKeys() {
320         // the CategoryDataset interface expects a list of categories, but
321         // we've stored them in an array...
322         if (this.categoryKeys == null) {
323             return new ArrayList();
324         }
325         else {
326             return Collections.unmodifiableList(Arrays.asList(
327                     this.categoryKeys));
328         }
329     }
330 
331     /**
332      * Sets the categories for the dataset.
333      *
334      * @param categoryKeys  an array of objects representing the categories in
335      *                      the dataset.
336      *
337      * @see #getRowKeys()
338      * @see #setSeriesKeys(Comparable[])
339      */
setCategoryKeys(Comparable[] categoryKeys)340     public void setCategoryKeys(Comparable[] categoryKeys) {
341         ParamChecks.nullNotPermitted(categoryKeys, "categoryKeys");
342         if (categoryKeys.length != getCategoryCount()) {
343             throw new IllegalArgumentException(
344                     "The number of categories does not match the data.");
345         }
346         for (int i = 0; i < categoryKeys.length; i++) {
347             if (categoryKeys[i] == null) {
348                 throw new IllegalArgumentException(
349                     "DefaultIntervalCategoryDataset.setCategoryKeys(): "
350                     + "null category not permitted.");
351             }
352         }
353         this.categoryKeys = categoryKeys;
354         fireDatasetChanged();
355     }
356 
357     /**
358      * Returns the data value for one category in a series.
359      * <P>
360      * This method is part of the CategoryDataset interface.  Not particularly
361      * meaningful for this class...returns the end value.
362      *
363      * @param series    The required series (zero based index).
364      * @param category  The required category.
365      *
366      * @return The data value for one category in a series (null possible).
367      *
368      * @see #getEndValue(Comparable, Comparable)
369      */
370     @Override
getValue(Comparable series, Comparable category)371     public Number getValue(Comparable series, Comparable category) {
372         int seriesIndex = getSeriesIndex(series);
373         if (seriesIndex < 0) {
374             throw new UnknownKeyException("Unknown 'series' key.");
375         }
376         int itemIndex = getColumnIndex(category);
377         if (itemIndex < 0) {
378             throw new UnknownKeyException("Unknown 'category' key.");
379         }
380         return getValue(seriesIndex, itemIndex);
381     }
382 
383     /**
384      * Returns the data value for one category in a series.
385      * <P>
386      * This method is part of the CategoryDataset interface.  Not particularly
387      * meaningful for this class...returns the end value.
388      *
389      * @param series  the required series (zero based index).
390      * @param category  the required category.
391      *
392      * @return The data value for one category in a series (null possible).
393      *
394      * @see #getEndValue(int, int)
395      */
396     @Override
getValue(int series, int category)397     public Number getValue(int series, int category) {
398         return getEndValue(series, category);
399     }
400 
401     /**
402      * Returns the start data value for one category in a series.
403      *
404      * @param series  the required series.
405      * @param category  the required category.
406      *
407      * @return The start data value for one category in a series
408      *         (possibly <code>null</code>).
409      *
410      * @see #getStartValue(int, int)
411      */
412     @Override
getStartValue(Comparable series, Comparable category)413     public Number getStartValue(Comparable series, Comparable category) {
414         int seriesIndex = getSeriesIndex(series);
415         if (seriesIndex < 0) {
416             throw new UnknownKeyException("Unknown 'series' key.");
417         }
418         int itemIndex = getColumnIndex(category);
419         if (itemIndex < 0) {
420             throw new UnknownKeyException("Unknown 'category' key.");
421         }
422         return getStartValue(seriesIndex, itemIndex);
423     }
424 
425     /**
426      * Returns the start data value for one category in a series.
427      *
428      * @param series  the required series (zero based index).
429      * @param category  the required category.
430      *
431      * @return The start data value for one category in a series
432      *         (possibly <code>null</code>).
433      *
434      * @see #getStartValue(Comparable, Comparable)
435      */
436     @Override
getStartValue(int series, int category)437     public Number getStartValue(int series, int category) {
438 
439         // check arguments...
440         if ((series < 0) || (series >= getSeriesCount())) {
441             throw new IllegalArgumentException(
442                 "DefaultIntervalCategoryDataset.getValue(): "
443                 + "series index out of range.");
444         }
445 
446         if ((category < 0) || (category >= getCategoryCount())) {
447             throw new IllegalArgumentException(
448                 "DefaultIntervalCategoryDataset.getValue(): "
449                 + "category index out of range.");
450         }
451 
452         // fetch the value...
453         return this.startData[series][category];
454 
455     }
456 
457     /**
458      * Returns the end data value for one category in a series.
459      *
460      * @param series  the required series.
461      * @param category  the required category.
462      *
463      * @return The end data value for one category in a series (null possible).
464      *
465      * @see #getEndValue(int, int)
466      */
467     @Override
getEndValue(Comparable series, Comparable category)468     public Number getEndValue(Comparable series, Comparable category) {
469         int seriesIndex = getSeriesIndex(series);
470         if (seriesIndex < 0) {
471             throw new UnknownKeyException("Unknown 'series' key.");
472         }
473         int itemIndex = getColumnIndex(category);
474         if (itemIndex < 0) {
475             throw new UnknownKeyException("Unknown 'category' key.");
476         }
477         return getEndValue(seriesIndex, itemIndex);
478     }
479 
480     /**
481      * Returns the end data value for one category in a series.
482      *
483      * @param series  the required series (zero based index).
484      * @param category  the required category.
485      *
486      * @return The end data value for one category in a series (null possible).
487      *
488      * @see #getEndValue(Comparable, Comparable)
489      */
490     @Override
getEndValue(int series, int category)491     public Number getEndValue(int series, int category) {
492         if ((series < 0) || (series >= getSeriesCount())) {
493             throw new IllegalArgumentException(
494                 "DefaultIntervalCategoryDataset.getValue(): "
495                 + "series index out of range.");
496         }
497 
498         if ((category < 0) || (category >= getCategoryCount())) {
499             throw new IllegalArgumentException(
500                 "DefaultIntervalCategoryDataset.getValue(): "
501                 + "category index out of range.");
502         }
503 
504         return this.endData[series][category];
505     }
506 
507     /**
508      * Sets the start data value for one category in a series.
509      *
510      * @param series  the series (zero-based index).
511      * @param category  the category.
512      *
513      * @param value The value.
514      *
515      * @see #setEndValue(int, Comparable, Number)
516      */
setStartValue(int series, Comparable category, Number value)517     public void setStartValue(int series, Comparable category, Number value) {
518 
519         // does the series exist?
520         if ((series < 0) || (series > getSeriesCount() - 1)) {
521             throw new IllegalArgumentException(
522                 "DefaultIntervalCategoryDataset.setValue: "
523                 + "series outside valid range.");
524         }
525 
526         // is the category valid?
527         int categoryIndex = getCategoryIndex(category);
528         if (categoryIndex < 0) {
529             throw new IllegalArgumentException(
530                 "DefaultIntervalCategoryDataset.setValue: "
531                 + "unrecognised category.");
532         }
533 
534         // update the data...
535         this.startData[series][categoryIndex] = value;
536         fireDatasetChanged();
537 
538     }
539 
540     /**
541      * Sets the end data value for one category in a series.
542      *
543      * @param series  the series (zero-based index).
544      * @param category  the category.
545      *
546      * @param value the value.
547      *
548      * @see #setStartValue(int, Comparable, Number)
549      */
setEndValue(int series, Comparable category, Number value)550     public void setEndValue(int series, Comparable category, Number value) {
551 
552         // does the series exist?
553         if ((series < 0) || (series > getSeriesCount() - 1)) {
554             throw new IllegalArgumentException(
555                 "DefaultIntervalCategoryDataset.setValue: "
556                 + "series outside valid range.");
557         }
558 
559         // is the category valid?
560         int categoryIndex = getCategoryIndex(category);
561         if (categoryIndex < 0) {
562             throw new IllegalArgumentException(
563                 "DefaultIntervalCategoryDataset.setValue: "
564                 + "unrecognised category.");
565         }
566 
567         // update the data...
568         this.endData[series][categoryIndex] = value;
569         fireDatasetChanged();
570 
571     }
572 
573     /**
574      * Returns the index for the given category.
575      *
576      * @param category  the category (<code>null</code> not permitted).
577      *
578      * @return The index.
579      *
580      * @see #getColumnIndex(Comparable)
581      */
getCategoryIndex(Comparable category)582     public int getCategoryIndex(Comparable category) {
583         int result = -1;
584         for (int i = 0; i < this.categoryKeys.length; i++) {
585             if (category.equals(this.categoryKeys[i])) {
586                 result = i;
587                 break;
588             }
589         }
590         return result;
591     }
592 
593     /**
594      * Generates an array of keys, by appending a space plus an integer
595      * (starting with 1) to the supplied prefix string.
596      *
597      * @param count  the number of keys required.
598      * @param prefix  the name prefix.
599      *
600      * @return An array of <i>prefixN</i> with N = { 1 .. count}.
601      */
generateKeys(int count, String prefix)602     private Comparable[] generateKeys(int count, String prefix) {
603         Comparable[] result = new Comparable[count];
604         String name;
605         for (int i = 0; i < count; i++) {
606             name = prefix + (i + 1);
607             result[i] = name;
608         }
609         return result;
610     }
611 
612     /**
613      * Returns a column key.
614      *
615      * @param column  the column index.
616      *
617      * @return The column key.
618      *
619      * @see #getRowKey(int)
620      */
621     @Override
getColumnKey(int column)622     public Comparable getColumnKey(int column) {
623         return this.categoryKeys[column];
624     }
625 
626     /**
627      * Returns a column index.
628      *
629      * @param columnKey  the column key (<code>null</code> not permitted).
630      *
631      * @return The column index.
632      *
633      * @see #getCategoryIndex(Comparable)
634      */
635     @Override
getColumnIndex(Comparable columnKey)636     public int getColumnIndex(Comparable columnKey) {
637         ParamChecks.nullNotPermitted(columnKey, "columnKey");
638         return getCategoryIndex(columnKey);
639     }
640 
641     /**
642      * Returns a row index.
643      *
644      * @param rowKey  the row key.
645      *
646      * @return The row index.
647      *
648      * @see #getSeriesIndex(Comparable)
649      */
650     @Override
getRowIndex(Comparable rowKey)651     public int getRowIndex(Comparable rowKey) {
652         return getSeriesIndex(rowKey);
653     }
654 
655     /**
656      * Returns a list of the series in the dataset.  This method supports the
657      * {@link CategoryDataset} interface.
658      *
659      * @return A list of the series in the dataset.
660      *
661      * @see #getColumnKeys()
662      */
663     @Override
getRowKeys()664     public List getRowKeys() {
665         // the CategoryDataset interface expects a list of series, but
666         // we've stored them in an array...
667         if (this.seriesKeys == null) {
668             return new java.util.ArrayList();
669         }
670         else {
671             return Collections.unmodifiableList(Arrays.asList(this.seriesKeys));
672         }
673     }
674 
675     /**
676      * Returns the name of the specified series.
677      *
678      * @param row  the index of the required row/series (zero-based).
679      *
680      * @return The name of the specified series.
681      *
682      * @see #getColumnKey(int)
683      */
684     @Override
getRowKey(int row)685     public Comparable getRowKey(int row) {
686         if ((row >= getRowCount()) || (row < 0)) {
687             throw new IllegalArgumentException(
688                     "The 'row' argument is out of bounds.");
689         }
690         return this.seriesKeys[row];
691     }
692 
693     /**
694      * Returns the number of categories in the dataset.  This method is part of
695      * the {@link CategoryDataset} interface.
696      *
697      * @return The number of categories in the dataset.
698      *
699      * @see #getCategoryCount()
700      * @see #getRowCount()
701      */
702     @Override
getColumnCount()703     public int getColumnCount() {
704         return this.categoryKeys.length;
705     }
706 
707     /**
708      * Returns the number of series in the dataset (possibly zero).
709      *
710      * @return The number of series in the dataset.
711      *
712      * @see #getSeriesCount()
713      * @see #getColumnCount()
714      */
715     @Override
getRowCount()716     public int getRowCount() {
717         return this.seriesKeys.length;
718     }
719 
720     /**
721      * Tests this dataset for equality with an arbitrary object.
722      *
723      * @param obj  the object (<code>null</code> permitted).
724      *
725      * @return A boolean.
726      */
727     @Override
equals(Object obj)728     public boolean equals(Object obj) {
729         if (obj == this) {
730             return true;
731         }
732         if (!(obj instanceof DefaultIntervalCategoryDataset)) {
733             return false;
734         }
735         DefaultIntervalCategoryDataset that
736                 = (DefaultIntervalCategoryDataset) obj;
737         if (!Arrays.equals(this.seriesKeys, that.seriesKeys)) {
738             return false;
739         }
740         if (!Arrays.equals(this.categoryKeys, that.categoryKeys)) {
741             return false;
742         }
743         if (!equal(this.startData, that.startData)) {
744             return false;
745         }
746         if (!equal(this.endData, that.endData)) {
747             return false;
748         }
749         // seem to be the same...
750         return true;
751     }
752 
753     /**
754      * Returns a clone of this dataset.
755      *
756      * @return A clone.
757      *
758      * @throws CloneNotSupportedException if there is a problem cloning the
759      *         dataset.
760      */
761     @Override
clone()762     public Object clone() throws CloneNotSupportedException {
763         DefaultIntervalCategoryDataset clone
764                 = (DefaultIntervalCategoryDataset) super.clone();
765         clone.categoryKeys = (Comparable[]) this.categoryKeys.clone();
766         clone.seriesKeys = (Comparable[]) this.seriesKeys.clone();
767         clone.startData = clone(this.startData);
768         clone.endData = clone(this.endData);
769         return clone;
770     }
771 
772     /**
773      * Tests two double[][] arrays for equality.
774      *
775      * @param array1  the first array (<code>null</code> permitted).
776      * @param array2  the second arrray (<code>null</code> permitted).
777      *
778      * @return A boolean.
779      */
equal(Number[][] array1, Number[][] array2)780     private static boolean equal(Number[][] array1, Number[][] array2) {
781         if (array1 == null) {
782             return (array2 == null);
783         }
784         if (array2 == null) {
785             return false;
786         }
787         if (array1.length != array2.length) {
788             return false;
789         }
790         for (int i = 0; i < array1.length; i++) {
791             if (!Arrays.equals(array1[i], array2[i])) {
792                 return false;
793             }
794         }
795         return true;
796     }
797 
798     /**
799      * Clones a two dimensional array of <code>Number</code> objects.
800      *
801      * @param array  the array (<code>null</code> not permitted).
802      *
803      * @return A clone of the array.
804      */
clone(Number[][] array)805     private static Number[][] clone(Number[][] array) {
806         ParamChecks.nullNotPermitted(array, "array");
807         Number[][] result = new Number[array.length][];
808         for (int i = 0; i < array.length; i++) {
809             Number[] child = array[i];
810             Number[] copychild = new Number[child.length];
811             System.arraycopy(child, 0, copychild, 0, child.length);
812             result[i] = copychild;
813         }
814         return result;
815     }
816 
817     /**
818      * Returns a list of the series in the dataset.
819      *
820      * @return A list of the series in the dataset.
821      *
822      * @deprecated Use {@link #getRowKeys()} instead.
823      */
getSeries()824     public List getSeries() {
825         if (this.seriesKeys == null) {
826             return new java.util.ArrayList();
827         }
828         else {
829             return Collections.unmodifiableList(Arrays.asList(this.seriesKeys));
830         }
831     }
832 
833     /**
834      * Returns a list of the categories in the dataset.
835      *
836      * @return A list of the categories in the dataset.
837      *
838      * @deprecated Use {@link #getColumnKeys()} instead.
839      */
getCategories()840     public List getCategories() {
841         return getColumnKeys();
842     }
843 
844     /**
845      * Returns the item count.
846      *
847      * @return The item count.
848      *
849      * @deprecated Use {@link #getCategoryCount()} instead.
850      */
getItemCount()851     public int getItemCount() {
852         return this.categoryKeys.length;
853     }
854 
855 }
856