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