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 * CategoryTableXYDataset.java
029 * ---------------------------
030 * (C) Copyright 2004, 2005, 2007, by Andreas Schroeder and Contributors.
031 *
032 * Original Author: Andreas Schroeder;
033 * Contributor(s): David Gilbert (for Object Refinery Limited);
034 *
035 * $Id: CategoryTableXYDataset.java,v 1.7.2.3 2007/02/02 15:14:53 mungady Exp $
036 *
037 * Changes
038 * -------
039 * 31-Mar-2004 : Version 1 (AS);
040 * 05-May-2004 : Now extends AbstractIntervalXYDataset (DG);
041 * 15-Jul-2004 : Switched interval access method names (DG);
042 * 18-Aug-2004 : Moved from org.jfree.data --> org.jfree.data.xy (DG);
043 * 17-Nov-2004 : Updates required by changes to DomainInfo interface (DG);
044 * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
045 * 05-Oct-2005 : Made the interval delegate a dataset change listener (DG);
046 * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG);
047 *
048 */
049
050 package org.jfree.data.xy;
051
052 import org.jfree.data.DefaultKeyedValues2D;
053 import org.jfree.data.DomainInfo;
054 import org.jfree.data.Range;
055 import org.jfree.data.general.DatasetChangeEvent;
056 import org.jfree.data.general.DatasetUtilities;
057
058 /**
059 * An implementation variant of the {@link TableXYDataset} where every series
060 * shares the same x-values (required for generating stacked area charts).
061 * This implementation uses a {@link DefaultKeyedValues2D} Object as backend
062 * implementation and is hence more "category oriented" than the {@link
063 * DefaultTableXYDataset} implementation.
064 * <p>
065 * This implementation provides no means to remove data items yet.
066 * This is due to the lack of such facility in the DefaultKeyedValues2D class.
067 * <p>
068 * This class also implements the {@link IntervalXYDataset} interface, but this
069 * implementation is provisional.
070 */
071 public class CategoryTableXYDataset extends AbstractIntervalXYDataset
072 implements TableXYDataset,
073 IntervalXYDataset,
074 DomainInfo {
075
076 /**
077 * The backing data structure.
078 */
079 private DefaultKeyedValues2D values;
080
081 /** A delegate for controlling the interval width. */
082 private IntervalXYDelegate intervalDelegate;
083
084 /**
085 * Creates a new empty CategoryTableXYDataset.
086 */
087 public CategoryTableXYDataset() {
088 this.values = new DefaultKeyedValues2D(true);
089 this.intervalDelegate = new IntervalXYDelegate(this);
090 addChangeListener(this.intervalDelegate);
091 }
092
093 /**
094 * Adds a data item to this dataset and sends a {@link DatasetChangeEvent}
095 * to all registered listeners.
096 *
097 * @param x the x value.
098 * @param y the y value.
099 * @param seriesName the name of the series to add the data item.
100 */
101 public void add(double x, double y, String seriesName) {
102 add(new Double(x), new Double(y), seriesName, true);
103 }
104
105 /**
106 * Adds a data item to this dataset and, if requested, sends a
107 * {@link DatasetChangeEvent} to all registered listeners.
108 *
109 * @param x the x value.
110 * @param y the y value.
111 * @param seriesName the name of the series to add the data item.
112 * @param notify notify listeners?
113 */
114 public void add(Number x, Number y, String seriesName, boolean notify) {
115 this.values.addValue(y, (Comparable) x, seriesName);
116 if (notify) {
117 fireDatasetChanged();
118 }
119 }
120
121 /**
122 * Removes a value from the dataset.
123 *
124 * @param x the x-value.
125 * @param seriesName the series name.
126 */
127 public void remove(double x, String seriesName) {
128 remove(new Double(x), seriesName, true);
129 }
130
131 /**
132 * Removes an item from the dataset.
133 *
134 * @param x the x-value.
135 * @param seriesName the series name.
136 * @param notify notify listeners?
137 */
138 public void remove(Number x, String seriesName, boolean notify) {
139 this.values.removeValue((Comparable) x, seriesName);
140 if (notify) {
141 fireDatasetChanged();
142 }
143 }
144
145
146 /**
147 * Returns the number of series in the collection.
148 *
149 * @return The series count.
150 */
151 public int getSeriesCount() {
152 return this.values.getColumnCount();
153 }
154
155 /**
156 * Returns the key for a series.
157 *
158 * @param series the series index (zero-based).
159 *
160 * @return The key for a series.
161 */
162 public Comparable getSeriesKey(int series) {
163 return this.values.getColumnKey(series);
164 }
165
166 /**
167 * Returns the number of x values in the dataset.
168 *
169 * @return The item count.
170 */
171 public int getItemCount() {
172 return this.values.getRowCount();
173 }
174
175 /**
176 * Returns the number of items in the specified series.
177 * Returns the same as {@link CategoryTableXYDataset#getItemCount()}.
178 *
179 * @param series the series index (zero-based).
180 *
181 * @return The item count.
182 */
183 public int getItemCount(int series) {
184 return getItemCount(); // all series have the same number of items in
185 // this dataset
186 }
187
188 /**
189 * Returns the x-value for the specified series and item.
190 *
191 * @param series the series index (zero-based).
192 * @param item the item index (zero-based).
193 *
194 * @return The value.
195 */
196 public Number getX(int series, int item) {
197 return (Number) this.values.getRowKey(item);
198 }
199
200 /**
201 * Returns the starting X value for the specified series and item.
202 *
203 * @param series the series index (zero-based).
204 * @param item the item index (zero-based).
205 *
206 * @return The starting X value.
207 */
208 public Number getStartX(int series, int item) {
209 return this.intervalDelegate.getStartX(series, item);
210 }
211
212 /**
213 * Returns the ending X value for the specified series and item.
214 *
215 * @param series the series index (zero-based).
216 * @param item the item index (zero-based).
217 *
218 * @return The ending X value.
219 */
220 public Number getEndX(int series, int item) {
221 return this.intervalDelegate.getEndX(series, item);
222 }
223
224 /**
225 * Returns the y-value for the specified series and item.
226 *
227 * @param series the series index (zero-based).
228 * @param item the item index (zero-based).
229 *
230 * @return The y value (possibly <code>null</code>).
231 */
232 public Number getY(int series, int item) {
233 return this.values.getValue(item, series);
234 }
235
236 /**
237 * Returns the starting Y value for the specified series and item.
238 *
239 * @param series the series index (zero-based).
240 * @param item the item index (zero-based).
241 *
242 * @return The starting Y value.
243 */
244 public Number getStartY(int series, int item) {
245 return getY(series, item);
246 }
247
248 /**
249 * Returns the ending Y value for the specified series and item.
250 *
251 * @param series the series index (zero-based).
252 * @param item the item index (zero-based).
253 *
254 * @return The ending Y value.
255 */
256 public Number getEndY(int series, int item) {
257 return getY(series, item);
258 }
259
260 /**
261 * Returns the minimum x-value in the dataset.
262 *
263 * @param includeInterval a flag that determines whether or not the
264 * x-interval is taken into account.
265 *
266 * @return The minimum value.
267 */
268 public double getDomainLowerBound(boolean includeInterval) {
269 return this.intervalDelegate.getDomainLowerBound(includeInterval);
270 }
271
272 /**
273 * Returns the maximum x-value in the dataset.
274 *
275 * @param includeInterval a flag that determines whether or not the
276 * x-interval is taken into account.
277 *
278 * @return The maximum value.
279 */
280 public double getDomainUpperBound(boolean includeInterval) {
281 return this.intervalDelegate.getDomainUpperBound(includeInterval);
282 }
283
284 /**
285 * Returns the range of the values in this dataset's domain.
286 *
287 * @param includeInterval a flag that determines whether or not the
288 * x-interval is taken into account.
289 *
290 * @return The range.
291 */
292 public Range getDomainBounds(boolean includeInterval) {
293 if (includeInterval) {
294 return this.intervalDelegate.getDomainBounds(includeInterval);
295 }
296 else {
297 return DatasetUtilities.iterateDomainBounds(this, includeInterval);
298 }
299 }
300
301 /**
302 * Returns the interval position factor.
303 *
304 * @return The interval position factor.
305 */
306 public double getIntervalPositionFactor() {
307 return this.intervalDelegate.getIntervalPositionFactor();
308 }
309
310 /**
311 * Sets the interval position factor. Must be between 0.0 and 1.0 inclusive.
312 * If the factor is 0.5, the gap is in the middle of the x values. If it
313 * is lesser than 0.5, the gap is farther to the left and if greater than
314 * 0.5 it gets farther to the right.
315 *
316 * @param d the new interval position factor.
317 */
318 public void setIntervalPositionFactor(double d) {
319 this.intervalDelegate.setIntervalPositionFactor(d);
320 fireDatasetChanged();
321 }
322
323 /**
324 * Returns the full interval width.
325 *
326 * @return The interval width to use.
327 */
328 public double getIntervalWidth() {
329 return this.intervalDelegate.getIntervalWidth();
330 }
331
332 /**
333 * Sets the interval width to a fixed value, and sends a
334 * {@link DatasetChangeEvent} to all registered listeners.
335 *
336 * @param d the new interval width (must be > 0).
337 */
338 public void setIntervalWidth(double d) {
339 this.intervalDelegate.setFixedIntervalWidth(d);
340 fireDatasetChanged();
341 }
342
343 /**
344 * Returns whether the interval width is automatically calculated or not.
345 *
346 * @return whether the width is automatically calculated or not.
347 */
348 public boolean isAutoWidth() {
349 return this.intervalDelegate.isAutoWidth();
350 }
351
352 /**
353 * Sets the flag that indicates whether the interval width is automatically
354 * calculated or not.
355 *
356 * @param b the flag.
357 */
358 public void setAutoWidth(boolean b) {
359 this.intervalDelegate.setAutoWidth(b);
360 fireDatasetChanged();
361 }
362
363 /**
364 * Tests this dataset for equality with an arbitrary object.
365 *
366 * @param obj the object (<code>null</code> permitted).
367 *
368 * @return A boolean.
369 */
370 public boolean equals(Object obj) {
371 if (!(obj instanceof CategoryTableXYDataset)) {
372 return false;
373 }
374 CategoryTableXYDataset that = (CategoryTableXYDataset) obj;
375 if (!this.intervalDelegate.equals(that.intervalDelegate)) {
376 return false;
377 }
378 if (!this.values.equals(that.values)) {
379 return false;
380 }
381 return true;
382 }
383
384 }