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