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 }