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