    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    }