Frames | No Frames |
1: /* =========================================================== 2: * JFreeChart : a free chart library for the Java(tm) platform 3: * =========================================================== 4: * 5: * (C) Copyright 2000-2008, 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-2008, by Andreas Schroeder and Contributors. 31: * 32: * Original Author: Andreas Schroeder; 33: * Contributor(s): David Gilbert (for Object Refinery Limited); 34: * 35: * Changes 36: * ------- 37: * 31-Mar-2004 : Version 1 (AS); 38: * 05-May-2004 : Now extends AbstractIntervalXYDataset (DG); 39: * 15-Jul-2004 : Switched interval access method names (DG); 40: * 18-Aug-2004 : Moved from org.jfree.data --> org.jfree.data.xy (DG); 41: * 17-Nov-2004 : Updates required by changes to DomainInfo interface (DG); 42: * 11-Jan-2005 : Removed deprecated code in preparation for 1.0.0 release (DG); 43: * 05-Oct-2005 : Made the interval delegate a dataset change listener (DG); 44: * 02-Feb-2007 : Removed author tags all over JFreeChart sources (DG); 45: * 22-Apr-2008 : Implemented PublicCloneable, and fixed clone() method (DG); 46: * 47: */ 48: 49: package org.jfree.data.xy; 50: 51: import org.jfree.data.DefaultKeyedValues2D; 52: import org.jfree.data.DomainInfo; 53: import org.jfree.data.Range; 54: import org.jfree.data.general.DatasetChangeEvent; 55: import org.jfree.data.general.DatasetUtilities; 56: import org.jfree.util.PublicCloneable; 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, IntervalXYDataset, DomainInfo, 73: PublicCloneable { 74: 75: /** 76: * The backing data structure. 77: */ 78: private DefaultKeyedValues2D values; 79: 80: /** A delegate for controlling the interval width. */ 81: private IntervalXYDelegate intervalDelegate; 82: 83: /** 84: * Creates a new empty CategoryTableXYDataset. 85: */ 86: public CategoryTableXYDataset() { 87: this.values = new DefaultKeyedValues2D(true); 88: this.intervalDelegate = new IntervalXYDelegate(this); 89: addChangeListener(this.intervalDelegate); 90: } 91: 92: /** 93: * Adds a data item to this dataset and sends a {@link DatasetChangeEvent} 94: * to all registered listeners. 95: * 96: * @param x the x value. 97: * @param y the y value. 98: * @param seriesName the name of the series to add the data item. 99: */ 100: public void add(double x, double y, String seriesName) { 101: add(new Double(x), new Double(y), seriesName, true); 102: } 103: 104: /** 105: * Adds a data item to this dataset and, if requested, sends a 106: * {@link DatasetChangeEvent} to all registered listeners. 107: * 108: * @param x the x value. 109: * @param y the y value. 110: * @param seriesName the name of the series to add the data item. 111: * @param notify notify listeners? 112: */ 113: public void add(Number x, Number y, String seriesName, boolean notify) { 114: this.values.addValue(y, (Comparable) x, seriesName); 115: if (notify) { 116: fireDatasetChanged(); 117: } 118: } 119: 120: /** 121: * Removes a value from the dataset. 122: * 123: * @param x the x-value. 124: * @param seriesName the series name. 125: */ 126: public void remove(double x, String seriesName) { 127: remove(new Double(x), seriesName, true); 128: } 129: 130: /** 131: * Removes an item from the dataset. 132: * 133: * @param x the x-value. 134: * @param seriesName the series name. 135: * @param notify notify listeners? 136: */ 137: public void remove(Number x, String seriesName, boolean notify) { 138: this.values.removeValue((Comparable) x, seriesName); 139: if (notify) { 140: fireDatasetChanged(); 141: } 142: } 143: 144: 145: /** 146: * Returns the number of series in the collection. 147: * 148: * @return The series count. 149: */ 150: public int getSeriesCount() { 151: return this.values.getColumnCount(); 152: } 153: 154: /** 155: * Returns the key for a series. 156: * 157: * @param series the series index (zero-based). 158: * 159: * @return The key for a series. 160: */ 161: public Comparable getSeriesKey(int series) { 162: return this.values.getColumnKey(series); 163: } 164: 165: /** 166: * Returns the number of x values in the dataset. 167: * 168: * @return The item count. 169: */ 170: public int getItemCount() { 171: return this.values.getRowCount(); 172: } 173: 174: /** 175: * Returns the number of items in the specified series. 176: * Returns the same as {@link CategoryTableXYDataset#getItemCount()}. 177: * 178: * @param series the series index (zero-based). 179: * 180: * @return The item count. 181: */ 182: public int getItemCount(int series) { 183: return getItemCount(); // all series have the same number of items in 184: // this dataset 185: } 186: 187: /** 188: * Returns the x-value for the specified series and item. 189: * 190: * @param series the series index (zero-based). 191: * @param item the item index (zero-based). 192: * 193: * @return The value. 194: */ 195: public Number getX(int series, int item) { 196: return (Number) this.values.getRowKey(item); 197: } 198: 199: /** 200: * Returns the starting X value for the specified series and item. 201: * 202: * @param series the series index (zero-based). 203: * @param item the item index (zero-based). 204: * 205: * @return The starting X value. 206: */ 207: public Number getStartX(int series, int item) { 208: return this.intervalDelegate.getStartX(series, item); 209: } 210: 211: /** 212: * Returns the ending X value for the specified series and item. 213: * 214: * @param series the series index (zero-based). 215: * @param item the item index (zero-based). 216: * 217: * @return The ending X value. 218: */ 219: public Number getEndX(int series, int item) { 220: return this.intervalDelegate.getEndX(series, item); 221: } 222: 223: /** 224: * Returns the y-value for the specified series and item. 225: * 226: * @param series the series index (zero-based). 227: * @param item the item index (zero-based). 228: * 229: * @return The y value (possibly <code>null</code>). 230: */ 231: public Number getY(int series, int item) { 232: return this.values.getValue(item, series); 233: } 234: 235: /** 236: * Returns the starting Y value for the specified series and item. 237: * 238: * @param series the series index (zero-based). 239: * @param item the item index (zero-based). 240: * 241: * @return The starting Y value. 242: */ 243: public Number getStartY(int series, int item) { 244: return getY(series, item); 245: } 246: 247: /** 248: * Returns the ending Y value for the specified series and item. 249: * 250: * @param series the series index (zero-based). 251: * @param item the item index (zero-based). 252: * 253: * @return The ending Y value. 254: */ 255: public Number getEndY(int series, int item) { 256: return getY(series, item); 257: } 258: 259: /** 260: * Returns the minimum x-value in the dataset. 261: * 262: * @param includeInterval a flag that determines whether or not the 263: * x-interval is taken into account. 264: * 265: * @return The minimum value. 266: */ 267: public double getDomainLowerBound(boolean includeInterval) { 268: return this.intervalDelegate.getDomainLowerBound(includeInterval); 269: } 270: 271: /** 272: * Returns the maximum x-value in the dataset. 273: * 274: * @param includeInterval a flag that determines whether or not the 275: * x-interval is taken into account. 276: * 277: * @return The maximum value. 278: */ 279: public double getDomainUpperBound(boolean includeInterval) { 280: return this.intervalDelegate.getDomainUpperBound(includeInterval); 281: } 282: 283: /** 284: * Returns the range of the values in this dataset's domain. 285: * 286: * @param includeInterval a flag that determines whether or not the 287: * x-interval is taken into account. 288: * 289: * @return The range. 290: */ 291: public Range getDomainBounds(boolean includeInterval) { 292: if (includeInterval) { 293: return this.intervalDelegate.getDomainBounds(includeInterval); 294: } 295: else { 296: return DatasetUtilities.iterateDomainBounds(this, includeInterval); 297: } 298: } 299: 300: /** 301: * Returns the interval position factor. 302: * 303: * @return The interval position factor. 304: */ 305: public double getIntervalPositionFactor() { 306: return this.intervalDelegate.getIntervalPositionFactor(); 307: } 308: 309: /** 310: * Sets the interval position factor. Must be between 0.0 and 1.0 inclusive. 311: * If the factor is 0.5, the gap is in the middle of the x values. If it 312: * is lesser than 0.5, the gap is farther to the left and if greater than 313: * 0.5 it gets farther to the right. 314: * 315: * @param d the new interval position factor. 316: */ 317: public void setIntervalPositionFactor(double d) { 318: this.intervalDelegate.setIntervalPositionFactor(d); 319: fireDatasetChanged(); 320: } 321: 322: /** 323: * Returns the full interval width. 324: * 325: * @return The interval width to use. 326: */ 327: public double getIntervalWidth() { 328: return this.intervalDelegate.getIntervalWidth(); 329: } 330: 331: /** 332: * Sets the interval width to a fixed value, and sends a 333: * {@link DatasetChangeEvent} to all registered listeners. 334: * 335: * @param d the new interval width (must be > 0). 336: */ 337: public void setIntervalWidth(double d) { 338: this.intervalDelegate.setFixedIntervalWidth(d); 339: fireDatasetChanged(); 340: } 341: 342: /** 343: * Returns whether the interval width is automatically calculated or not. 344: * 345: * @return whether the width is automatically calculated or not. 346: */ 347: public boolean isAutoWidth() { 348: return this.intervalDelegate.isAutoWidth(); 349: } 350: 351: /** 352: * Sets the flag that indicates whether the interval width is automatically 353: * calculated or not. 354: * 355: * @param b the flag. 356: */ 357: public void setAutoWidth(boolean b) { 358: this.intervalDelegate.setAutoWidth(b); 359: fireDatasetChanged(); 360: } 361: 362: /** 363: * Tests this dataset for equality with an arbitrary object. 364: * 365: * @param obj the object (<code>null</code> permitted). 366: * 367: * @return A boolean. 368: */ 369: public boolean equals(Object obj) { 370: if (!(obj instanceof CategoryTableXYDataset)) { 371: return false; 372: } 373: CategoryTableXYDataset that = (CategoryTableXYDataset) obj; 374: if (!this.intervalDelegate.equals(that.intervalDelegate)) { 375: return false; 376: } 377: if (!this.values.equals(that.values)) { 378: return false; 379: } 380: return true; 381: } 382: 383: /** 384: * Returns an independent copy of this dataset. 385: * 386: * @return A clone. 387: * 388: * @throws CloneNotSupportedException if there is some reason that cloning 389: * cannot be performed. 390: */ 391: public Object clone() throws CloneNotSupportedException { 392: CategoryTableXYDataset clone = (CategoryTableXYDataset) super.clone(); 393: clone.values = (DefaultKeyedValues2D) this.values.clone(); 394: clone.intervalDelegate = new IntervalXYDelegate(clone); 395: // need to configure the intervalDelegate to match the original 396: clone.intervalDelegate.setFixedIntervalWidth(getIntervalWidth()); 397: clone.intervalDelegate.setAutoWidth(isAutoWidth()); 398: clone.intervalDelegate.setIntervalPositionFactor( 399: getIntervalPositionFactor()); 400: return clone; 401: } 402: 403: }