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 * 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    @Override
125    public int getSeriesCount() {
126        return this.underlying.getSeriesCount();
127    }
128
129    /**
130     * Returns the key for a series.
131     *
132     * @param series  the series index (in the range <code>0</code> to
133     *     <code>getSeriesCount() - 1</code>).
134     *
135     * @return The series key.
136     */
137    @Override
138    public Comparable getSeriesKey(int series) {
139        return this.underlying.getSeriesKey(series);
140    }
141
142    /**
143     * Returns the number of items in a series.
144     *
145     * @param series  the series index (zero-based).
146     *
147     * @return The item count.
148     */
149    @Override
150    public int getItemCount(int series) {
151        return this.underlying.getItemCount(series);
152    }
153
154    /**
155     * Returns the x-value for an item within a series.
156     *
157     * @param series  the series index (zero-based).
158     * @param item  the item index (zero-based).
159     *
160     * @return The x-value.
161     *
162     * @see #getXValue(int, int)
163     */
164    @Override
165    public Number getX(int series, int item) {
166        return this.underlying.getX(series, item);
167    }
168
169    /**
170     * Returns the x-value (as a double primitive) for an item within a series.
171     *
172     * @param series  the series index (zero-based).
173     * @param item  the item index (zero-based).
174     *
175     * @return The value.
176     *
177     * @see #getX(int, int)
178     */
179    @Override
180    public double getXValue(int series, int item) {
181        return this.underlying.getXValue(series, item);
182    }
183
184    /**
185     * Returns the y-value for an item within a series.
186     *
187     * @param series  the series index (zero-based).
188     * @param item  the item index (zero-based).
189     *
190     * @return The y-value (possibly <code>null</code>).
191     *
192     * @see #getYValue(int, int)
193     */
194    @Override
195    public Number getY(int series, int item) {
196        return this.underlying.getY(series, item);
197    }
198
199    /**
200     * Returns the y-value (as a double primitive) for an item within a series.
201     *
202     * @param series  the series index (zero-based).
203     * @param item  the item index (zero-based).
204     *
205     * @return The value.
206     *
207     * @see #getY(int, int)
208     */
209    @Override
210    public double getYValue(int series, int item) {
211        return this.underlying.getYValue(series, item);
212    }
213
214    /**
215     * Returns the starting X value for the specified series and item.
216     *
217     * @param series  the series index (zero-based).
218     * @param item  the item index (zero-based).
219     *
220     * @return The value.
221     */
222    @Override
223    public Number getStartX(int series, int item) {
224        Number result = null;
225        Number xnum = this.underlying.getX(series, item);
226        if (xnum != null) {
227             result = new Double(xnum.doubleValue() - this.barWidth / 2.0);
228        }
229        return result;
230    }
231
232    /**
233     * Returns the starting x-value (as a double primitive) for an item within
234     * a series.
235     *
236     * @param series  the series index (zero-based).
237     * @param item  the item index (zero-based).
238     *
239     * @return The value.
240     *
241     * @see #getXValue(int, int)
242     */
243    @Override
244    public double getStartXValue(int series, int item) {
245        return getXValue(series, item) - this.barWidth / 2.0;
246    }
247
248    /**
249     * Returns the ending X value for the specified series and item.
250     *
251     * @param series  the series index (zero-based).
252     * @param item  the item index (zero-based).
253     *
254     * @return The value.
255     */
256    @Override
257    public Number getEndX(int series, int item) {
258        Number result = null;
259        Number xnum = this.underlying.getX(series, item);
260        if (xnum != null) {
261             result = new Double(xnum.doubleValue() + this.barWidth / 2.0);
262        }
263        return result;
264    }
265
266    /**
267     * Returns the ending x-value (as a double primitive) for an item within
268     * a series.
269     *
270     * @param series  the series index (zero-based).
271     * @param item  the item index (zero-based).
272     *
273     * @return The value.
274     *
275     * @see #getXValue(int, int)
276     */
277    @Override
278    public double getEndXValue(int series, int item) {
279        return getXValue(series, item) + this.barWidth / 2.0;
280    }
281
282    /**
283     * Returns the starting Y value for the specified series and item.
284     *
285     * @param series  the series index (zero-based).
286     * @param item  the item index (zero-based).
287     *
288     * @return The value.
289     */
290    @Override
291    public Number getStartY(int series, int item) {
292        return this.underlying.getY(series, item);
293    }
294
295    /**
296     * Returns the starting y-value (as a double primitive) for an item within
297     * a series.
298     *
299     * @param series  the series index (zero-based).
300     * @param item  the item index (zero-based).
301     *
302     * @return The value.
303     *
304     * @see #getYValue(int, int)
305     */
306    @Override
307    public double getStartYValue(int series, int item) {
308        return getYValue(series, item);
309    }
310
311    /**
312     * Returns the ending Y value for the specified series and item.
313     *
314     * @param series  the series index (zero-based).
315     * @param item  the item index (zero-based).
316     *
317     * @return The value.
318     */
319    @Override
320    public Number getEndY(int series, int item) {
321        return this.underlying.getY(series, item);
322    }
323
324    /**
325     * Returns the ending y-value (as a double primitive) for an item within
326     * a series.
327     *
328     * @param series  the series index (zero-based).
329     * @param item  the item index (zero-based).
330     *
331     * @return The value.
332     *
333     * @see #getYValue(int, int)
334     */
335    @Override
336    public double getEndYValue(int series, int item) {
337        return getYValue(series, item);
338    }
339
340    /**
341     * Receives notification of an dataset change event.
342     *
343     * @param event  information about the event.
344     */
345    @Override
346    public void datasetChanged(DatasetChangeEvent event) {
347        notifyListeners(event);
348    }
349
350    /**
351     * Tests this dataset for equality with an arbitrary object.
352     *
353     * @param obj  the object (<code>null</code> permitted).
354     *
355     * @return A boolean.
356     */
357    @Override
358    public boolean equals(Object obj) {
359        if (obj == this) {
360            return true;
361        }
362        if (!(obj instanceof XYBarDataset)) {
363            return false;
364        }
365        XYBarDataset that = (XYBarDataset) obj;
366        if (!this.underlying.equals(that.underlying)) {
367            return false;
368        }
369        if (this.barWidth != that.barWidth) {
370            return false;
371        }
372        return true;
373    }
374
375    /**
376     * Returns an independent copy of the dataset.  Note that:
377     * <ul>
378     * <li>the underlying dataset is only cloned if it implements the
379     * {@link PublicCloneable} interface;</li>
380     * <li>the listeners registered with this dataset are not carried over to
381     * the cloned dataset.</li>
382     * </ul>
383     *
384     * @return An independent copy of the dataset.
385     *
386     * @throws CloneNotSupportedException if the dataset cannot be cloned for
387     *         any reason.
388     */
389    @Override
390    public Object clone() throws CloneNotSupportedException {
391        XYBarDataset clone = (XYBarDataset) super.clone();
392        if (this.underlying instanceof PublicCloneable) {
393            PublicCloneable pc = (PublicCloneable) this.underlying;
394            clone.underlying = (XYDataset) pc.clone();
395        }
396        return clone;
397    }
398
399}