001 /* =========================================================== 002 * JFreeChart : a free chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors. 006 * 007 * Project Info: http://www.jfree.org/jfreechart/index.html 008 * 009 * This library is free software; you can redistribute it and/or modify it 010 * under the terms of the GNU Lesser General Public License as published by 011 * the Free Software Foundation; either version 2.1 of the License, or 012 * (at your option) any later version. 013 * 014 * This library is distributed in the hope that it will be useful, but 015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 017 * License for more details. 018 * 019 * You should have received a copy of the GNU Lesser General Public 020 * License along with this library; if not, write to the Free Software 021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 022 * USA. 023 * 024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 025 * in the United States and other countries.] 026 * 027 * ----------------------- 028 * DefaultKeyedValues.java 029 * ----------------------- 030 * (C) Copyright 2002-2005, by Object Refinery Limited. 031 * 032 * Original Author: David Gilbert (for Object Refinery Limited); 033 * Contributor(s): -; 034 * 035 * $Id: DefaultKeyedValues.java,v 1.8.2.2 2005/10/25 21:29:13 mungady Exp $ 036 * 037 * Changes: 038 * -------- 039 * 31-Oct-2002 : Version 1 (DG); 040 * 11-Feb-2003 : Fixed bug in getValue(key) method for unrecognised key (DG); 041 * 05-Mar-2003 : Added methods to sort stored data 'by key' or 'by value' (DG); 042 * 13-Mar-2003 : Implemented Serializable (DG); 043 * 08-Apr-2003 : Modified removeValue(Comparable) method to fix bug 717049 (DG); 044 * 18-Aug-2003 : Implemented Cloneable (DG); 045 * 27-Aug-2003 : Moved SortOrder from org.jfree.data --> org.jfree.util (DG); 046 * 09-Feb-2004 : Modified getIndex() method - see bug report 893256 (DG); 047 * 15-Sep-2004 : Updated clone() method and added PublicCloneable 048 * interface (DG); 049 * 25-Nov-2004 : Small update to the clone() implementation (DG); 050 * 24-Feb-2005 : Added methods addValue(Comparable, double) and 051 * setValue(Comparable, double) for convenience (DG); 052 * 053 */ 054 055 package org.jfree.data; 056 057 import java.io.Serializable; 058 import java.util.Collections; 059 import java.util.Comparator; 060 import java.util.Iterator; 061 import java.util.List; 062 063 import org.jfree.util.ObjectUtilities; 064 import org.jfree.util.PublicCloneable; 065 import org.jfree.util.SortOrder; 066 067 /** 068 * An ordered list of (key, value) items. This class provides a default 069 * implementation of the {@link KeyedValues} interface. 070 */ 071 public class DefaultKeyedValues implements KeyedValues, 072 Cloneable, PublicCloneable, 073 Serializable { 074 075 /** For serialization. */ 076 private static final long serialVersionUID = 8468154364608194797L; 077 078 /** Storage for the data. */ 079 private List data; 080 081 /** 082 * Creates a new collection (initially empty). 083 */ 084 public DefaultKeyedValues() { 085 this.data = new java.util.ArrayList(); 086 } 087 088 /** 089 * Returns the number of items (values) in the collection. 090 * 091 * @return The item count. 092 */ 093 public int getItemCount() { 094 return this.data.size(); 095 } 096 097 /** 098 * Returns a value. 099 * 100 * @param item the item of interest (zero-based index). 101 * 102 * @return The value. 103 * 104 * @throws IndexOutOfBoundsException if <code>item</code> is out of bounds. 105 */ 106 public Number getValue(int item) { 107 Number result = null; 108 KeyedValue kval = (KeyedValue) this.data.get(item); 109 if (kval != null) { 110 result = kval.getValue(); 111 } 112 return result; 113 } 114 115 /** 116 * Returns a key. 117 * 118 * @param index the item index (zero-based). 119 * 120 * @return The row key. 121 * 122 * @throws IndexOutOfBoundsException if <code>item</code> is out of bounds. 123 */ 124 public Comparable getKey(int index) { 125 Comparable result = null; 126 KeyedValue item = (KeyedValue) this.data.get(index); 127 if (item != null) { 128 result = item.getKey(); 129 } 130 return result; 131 } 132 133 /** 134 * Returns the index for a given key. 135 * 136 * @param key the key. 137 * 138 * @return The index, or <code>-1</code> if the key is unrecognised. 139 */ 140 public int getIndex(Comparable key) { 141 int i = 0; 142 Iterator iterator = this.data.iterator(); 143 while (iterator.hasNext()) { 144 KeyedValue kv = (KeyedValue) iterator.next(); 145 if (kv.getKey().equals(key)) { 146 return i; 147 } 148 i++; 149 } 150 return -1; // key not found 151 } 152 153 /** 154 * Returns the keys for the values in the collection. 155 * 156 * @return The keys (never <code>null</code>). 157 */ 158 public List getKeys() { 159 List result = new java.util.ArrayList(); 160 Iterator iterator = this.data.iterator(); 161 while (iterator.hasNext()) { 162 KeyedValue kv = (KeyedValue) iterator.next(); 163 result.add(kv.getKey()); 164 } 165 return result; 166 } 167 168 /** 169 * Returns the value for a given key. 170 * 171 * @param key the key. 172 * 173 * @return The value (possibly <code>null</code>). 174 * 175 * @throws UnknownKeyException if the key is not recognised. 176 */ 177 public Number getValue(Comparable key) { 178 int index = getIndex(key); 179 if (index < 0) { 180 throw new UnknownKeyException("Key not found: " + key); 181 } 182 return getValue(index); 183 } 184 185 /** 186 * Updates an existing value, or adds a new value to the collection. 187 * 188 * @param key the key (<code>null</code> not permitted). 189 * @param value the value. 190 */ 191 public void addValue(Comparable key, double value) { 192 addValue(key, new Double(value)); 193 } 194 195 /** 196 * Adds a new value to the collection, or updates an existing value. 197 * This method passes control directly to the 198 * {@link #setValue(Comparable, Number)} method. 199 * 200 * @param key the key (<code>null</code> not permitted). 201 * @param value the value (<code>null</code> permitted). 202 */ 203 public void addValue(Comparable key, Number value) { 204 setValue(key, value); 205 } 206 207 /** 208 * Updates an existing value, or adds a new value to the collection. 209 * 210 * @param key the key (<code>null</code> not permitted). 211 * @param value the value. 212 */ 213 public void setValue(Comparable key, double value) { 214 setValue(key, new Double(value)); 215 } 216 217 /** 218 * Updates an existing value, or adds a new value to the collection. 219 * 220 * @param key the key (<code>null</code> not permitted). 221 * @param value the value (<code>null</code> permitted). 222 */ 223 public void setValue(Comparable key, Number value) { 224 if (key == null) { 225 throw new IllegalArgumentException("Null 'key' argument."); 226 } 227 int keyIndex = getIndex(key); 228 if (keyIndex >= 0) { 229 DefaultKeyedValue kv = (DefaultKeyedValue) this.data.get(keyIndex); 230 kv.setValue(value); 231 } 232 else { 233 KeyedValue kv = new DefaultKeyedValue(key, value); 234 this.data.add(kv); 235 } 236 } 237 238 /** 239 * Removes a value from the collection. 240 * 241 * @param index the index of the item to remove. 242 */ 243 public void removeValue(int index) { 244 this.data.remove(index); 245 } 246 247 /** 248 * Removes a value from the collection. If there is no item with the 249 * specified key, this method does nothing. 250 * 251 * @param key the item key. 252 */ 253 public void removeValue(Comparable key) { 254 int index = getIndex(key); 255 if (index >= 0) { 256 removeValue(index); 257 } 258 } 259 260 /** 261 * Sorts the items in the list by key. 262 * 263 * @param order the sort order (<code>null</code> not permitted). 264 */ 265 public void sortByKeys(SortOrder order) { 266 Comparator comparator = new KeyedValueComparator( 267 KeyedValueComparatorType.BY_KEY, order 268 ); 269 Collections.sort(this.data, comparator); 270 } 271 272 /** 273 * Sorts the items in the list by value. If the list contains 274 * <code>null</code> values, they will sort to the end of the list, 275 * irrespective of the sort order. 276 * 277 * @param order the sort order (<code>null</code> not permitted). 278 */ 279 public void sortByValues(SortOrder order) { 280 Comparator comparator = new KeyedValueComparator( 281 KeyedValueComparatorType.BY_VALUE, order 282 ); 283 Collections.sort(this.data, comparator); 284 } 285 286 /** 287 * Tests if this object is equal to another. 288 * 289 * @param obj the object (<code>null</code> permitted). 290 * 291 * @return A boolean. 292 */ 293 public boolean equals(Object obj) { 294 if (obj == this) { 295 return true; 296 } 297 298 if (!(obj instanceof KeyedValues)) { 299 return false; 300 } 301 302 KeyedValues that = (KeyedValues) obj; 303 int count = getItemCount(); 304 if (count != that.getItemCount()) { 305 return false; 306 } 307 308 for (int i = 0; i < count; i++) { 309 Comparable k1 = getKey(i); 310 Comparable k2 = that.getKey(i); 311 if (!k1.equals(k2)) { 312 return false; 313 } 314 Number v1 = getValue(i); 315 Number v2 = that.getValue(i); 316 if (v1 == null) { 317 if (v2 != null) { 318 return false; 319 } 320 } 321 else { 322 if (!v1.equals(v2)) { 323 return false; 324 } 325 } 326 } 327 return true; 328 } 329 330 /** 331 * Returns a hash code. 332 * 333 * @return A hash code. 334 */ 335 public int hashCode() { 336 return (this.data != null ? this.data.hashCode() : 0); 337 } 338 339 /** 340 * Returns a clone. 341 * 342 * @return A clone. 343 * 344 * @throws CloneNotSupportedException this class will not throw this 345 * exception, but subclasses might. 346 */ 347 public Object clone() throws CloneNotSupportedException { 348 DefaultKeyedValues clone = (DefaultKeyedValues) super.clone(); 349 clone.data = (List) ObjectUtilities.deepClone(this.data); 350 return clone; 351 } 352 353 }