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