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 }