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