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