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 * XYBarDataset.java
029 * -----------------
030 * (C) Copyright 2004-2008, by Object Refinery Limited and Contributors.
031 *
032 * Original Author:  David Gilbert (for Object Refinery Limited);
033 * Contributor(s):   -;
034 *
035 * Changes
036 * -------
037 * 02-Mar-2004 : Version 1 (DG);
038 * 05-May-2004 : Now extends AbstractIntervalXYDataset (DG);
039 * 15-Jul-2004 : Switched getX() with getXValue() and getY() with
040 *               getYValue() (DG);
041 * ------------- JFREECHART 1.0.x ---------------------------------------------
042 * 25-Jan-2007 : Added some accessor methods, plus new equals() and clone()
043 *               overrides (DG);
044 * 30-Jan-2007 : Added method overrides to prevent unnecessary object
045 *               creation (DG);
046 * 22-Apr-2008 : Implemented PublicCloneable (DG);
047 *
048 */
049
050package org.jfree.data.xy;
051
052import org.jfree.data.general.DatasetChangeEvent;
053import org.jfree.data.general.DatasetChangeListener;
054import org.jfree.util.PublicCloneable;
055
056/**
057 * A dataset wrapper class that converts a standard {@link XYDataset} into an
058 * {@link IntervalXYDataset} suitable for use in creating XY bar charts.
059 */
060public class XYBarDataset extends AbstractIntervalXYDataset
061        implements IntervalXYDataset, DatasetChangeListener, PublicCloneable {
062
063    /** The underlying dataset. */
064    private XYDataset underlying;
065
066    /** The bar width. */
067    private double barWidth;
068
069    /**
070     * Creates a new dataset.
071     *
072     * @param underlying  the underlying dataset (<code>null</code> not
073     *     permitted).
074     * @param barWidth  the width of the bars.
075     */
076    public XYBarDataset(XYDataset underlying, double barWidth) {
077        this.underlying = underlying;
078        this.underlying.addChangeListener(this);
079        this.barWidth = barWidth;
080    }
081
082    /**
083     * Returns the underlying dataset that was specified via the constructor.
084     *
085     * @return The underlying dataset (never <code>null</code>).
086     *
087     * @since 1.0.4
088     */
089    public XYDataset getUnderlyingDataset() {
090        return this.underlying;
091    }
092
093    /**
094     * Returns the bar width.
095     *
096     * @return The bar width.
097     *
098     * @see #setBarWidth(double)
099     * @since 1.0.4
100     */
101    public double getBarWidth() {
102        return this.barWidth;
103    }
104
105    /**
106     * Sets the bar width and sends a {@link DatasetChangeEvent} to all
107     * registered listeners.
108     *
109     * @param barWidth  the bar width.
110     *
111     * @see #getBarWidth()
112     * @since 1.0.4
113     */
114    public void setBarWidth(double barWidth) {
115        this.barWidth = barWidth;
116        notifyListeners(new DatasetChangeEvent(this, this));
117    }
118
119    /**
120     * Returns the number of series in the dataset.
121     *
122     * @return The series count.
123     */
124    public int getSeriesCount() {
125        return this.underlying.getSeriesCount();
126    }
127
128    /**
129     * Returns the key for a series.
130     *
131     * @param series  the series index (in the range <code>0</code> to
132     *     <code>getSeriesCount() - 1</code>).
133     *
134     * @return The series key.
135     */
136    public Comparable getSeriesKey(int series) {
137        return this.underlying.getSeriesKey(series);
138    }
139
140    /**
141     * Returns the number of items in a series.
142     *
143     * @param series  the series index (zero-based).
144     *
145     * @return The item count.
146     */
147    public int getItemCount(int series) {
148        return this.underlying.getItemCount(series);
149    }
150
151    /**
152     * Returns the x-value for an item within a series.
153     *
154     * @param series  the series index (zero-based).
155     * @param item  the item index (zero-based).
156     *
157     * @return The x-value.
158     *
159     * @see #getXValue(int, int)
160     */
161    public Number getX(int series, int item) {
162        return this.underlying.getX(series, item);
163    }
164
165    /**
166     * Returns the x-value (as a double primitive) for an item within a 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     * @see #getX(int, int)
174     */
175    public double getXValue(int series, int item) {
176        return this.underlying.getXValue(series, item);
177    }
178
179    /**
180     * Returns the y-value for an item within a series.
181     *
182     * @param series  the series index (zero-based).
183     * @param item  the item index (zero-based).
184     *
185     * @return The y-value (possibly <code>null</code>).
186     *
187     * @see #getYValue(int, int)
188     */
189    public Number getY(int series, int item) {
190        return this.underlying.getY(series, item);
191    }
192
193    /**
194     * Returns the y-value (as a double primitive) for an item within a series.
195     *
196     * @param series  the series index (zero-based).
197     * @param item  the item index (zero-based).
198     *
199     * @return The value.
200     *
201     * @see #getY(int, int)
202     */
203    public double getYValue(int series, int item) {
204        return this.underlying.getYValue(series, item);
205    }
206
207    /**
208     * Returns the starting X value for the specified series and item.
209     *
210     * @param series  the series index (zero-based).
211     * @param item  the item index (zero-based).
212     *
213     * @return The value.
214     */
215    public Number getStartX(int series, int item) {
216        Number result = null;
217        Number xnum = this.underlying.getX(series, item);
218        if (xnum != null) {
219             result = new Double(xnum.doubleValue() - this.barWidth / 2.0);
220        }
221        return result;
222    }
223
224    /**
225     * Returns the starting x-value (as a double primitive) for an item within
226     * a series.
227     *
228     * @param series  the series index (zero-based).
229     * @param item  the item index (zero-based).
230     *
231     * @return The value.
232     *
233     * @see #getXValue(int, int)
234     */
235    public double getStartXValue(int series, int item) {
236        return getXValue(series, item) - this.barWidth / 2.0;
237    }
238
239    /**
240     * Returns the ending X value for the specified series and item.
241     *
242     * @param series  the series index (zero-based).
243     * @param item  the item index (zero-based).
244     *
245     * @return The value.
246     */
247    public Number getEndX(int series, int item) {
248        Number result = null;
249        Number xnum = this.underlying.getX(series, item);
250        if (xnum != null) {
251             result = new Double(xnum.doubleValue() + this.barWidth / 2.0);
252        }
253        return result;
254    }
255
256    /**
257     * Returns the ending x-value (as a double primitive) for an item within
258     * a series.
259     *
260     * @param series  the series index (zero-based).
261     * @param item  the item index (zero-based).
262     *
263     * @return The value.
264     *
265     * @see #getXValue(int, int)
266     */
267    public double getEndXValue(int series, int item) {
268        return getXValue(series, item) + this.barWidth / 2.0;
269    }
270
271    /**
272     * Returns the starting Y value for the specified series and item.
273     *
274     * @param series  the series index (zero-based).
275     * @param item  the item index (zero-based).
276     *
277     * @return The value.
278     */
279    public Number getStartY(int series, int item) {
280        return this.underlying.getY(series, item);
281    }
282
283    /**
284     * Returns the starting y-value (as a double primitive) for an item within
285     * a series.
286     *
287     * @param series  the series index (zero-based).
288     * @param item  the item index (zero-based).
289     *
290     * @return The value.
291     *
292     * @see #getYValue(int, int)
293     */
294    public double getStartYValue(int series, int item) {
295        return getYValue(series, item);
296    }
297
298    /**
299     * Returns the ending Y value for the specified series and item.
300     *
301     * @param series  the series index (zero-based).
302     * @param item  the item index (zero-based).
303     *
304     * @return The value.
305     */
306    public Number getEndY(int series, int item) {
307        return this.underlying.getY(series, item);
308    }
309
310    /**
311     * Returns the ending y-value (as a double primitive) for an item within
312     * a series.
313     *
314     * @param series  the series index (zero-based).
315     * @param item  the item index (zero-based).
316     *
317     * @return The value.
318     *
319     * @see #getYValue(int, int)
320     */
321    public double getEndYValue(int series, int item) {
322        return getYValue(series, item);
323    }
324
325    /**
326     * Receives notification of an dataset change event.
327     *
328     * @param event  information about the event.
329     */
330    public void datasetChanged(DatasetChangeEvent event) {
331        notifyListeners(event);
332    }
333
334    /**
335     * Tests this dataset for equality with an arbitrary object.
336     *
337     * @param obj  the object (<code>null</code> permitted).
338     *
339     * @return A boolean.
340     */
341    public boolean equals(Object obj) {
342        if (obj == this) {
343            return true;
344        }
345        if (!(obj instanceof XYBarDataset)) {
346            return false;
347        }
348        XYBarDataset that = (XYBarDataset) obj;
349        if (!this.underlying.equals(that.underlying)) {
350            return false;
351        }
352        if (this.barWidth != that.barWidth) {
353            return false;
354        }
355        return true;
356    }
357
358    /**
359     * Returns an independent copy of the dataset.  Note that:
360     * <ul>
361     * <li>the underlying dataset is only cloned if it implements the
362     * {@link PublicCloneable} interface;</li>
363     * <li>the listeners registered with this dataset are not carried over to
364     * the cloned dataset.</li>
365     * </ul>
366     *
367     * @return An independent copy of the dataset.
368     *
369     * @throws CloneNotSupportedException if the dataset cannot be cloned for
370     *         any reason.
371     */
372    public Object clone() throws CloneNotSupportedException {
373        XYBarDataset clone = (XYBarDataset) super.clone();
374        if (this.underlying instanceof PublicCloneable) {
375            PublicCloneable pc = (PublicCloneable) this.underlying;
376            clone.underlying = (XYDataset) pc.clone();
377        }
378        return clone;
379    }
380
381}