Frames | No Frames |
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: }