Source for org.jfree.data.xy.CategoryTableXYDataset

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2007, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it 
  10:  * under the terms of the GNU Lesser General Public License as published by 
  11:  * the Free Software Foundation; either version 2.1 of the License, or 
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but 
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
  22:  * USA.  
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
  25:  * in the United States and other countries.]
  26:  *
  27:  * ---------------------------
  28:  * CategoryTableXYDataset.java
  29:  * ---------------------------
  30:  * (C) Copyright 2004, 2005, 2007, by Andreas Schroeder and Contributors.
  31:  *
  32:  * Original Author:  Andreas Schroeder;
  33:  * Contributor(s):   David Gilbert (for Object Refinery Limited);
  34:  *
  35:  * $Id: CategoryTableXYDataset.java,v 1.7.2.3 2007/02/02 15:14:53 mungady Exp $
  36:  *
  37:  * Changes
  38:  * -------
  39:  * 31-Mar-2004 : Version 1 (AS);
  40:  * 05-May-2004 : Now extends AbstractIntervalXYDataset (DG);
  41:  * 15-Jul-2004 : Switched interval access method names (DG);
  42:  * 18-Aug-2004 : Moved from org.jfree.data --> org.jfree.data.xy (DG);
  43:  * 17-Nov-2004 : Updates required by changes to DomainInfo interface (DG);
  44:  * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG);
  45:  * 05-Oct-2005 : Made the interval delegate a dataset change listener (DG);
  46:  * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG);
  47:  *
  48:  */
  49: 
  50: package org.jfree.data.xy;
  51: 
  52: import org.jfree.data.DefaultKeyedValues2D;
  53: import org.jfree.data.DomainInfo;
  54: import org.jfree.data.Range;
  55: import org.jfree.data.general.DatasetChangeEvent;
  56: import org.jfree.data.general.DatasetUtilities;
  57: 
  58: /**
  59:  * An implementation variant of the {@link TableXYDataset} where every series 
  60:  * shares the same x-values (required for generating stacked area charts). 
  61:  * This implementation uses a {@link DefaultKeyedValues2D} Object as backend 
  62:  * implementation and is hence more "category oriented" than the {@link 
  63:  * DefaultTableXYDataset} implementation.
  64:  * <p>
  65:  * This implementation provides no means to remove data items yet.
  66:  * This is due to the lack of such facility in the DefaultKeyedValues2D class.
  67:  * <p>
  68:  * This class also implements the {@link IntervalXYDataset} interface, but this
  69:  * implementation is provisional. 
  70:  */
  71: public class CategoryTableXYDataset extends AbstractIntervalXYDataset
  72:                                     implements TableXYDataset, 
  73:                                                IntervalXYDataset, 
  74:                                                DomainInfo {
  75:     
  76:     /**
  77:      * The backing data structure.
  78:      */
  79:     private DefaultKeyedValues2D values;
  80:     
  81:     /** A delegate for controlling the interval width. */
  82:     private IntervalXYDelegate intervalDelegate;
  83: 
  84:     /**
  85:      * Creates a new empty CategoryTableXYDataset.
  86:      */
  87:     public CategoryTableXYDataset() {
  88:         this.values = new DefaultKeyedValues2D(true);
  89:         this.intervalDelegate = new IntervalXYDelegate(this);
  90:         addChangeListener(this.intervalDelegate);
  91:     }
  92: 
  93:     /**
  94:      * Adds a data item to this dataset and sends a {@link DatasetChangeEvent} 
  95:      * to all registered listeners.
  96:      * 
  97:      * @param x  the x value.
  98:      * @param y  the y value.
  99:      * @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: }