Source for org.jfree.data.DefaultKeyedValues

   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:  * DefaultKeyedValues.java
  29:  * -----------------------
  30:  * (C) Copyright 2002-2006, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * $Id: DefaultKeyedValues.java,v 1.8.2.5 2006/11/16 14:41:25 mungady Exp $
  36:  *
  37:  * Changes:
  38:  * --------
  39:  * 31-Oct-2002 : Version 1 (DG);
  40:  * 11-Feb-2003 : Fixed bug in getValue(key) method for unrecognised key (DG);
  41:  * 05-Mar-2003 : Added methods to sort stored data 'by key' or 'by value' (DG);
  42:  * 13-Mar-2003 : Implemented Serializable (DG);
  43:  * 08-Apr-2003 : Modified removeValue(Comparable) method to fix bug 717049 (DG);
  44:  * 18-Aug-2003 : Implemented Cloneable (DG);
  45:  * 27-Aug-2003 : Moved SortOrder from org.jfree.data --> org.jfree.util (DG);
  46:  * 09-Feb-2004 : Modified getIndex() method - see bug report 893256 (DG);
  47:  * 15-Sep-2004 : Updated clone() method and added PublicCloneable 
  48:  *               interface (DG);
  49:  * 25-Nov-2004 : Small update to the clone() implementation (DG);
  50:  * 24-Feb-2005 : Added methods addValue(Comparable, double) and 
  51:  *               setValue(Comparable, double) for convenience (DG);
  52:  * ------------- JFREECHART 1.0.0 -----------------------------------------------
  53:  * 31-Jul-2006 : Added a clear() method (DG);
  54:  * 01-Aug-2006 : Added argument check to getIndex() method (DG);
  55:  *
  56:  */
  57: 
  58: package org.jfree.data;
  59: 
  60: import java.io.Serializable;
  61: import java.util.Collections;
  62: import java.util.Comparator;
  63: import java.util.Iterator;
  64: import java.util.List;
  65: 
  66: import org.jfree.util.ObjectUtilities;
  67: import org.jfree.util.PublicCloneable;
  68: import org.jfree.util.SortOrder;
  69: 
  70: /**
  71:  * An ordered list of (key, value) items.  This class provides a default 
  72:  * implementation of the {@link KeyedValues} interface.
  73:  */
  74: public class DefaultKeyedValues implements KeyedValues, 
  75:                                            Cloneable, PublicCloneable, 
  76:                                            Serializable {
  77: 
  78:     /** For serialization. */
  79:     private static final long serialVersionUID = 8468154364608194797L;
  80:     
  81:     /** Storage for the data. */
  82:     private List data;
  83: 
  84:     /**
  85:      * Creates a new collection (initially empty).
  86:      */
  87:     public DefaultKeyedValues() {
  88:         this.data = new java.util.ArrayList();
  89:     }
  90: 
  91:     /**
  92:      * Returns the number of items (values) in the collection.
  93:      *
  94:      * @return The item count.
  95:      */
  96:     public int getItemCount() {
  97:         return this.data.size();
  98:     }
  99: 
 100:     /**
 101:      * Returns a value.
 102:      *
 103:      * @param item  the item of interest (zero-based index).
 104:      *
 105:      * @return The value.
 106:      * 
 107:      * @throws IndexOutOfBoundsException if <code>item</code> is out of bounds.
 108:      */
 109:     public Number getValue(int item) {
 110:         Number result = null;
 111:         KeyedValue kval = (KeyedValue) this.data.get(item);
 112:         if (kval != null) {
 113:             result = kval.getValue();
 114:         }
 115:         return result;
 116:     }
 117: 
 118:     /**
 119:      * Returns a key.
 120:      *
 121:      * @param index  the item index (zero-based).
 122:      *
 123:      * @return The row key.
 124:      * 
 125:      * @throws IndexOutOfBoundsException if <code>item</code> is out of bounds.
 126:      */
 127:     public Comparable getKey(int index) {
 128:         Comparable result = null;
 129:         KeyedValue item = (KeyedValue) this.data.get(index);
 130:         if (item != null) {
 131:             result = item.getKey();
 132:         }
 133:         return result;
 134:     }
 135: 
 136:     /**
 137:      * Returns the index for a given key.
 138:      *
 139:      * @param key  the key (<code>null</code> not permitted).
 140:      *
 141:      * @return The index, or <code>-1</code> if the key is not recognised.
 142:      * 
 143:      * @throws IllegalArgumentException if <code>key</code> is 
 144:      *     <code>null</code>.
 145:      */
 146:     public int getIndex(Comparable key) {
 147:         if (key == null) {
 148:             throw new IllegalArgumentException("Null 'key' argument.");
 149:         }
 150:         int i = 0;
 151:         Iterator iterator = this.data.iterator();
 152:         while (iterator.hasNext()) {
 153:             KeyedValue kv = (KeyedValue) iterator.next();
 154:             if (kv.getKey().equals(key)) {
 155:                 return i;
 156:             }
 157:             i++;
 158:         }
 159:         return -1;  // key not found
 160:     }
 161: 
 162:     /**
 163:      * Returns the keys for the values in the collection.
 164:      *
 165:      * @return The keys (never <code>null</code>).
 166:      */
 167:     public List getKeys() {
 168:         List result = new java.util.ArrayList();
 169:         Iterator iterator = this.data.iterator();
 170:         while (iterator.hasNext()) {
 171:             KeyedValue kv = (KeyedValue) iterator.next();
 172:             result.add(kv.getKey());
 173:         }
 174:         return result;
 175:     }
 176: 
 177:     /**
 178:      * Returns the value for a given key.
 179:      *
 180:      * @param key  the key.
 181:      *
 182:      * @return The value (possibly <code>null</code>).
 183:      * 
 184:      * @throws UnknownKeyException if the key is not recognised.
 185:      */
 186:     public Number getValue(Comparable key) {
 187:         int index = getIndex(key);
 188:         if (index < 0) {
 189:             throw new UnknownKeyException("Key not found: " + key);
 190:         }
 191:         return getValue(index);
 192:     }
 193: 
 194:     /**
 195:      * Updates an existing value, or adds a new value to the collection.
 196:      *
 197:      * @param key  the key (<code>null</code> not permitted).
 198:      * @param value  the value.
 199:      */
 200:     public void addValue(Comparable key, double value) {
 201:         addValue(key, new Double(value)); 
 202:     }
 203:     
 204:     /**
 205:      * Adds a new value to the collection, or updates an existing value.
 206:      * This method passes control directly to the 
 207:      * {@link #setValue(Comparable, Number)} method.
 208:      *
 209:      * @param key  the key (<code>null</code> not permitted).
 210:      * @param value  the value (<code>null</code> permitted).
 211:      */
 212:     public void addValue(Comparable key, Number value) {
 213:         setValue(key, value);
 214:     }
 215: 
 216:     /**
 217:      * Updates an existing value, or adds a new value to the collection.
 218:      *
 219:      * @param key  the key (<code>null</code> not permitted).
 220:      * @param value  the value.
 221:      */
 222:     public void setValue(Comparable key, double value) {
 223:         setValue(key, new Double(value));   
 224:     }
 225:     
 226:     /**
 227:      * Updates an existing value, or adds a new value to the collection.
 228:      *
 229:      * @param key  the key (<code>null</code> not permitted).
 230:      * @param value  the value (<code>null</code> permitted).
 231:      */
 232:     public void setValue(Comparable key, Number value) {
 233:         if (key == null) {
 234:             throw new IllegalArgumentException("Null 'key' argument.");
 235:         }
 236:         int keyIndex = getIndex(key);
 237:         if (keyIndex >= 0) {
 238:             DefaultKeyedValue kv = (DefaultKeyedValue) this.data.get(keyIndex);
 239:             kv.setValue(value);
 240:         }
 241:         else {
 242:             KeyedValue kv = new DefaultKeyedValue(key, value);
 243:             this.data.add(kv);
 244:         }
 245:     }
 246: 
 247:     /**
 248:      * Removes a value from the collection.
 249:      *
 250:      * @param index  the index of the item to remove (in the range 
 251:      *     <code>0</code> to <code>getItemCount() - 1</code>).
 252:      *     
 253:      * @throws IndexOutOfBoundsException if <code>index</code> is not within
 254:      *     the specified range.
 255:      */
 256:     public void removeValue(int index) {
 257:         this.data.remove(index);
 258:     }
 259: 
 260:     /**
 261:      * Removes a value from the collection.  If there is no item with the 
 262:      * specified key, this method does nothing.
 263:      *
 264:      * @param key  the item key (<code>null</code> not permitted).
 265:      * 
 266:      * @throws IllegalArgumentException if <code>key</code> is 
 267:      *     <code>null</code>.
 268:      */
 269:     public void removeValue(Comparable key) {
 270:         int index = getIndex(key);
 271:         if (index >= 0) {
 272:             removeValue(index);
 273:         }
 274:     }
 275:     
 276:     /**
 277:      * Clears all values from the collection.
 278:      * 
 279:      * @since 1.0.2
 280:      */
 281:     public void clear() {
 282:         this.data.clear();
 283:     }
 284: 
 285:     /**
 286:      * Sorts the items in the list by key.
 287:      *
 288:      * @param order  the sort order (<code>null</code> not permitted).
 289:      */
 290:     public void sortByKeys(SortOrder order) {
 291:         Comparator comparator = new KeyedValueComparator(
 292:                 KeyedValueComparatorType.BY_KEY, order);
 293:         Collections.sort(this.data, comparator);
 294:     }
 295: 
 296:     /**
 297:      * Sorts the items in the list by value.  If the list contains 
 298:      * <code>null</code> values, they will sort to the end of the list, 
 299:      * irrespective of the sort order.
 300:      *
 301:      * @param order  the sort order (<code>null</code> not permitted).
 302:      */
 303:     public void sortByValues(SortOrder order) {
 304:         Comparator comparator = new KeyedValueComparator(
 305:                 KeyedValueComparatorType.BY_VALUE, order);
 306:         Collections.sort(this.data, comparator);
 307:     }
 308: 
 309:     /**
 310:      * Tests if this object is equal to another.
 311:      *
 312:      * @param obj  the object (<code>null</code> permitted).
 313:      *
 314:      * @return A boolean.
 315:      */
 316:     public boolean equals(Object obj) {
 317:         if (obj == this) {
 318:             return true;
 319:         }
 320: 
 321:         if (!(obj instanceof KeyedValues)) {
 322:             return false;
 323:         }
 324: 
 325:         KeyedValues that = (KeyedValues) obj;
 326:         int count = getItemCount();
 327:         if (count != that.getItemCount()) {
 328:             return false;
 329:         }
 330: 
 331:         for (int i = 0; i < count; i++) {
 332:             Comparable k1 = getKey(i);
 333:             Comparable k2 = that.getKey(i);
 334:             if (!k1.equals(k2)) {
 335:                 return false;
 336:             }
 337:             Number v1 = getValue(i);
 338:             Number v2 = that.getValue(i);
 339:             if (v1 == null) {
 340:                 if (v2 != null) {
 341:                     return false;
 342:                 }
 343:             }
 344:             else {
 345:                 if (!v1.equals(v2)) {
 346:                     return false;
 347:                 }
 348:             }
 349:         }
 350:         return true;
 351:     }
 352: 
 353:     /**
 354:      * Returns a hash code.
 355:      * 
 356:      * @return A hash code.
 357:      */
 358:     public int hashCode() {
 359:         return (this.data != null ? this.data.hashCode() : 0);
 360:     }
 361: 
 362:     /**
 363:      * Returns a clone.
 364:      * 
 365:      * @return A clone.
 366:      * 
 367:      * @throws CloneNotSupportedException  this class will not throw this 
 368:      *         exception, but subclasses might.
 369:      */
 370:     public Object clone() throws CloneNotSupportedException {
 371:         DefaultKeyedValues clone = (DefaultKeyedValues) super.clone();
 372:         clone.data = (List) ObjectUtilities.deepClone(this.data);
 373:         return clone;    
 374:     }
 375:     
 376: }