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     * XYIntervalSeriesCollection.java
029     * -------------------------------
030     * (C) Copyright 2006-2008, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * Changes
036     * -------
037     * 20-Oct-2006 : Version 1 (DG);
038     * 13-Feb-2007 : Provided a number of method overrides that enhance
039     *               performance, and added a proper clone()
040     *               implementation (DG);
041     * 18-Jan-2008 : Added removeSeries() and removeAllSeries() methods (DG);
042     * 22-Apr-2008 : Implemented PublicCloneable (DG);
043     *
044     */
045    
046    package org.jfree.data.xy;
047    
048    import java.io.Serializable;
049    import java.util.List;
050    
051    import org.jfree.data.general.DatasetChangeEvent;
052    import org.jfree.util.ObjectUtilities;
053    import org.jfree.util.PublicCloneable;
054    
055    /**
056     * A collection of {@link XYIntervalSeries} objects.
057     *
058     * @since 1.0.3
059     *
060     * @see XYIntervalSeries
061     */
062    public class XYIntervalSeriesCollection extends AbstractIntervalXYDataset
063            implements IntervalXYDataset, PublicCloneable, Serializable {
064    
065        /** Storage for the data series. */
066        private List data;
067    
068        /**
069         * Creates a new instance of <code>XIntervalSeriesCollection</code>.
070         */
071        public XYIntervalSeriesCollection() {
072            this.data = new java.util.ArrayList();
073        }
074    
075        /**
076         * Adds a series to the collection and sends a {@link DatasetChangeEvent}
077         * to all registered listeners.
078         *
079         * @param series  the series (<code>null</code> not permitted).
080         */
081        public void addSeries(XYIntervalSeries series) {
082            if (series == null) {
083                throw new IllegalArgumentException("Null 'series' argument.");
084            }
085            this.data.add(series);
086            series.addChangeListener(this);
087            fireDatasetChanged();
088        }
089    
090        /**
091         * Returns the number of series in the collection.
092         *
093         * @return The series count.
094         */
095        public int getSeriesCount() {
096            return this.data.size();
097        }
098    
099        /**
100         * Returns a series from the collection.
101         *
102         * @param series  the series index (zero-based).
103         *
104         * @return The series.
105         *
106         * @throws IllegalArgumentException if <code>series</code> is not in the
107         *     range <code>0</code> to <code>getSeriesCount() - 1</code>.
108         */
109        public XYIntervalSeries getSeries(int series) {
110            if ((series < 0) || (series >= getSeriesCount())) {
111                throw new IllegalArgumentException("Series index out of bounds");
112            }
113            return (XYIntervalSeries) this.data.get(series);
114        }
115    
116        /**
117         * Returns the key for a series.
118         *
119         * @param series  the series index (in the range <code>0</code> to
120         *     <code>getSeriesCount() - 1</code>).
121         *
122         * @return The key for a series.
123         *
124         * @throws IllegalArgumentException if <code>series</code> is not in the
125         *     specified range.
126         */
127        public Comparable getSeriesKey(int series) {
128            // defer argument checking
129            return getSeries(series).getKey();
130        }
131    
132        /**
133         * Returns the number of items in the specified series.
134         *
135         * @param series  the series (zero-based index).
136         *
137         * @return The item count.
138         *
139         * @throws IllegalArgumentException if <code>series</code> is not in the
140         *     range <code>0</code> to <code>getSeriesCount() - 1</code>.
141         */
142        public int getItemCount(int series) {
143            // defer argument checking
144            return getSeries(series).getItemCount();
145        }
146    
147        /**
148         * Returns the x-value for an item within a series.
149         *
150         * @param series  the series index.
151         * @param item  the item index.
152         *
153         * @return The x-value.
154         */
155        public Number getX(int series, int item) {
156            XYIntervalSeries s = (XYIntervalSeries) this.data.get(series);
157            return s.getX(item);
158        }
159    
160        /**
161         * Returns the start x-value (as a double primitive) for an item within a
162         * series.
163         *
164         * @param series  the series index (zero-based).
165         * @param item  the item index (zero-based).
166         *
167         * @return The value.
168         */
169        public double getStartXValue(int series, int item) {
170            XYIntervalSeries s = (XYIntervalSeries) this.data.get(series);
171            return s.getXLowValue(item);
172        }
173    
174        /**
175         * Returns the end x-value (as a double primitive) for an item within a
176         * series.
177         *
178         * @param series  the series index (zero-based).
179         * @param item  the item index (zero-based).
180         *
181         * @return The value.
182         */
183        public double getEndXValue(int series, int item) {
184            XYIntervalSeries s = (XYIntervalSeries) this.data.get(series);
185            return s.getXHighValue(item);
186        }
187    
188        /**
189         * Returns the y-value (as a double primitive) for an item within a
190         * series.
191         *
192         * @param series  the series index (zero-based).
193         * @param item  the item index (zero-based).
194         *
195         * @return The value.
196         */
197        public double getYValue(int series, int item) {
198            XYIntervalSeries s = (XYIntervalSeries) this.data.get(series);
199            return s.getYValue(item);
200        }
201    
202        /**
203         * Returns the start y-value (as a double primitive) for an item within a
204         * series.
205         *
206         * @param series  the series index (zero-based).
207         * @param item  the item index (zero-based).
208         *
209         * @return The value.
210         */
211        public double getStartYValue(int series, int item) {
212            XYIntervalSeries s = (XYIntervalSeries) this.data.get(series);
213            return s.getYLowValue(item);
214        }
215    
216        /**
217         * Returns the end y-value (as a double primitive) for an item within a
218         * series.
219         *
220         * @param series  the series (zero-based index).
221         * @param item  the item (zero-based index).
222         *
223         * @return The value.
224         */
225        public double getEndYValue(int series, int item) {
226            XYIntervalSeries s = (XYIntervalSeries) this.data.get(series);
227            return s.getYHighValue(item);
228        }
229    
230        /**
231         * Returns the y-value for an item within a series.
232         *
233         * @param series  the series index.
234         * @param item  the item index.
235         *
236         * @return The y-value.
237         */
238        public Number getY(int series, int item) {
239            return new Double(getYValue(series, item));
240        }
241    
242        /**
243         * Returns the start x-value for an item within a series.
244         *
245         * @param series  the series index.
246         * @param item  the item index.
247         *
248         * @return The x-value.
249         */
250        public Number getStartX(int series, int item) {
251            return new Double(getStartXValue(series, item));
252        }
253    
254        /**
255         * Returns the end x-value for an item within a series.
256         *
257         * @param series  the series index.
258         * @param item  the item index.
259         *
260         * @return The x-value.
261         */
262        public Number getEndX(int series, int item) {
263            return new Double(getEndXValue(series, item));
264        }
265    
266        /**
267         * Returns the start y-value for an item within a series.  This method
268         * maps directly to {@link #getY(int, int)}.
269         *
270         * @param series  the series index.
271         * @param item  the item index.
272         *
273         * @return The start y-value.
274         */
275        public Number getStartY(int series, int item) {
276            return new Double(getStartYValue(series, item));
277        }
278    
279        /**
280         * Returns the end y-value for an item within a series.  This method
281         * maps directly to {@link #getY(int, int)}.
282         *
283         * @param series  the series index.
284         * @param item  the item index.
285         *
286         * @return The end y-value.
287         */
288        public Number getEndY(int series, int item) {
289            return new Double(getEndYValue(series, item));
290        }
291    
292        /**
293         * Removes a series from the collection and sends a
294         * {@link DatasetChangeEvent} to all registered listeners.
295         *
296         * @param series  the series index (zero-based).
297         *
298         * @since 1.0.10
299         */
300        public void removeSeries(int series) {
301            if ((series < 0) || (series >= getSeriesCount())) {
302                throw new IllegalArgumentException("Series index out of bounds.");
303            }
304            XYIntervalSeries ts = (XYIntervalSeries) this.data.get(series);
305            ts.removeChangeListener(this);
306            this.data.remove(series);
307            fireDatasetChanged();
308        }
309    
310        /**
311         * Removes a series from the collection and sends a
312         * {@link DatasetChangeEvent} to all registered listeners.
313         *
314         * @param series  the series (<code>null</code> not permitted).
315         *
316         * @since 1.0.10
317         */
318        public void removeSeries(XYIntervalSeries series) {
319            if (series == null) {
320                throw new IllegalArgumentException("Null 'series' argument.");
321            }
322            if (this.data.contains(series)) {
323                series.removeChangeListener(this);
324                this.data.remove(series);
325                fireDatasetChanged();
326            }
327        }
328    
329        /**
330         * Removes all the series from the collection and sends a
331         * {@link DatasetChangeEvent} to all registered listeners.
332         *
333         * @since 1.0.10
334         */
335        public void removeAllSeries() {
336            // Unregister the collection as a change listener to each series in
337            // the collection.
338            for (int i = 0; i < this.data.size(); i++) {
339              XYIntervalSeries series = (XYIntervalSeries) this.data.get(i);
340              series.removeChangeListener(this);
341            }
342            this.data.clear();
343            fireDatasetChanged();
344        }
345    
346        /**
347         * Tests this instance for equality with an arbitrary object.
348         *
349         * @param obj  the object (<code>null</code> permitted).
350         *
351         * @return A boolean.
352         */
353        public boolean equals(Object obj) {
354            if (obj == this) {
355                return true;
356            }
357            if (!(obj instanceof XYIntervalSeriesCollection)) {
358                return false;
359            }
360            XYIntervalSeriesCollection that = (XYIntervalSeriesCollection) obj;
361            return ObjectUtilities.equal(this.data, that.data);
362        }
363    
364        /**
365         * Returns a clone of this dataset.
366         *
367         * @return A clone of this dataset.
368         *
369         * @throws CloneNotSupportedException if there is a problem cloning.
370         */
371        public Object clone() throws CloneNotSupportedException {
372            XYIntervalSeriesCollection clone
373                    = (XYIntervalSeriesCollection) super.clone();
374            int seriesCount = getSeriesCount();
375            clone.data = new java.util.ArrayList(seriesCount);
376            for (int i = 0; i < this.data.size(); i++) {
377                clone.data.set(i, getSeries(i).clone());
378            }
379            return clone;
380        }
381    
382    }