Source for org.jfree.data.general.DefaultPieDataset

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2006, 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:  * DefaultPieDataset.java
  29:  * ----------------------
  30:  * (C) Copyright 2001-2006, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   Sam (oldman);
  34:  *
  35:  * $Id: DefaultPieDataset.java,v 1.6.2.5 2006/09/28 13:41:15 mungady Exp $
  36:  *
  37:  * Changes
  38:  * -------
  39:  * 17-Nov-2001 : Version 1 (DG);
  40:  * 22-Jan-2002 : Removed legend methods from dataset implementations (DG);
  41:  * 07-Apr-2002 : Modified implementation to guarantee data sequence to remain 
  42:  *               in the order categories are added (oldman);
  43:  * 23-Oct-2002 : Added getCategory(int) method and getItemCount() method, in 
  44:  *               line with changes to the PieDataset interface (DG);
  45:  * 04-Feb-2003 : Changed underlying data storage to DefaultKeyedValues (DG);
  46:  * 04-Mar-2003 : Inserted DefaultKeyedValuesDataset class into hierarchy (DG);
  47:  * 24-Apr-2003 : Switched places with DefaultKeyedValuesDataset (DG);
  48:  * 18-Aug-2003 : Implemented Cloneable (DG);
  49:  * 03-Mar-2005 : Implemented PublicCloneable (DG);
  50:  * 29-Jun-2005 : Added remove() method (DG);
  51:  * ------------- JFREECHART 1.0.0 ---------------------------------------------
  52:  * 31-Jul-2006 : Added a clear() method to clear all values from the 
  53:  *               dataset (DG);
  54:  * 28-Sep-2006 : Added sortByKeys() and sortByValues() methods (DG);
  55:  * 
  56:  */
  57: 
  58: package org.jfree.data.general;
  59: 
  60: import java.io.Serializable;
  61: import java.util.Collections;
  62: import java.util.List;
  63: 
  64: import org.jfree.data.DefaultKeyedValues;
  65: import org.jfree.data.KeyedValues;
  66: import org.jfree.data.UnknownKeyException;
  67: import org.jfree.util.PublicCloneable;
  68: import org.jfree.util.SortOrder;
  69: 
  70: /**
  71:  * A default implementation of the {@link PieDataset} interface.
  72:  */
  73: public class DefaultPieDataset extends AbstractDataset
  74:                                implements PieDataset, 
  75:                                           Cloneable, PublicCloneable, 
  76:                                           Serializable {
  77: 
  78:     /** For serialization. */
  79:     private static final long serialVersionUID = 2904745139106540618L;
  80:     
  81:     /** Storage for the data. */
  82:     private DefaultKeyedValues data;
  83: 
  84:     /**
  85:      * Constructs a new dataset, initially empty.
  86:      */
  87:     public DefaultPieDataset() {
  88:         this.data = new DefaultKeyedValues();
  89:     }
  90: 
  91:     /**
  92:      * Creates a new dataset by copying data from a {@link KeyedValues} 
  93:      * instance.
  94:      *
  95:      * @param data  the data (<code>null</code> not permitted).
  96:      */
  97:     public DefaultPieDataset(KeyedValues data) {
  98:         if (data == null) {
  99:             throw new IllegalArgumentException("Null 'data' argument.");   
 100:         }
 101:         this.data = new DefaultKeyedValues();
 102:         for (int i = 0; i < data.getItemCount(); i++) {
 103:             this.data.addValue(data.getKey(i), data.getValue(i));
 104:         }
 105:     }
 106: 
 107:     /**
 108:      * Returns the number of items in the dataset.
 109:      *
 110:      * @return The item count.
 111:      */
 112:     public int getItemCount() {
 113:         return this.data.getItemCount();
 114:     }
 115: 
 116:     /**
 117:      * Returns the categories in the dataset.  The returned list is 
 118:      * unmodifiable.
 119:      *
 120:      * @return The categories in the dataset.
 121:      */
 122:     public List getKeys() {
 123:         return Collections.unmodifiableList(this.data.getKeys());
 124:     }
 125: 
 126:     /**
 127:      * Returns the key for the specified item, or <code>null</code>. 
 128:      *
 129:      * @param item  the item index (in the range <code>0</code> to 
 130:      *     <code>getItemCount() - 1</code>).
 131:      *
 132:      * @return The key, or <code>null</code>.
 133:      * 
 134:      * @throws IndexOutOfBoundsException if <code>item</code> is not in the
 135:      *     specified range.
 136:      */
 137:     public Comparable getKey(int item) {
 138:         return this.data.getKey(item);
 139:     }
 140: 
 141:     /**
 142:      * Returns the index for a key, or -1 if the key is not recognised.
 143:      *
 144:      * @param key  the key (<code>null</code> not permitted).
 145:      *
 146:      * @return The index, or <code>-1</code> if the key is unrecognised.
 147:      * 
 148:      * @throws IllegalArgumentException if <code>key</code> is 
 149:      *     <code>null</code>.
 150:      */
 151:     public int getIndex(Comparable key) {
 152:         return this.data.getIndex(key);
 153:     }
 154: 
 155:     /**
 156:      * Returns a value.
 157:      *
 158:      * @param item  the value index.
 159:      *
 160:      * @return The value (possibly <code>null</code>).
 161:      */
 162:     public Number getValue(int item) {
 163: 
 164:         Number result = null;
 165:         if (getItemCount() > item) {
 166:             result = this.data.getValue(item);
 167:         }
 168:         return result;
 169: 
 170:     }
 171: 
 172:     /**
 173:      * Returns the data value associated with a key.
 174:      *
 175:      * @param key  the key (<code>null</code> not permitted).
 176:      *
 177:      * @return The value (possibly <code>null</code>).
 178:      * 
 179:      * @throws UnknownKeyException if the key is not recognised.
 180:      */
 181:     public Number getValue(Comparable key) {
 182:         if (key == null) {
 183:             throw new IllegalArgumentException("Null 'key' argument.");
 184:         }
 185:         return this.data.getValue(key);
 186:     }
 187: 
 188:     /**
 189:      * Sets the data value for a key and sends a {@link DatasetChangeEvent} to
 190:      * all registered listeners.
 191:      *
 192:      * @param key  the key (<code>null</code> not permitted).
 193:      * @param value  the value.
 194:      * 
 195:      * @throws IllegalArgumentException if <code>key</code> is 
 196:      *     <code>null</code>.
 197:      */
 198:     public void setValue(Comparable key, Number value) {
 199:         this.data.setValue(key, value);
 200:         fireDatasetChanged();
 201:     }
 202: 
 203:     /**
 204:      * Sets the data value for a key and sends a {@link DatasetChangeEvent} to
 205:      * all registered listeners.
 206:      *
 207:      * @param key  the key (<code>null</code> not permitted).
 208:      * @param value  the value.
 209:      * 
 210:      * @throws IllegalArgumentException if <code>key</code> is 
 211:      *     <code>null</code>.
 212:      */
 213:     public void setValue(Comparable key, double value) {
 214:         setValue(key, new Double(value));
 215:     }
 216:     
 217:     /**
 218:      * Removes an item from the dataset and sends a {@link DatasetChangeEvent}
 219:      * to all registered listeners.
 220:      * 
 221:      * @param key  the key (<code>null</code> not permitted).
 222:      * 
 223:      * @throws IllegalArgumentException if <code>key</code> is 
 224:      *     <code>null</code>.
 225:      */
 226:     public void remove(Comparable key) {
 227:         this.data.removeValue(key);   
 228:         fireDatasetChanged();
 229:     }
 230:     
 231:     /**
 232:      * Clears all data from this dataset and sends a {@link DatasetChangeEvent}
 233:      * to all registered listeners (unless the dataset was already empty).
 234:      * 
 235:      * @since 1.0.2
 236:      */
 237:     public void clear() {
 238:         if (getItemCount() > 0) {
 239:             this.data.clear();
 240:             fireDatasetChanged();
 241:         }
 242:     }
 243: 
 244:     /**
 245:      * Sorts the dataset's items by key and sends a {@link DatasetChangeEvent}
 246:      * to all registered listeners.
 247:      * 
 248:      * @param order  the sort order (<code>null</code> not permitted).
 249:      * 
 250:      * @since 1.0.3
 251:      */
 252:     public void sortByKeys(SortOrder order) {
 253:         this.data.sortByKeys(order);
 254:         fireDatasetChanged();
 255:     }
 256:     
 257:     /**
 258:      * Sorts the dataset's items by value and sends a {@link DatasetChangeEvent}
 259:      * to all registered listeners.
 260:      * 
 261:      * @param order  the sort order (<code>null</code> not permitted).
 262:      * 
 263:      * @since 1.0.3
 264:      */
 265:     public void sortByValues(SortOrder order) {
 266:         this.data.sortByValues(order);
 267:         fireDatasetChanged();
 268:     }
 269: 
 270:     /**
 271:      * Tests if this object is equal to another.
 272:      *
 273:      * @param obj  the other object.
 274:      *
 275:      * @return A boolean.
 276:      */
 277:     public boolean equals(Object obj) {
 278:         if (obj == this) {
 279:             return true;
 280:         }
 281: 
 282:         if (!(obj instanceof PieDataset)) {
 283:             return false;
 284:         }
 285:         PieDataset that = (PieDataset) obj;
 286:         int count = getItemCount();
 287:         if (that.getItemCount() != count) {
 288:             return false;
 289:         }
 290: 
 291:         for (int i = 0; i < count; i++) {
 292:             Comparable k1 = getKey(i);
 293:             Comparable k2 = that.getKey(i);
 294:             if (!k1.equals(k2)) {
 295:                 return false;
 296:             }
 297: 
 298:             Number v1 = getValue(i);
 299:             Number v2 = that.getValue(i);
 300:             if (v1 == null) {
 301:                 if (v2 != null) {
 302:                     return false;
 303:                 }
 304:             }
 305:             else {
 306:                 if (!v1.equals(v2)) {
 307:                     return false;
 308:                 }
 309:             }
 310:         }
 311:         return true;
 312: 
 313:     }
 314: 
 315:     /**
 316:      * Returns a hash code.
 317:      * 
 318:      * @return A hash code.
 319:      */
 320:     public int hashCode() {
 321:         return this.data.hashCode();
 322:     }
 323: 
 324:     /**
 325:      * Returns a clone of the dataset.
 326:      * 
 327:      * @return A clone.
 328:      * 
 329:      * @throws CloneNotSupportedException This class will not throw this 
 330:      *         exception, but subclasses (if any) might.
 331:      */
 332:     public Object clone() throws CloneNotSupportedException {
 333:         DefaultPieDataset clone = (DefaultPieDataset) super.clone();
 334:         clone.data = (DefaultKeyedValues) this.data.clone();
 335:         return clone;    
 336:     }
 337:     
 338: }