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    
050    package org.jfree.data.xy;
051    
052    import org.jfree.data.general.DatasetChangeEvent;
053    import org.jfree.data.general.DatasetChangeListener;
054    import 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     */
060    public 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    }