    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     * KeyedObject2D.java
    029     * ------------------
    030     * (C) Copyright 2003-2005, by Object Refinery Limited.
    031     *
    032     * Original Author:  David Gilbert (for Object Refinery Limited);
    033     * Contributor(s):   -;
    034     *
    035     * $Id: KeyedObjects2D.java,v 1.6.2.1 2005/10/25 21:29:13 mungady Exp $
    036     *
    037     * Changes
    038     * -------
    039     * 05-Feb-2003 : Version 1 (DG);
    040     * 01-Mar-2004 : Added equals() and clone() methods and implemented
    041     *               Serializable (DG);
    042     *
    043     */
    044
    045    package org.jfree.data;
    046
    047    import java.io.Serializable;
    048    import java.util.Collections;
    049    import java.util.Iterator;
    050    import java.util.List;
    051
    052
    053    /**
    054     * A data structure that stores zero, one or many objects, where each object is
    055     * associated with two keys (a 'row' key and a 'column' key).
    056     */
    057    public class KeyedObjects2D implements Cloneable, Serializable {
    058
    059        /** For serialization. */
    060        private static final long serialVersionUID = -1015873563138522374L;
    061
    062        /** The row keys. */
    063        private List rowKeys;
    064
    065        /** The column keys. */
    066        private List columnKeys;
    067
    068        /** The row data. */
    069        private List rows;
    070
    071        /**
    072         * Creates a new instance (initially empty).
    073         */
    074        public KeyedObjects2D() {
    075            this.rowKeys = new java.util.ArrayList();
    076            this.columnKeys = new java.util.ArrayList();
    077            this.rows = new java.util.ArrayList();
    078        }
    079
    080        /**
    081         * Returns the row count.
    082         *
    083         * @return The row count.
    084         */
    085        public int getRowCount() {
    086            return this.rowKeys.size();
    087        }
    088
    089        /**
    090         * Returns the column count.
    091         *
    092         * @return The column count.
    093         */
    094        public int getColumnCount() {
    095            return this.columnKeys.size();
    096        }
    097
    098        /**
    099         * Returns the object for a given row and column.
    100         *
    101         * @param row  the row index.
    102         * @param column  the column index.
    103         *
    104         * @return The object.
    105         */
    106        public Object getObject(int row, int column) {
    107
    108            Object result = null;
    109            KeyedObjects rowData = (KeyedObjects) this.rows.get(row);
    110            if (rowData != null) {
    111                Comparable columnKey = (Comparable) this.columnKeys.get(column);
    112                if (columnKey != null) {
    113                    result = rowData.getObject(columnKey);
    114                }
    115            }
    116            return result;
    117
    118        }
    119
    120        /**
    121         * Returns the key for a given row.
    122         *
    123         * @param row  the row index (zero based).
    124         *
    125         * @return The row index.
    126         */
    127        public Comparable getRowKey(int row) {
    128            return (Comparable) this.rowKeys.get(row);
    129        }
    130
    131        /**
    132         * Returns the row index for a given key.
    133         *
    134         * @param key  the key.
    135         *
    136         * @return The row index.
    137         */
    138        public int getRowIndex(Comparable key) {
    139            return this.rowKeys.indexOf(key);
    140        }
    141
    142        /**
    143         * Returns the row keys.
    144         *
    145         * @return The row keys (never <code>null</code>).
    146         */
    147        public List getRowKeys() {
    148            return Collections.unmodifiableList(this.rowKeys);
    149        }
    150
    151        /**
    152         * Returns the key for a given column.
    153         *
    154         * @param column  the column.
    155         *
    156         * @return The key.
    157         */
    158        public Comparable getColumnKey(int column) {
    159            return (Comparable) this.columnKeys.get(column);
    160        }
    161
    162        /**
    163         * Returns the column index for a given key.
    164         *
    165         * @param key  the key.
    166         *
    167         * @return The column index.
    168         */
    169        public int getColumnIndex(Comparable key) {
    170            return this.columnKeys.indexOf(key);
    171        }
    172
    173        /**
    174         * Returns the column keys.
    175         *
    176         * @return The column keys (never <code>null</code>).
    177         */
    178        public List getColumnKeys() {
    179            return Collections.unmodifiableList(this.columnKeys);
    180        }
    181
    182        /**
    183         * Returns the object for the given row and column keys.
    184         *
    185         * @param rowKey  the row key.
    186         * @param columnKey  the column key.
    187         *
    188         * @return The object.
    189         */
    190        public Object getObject(Comparable rowKey, Comparable columnKey) {
    191
    192            Object result = null;
    193            int row = this.rowKeys.indexOf(rowKey);
    194            if (row >= 0) {
    195                KeyedObjects rowData = (KeyedObjects) this.rows.get(row);
    196                result = rowData.getObject(columnKey);
    197            }
    198            return result;
    199
    200        }
    201
    202        /**
    203         * Adds an object to the table.  Performs the same function as setObject().
    204         *
    205         * @param object  the object.
    206         * @param rowKey  the row key.
    207         * @param columnKey  the column key.
    208         */
    209        public void addObject(Object object,
    210                              Comparable rowKey,
    211                              Comparable columnKey) {
    212            setObject(object, rowKey, columnKey);
    213        }
    214
    215        /**
    216         * Adds or updates an object.
    217         *
    218         * @param object  the object.
    219         * @param rowKey  the row key.
    220         * @param columnKey  the column key.
    221         */
    222        public void setObject(Object object,
    223                              Comparable rowKey,
    224                              Comparable columnKey) {
    225
    226            KeyedObjects row;
    227            int rowIndex = this.rowKeys.indexOf(rowKey);
    228            if (rowIndex >= 0) {
    229                row = (KeyedObjects) this.rows.get(rowIndex);
    230            }
    231            else {
    232                this.rowKeys.add(rowKey);
    233                row = new KeyedObjects();
    234                this.rows.add(row);
    235            }
    236            row.setObject(columnKey, object);
    237            int columnIndex = this.columnKeys.indexOf(columnKey);
    238            if (columnIndex < 0) {
    239                this.columnKeys.add(columnKey);
    240            }
    241
    242        }
    243
    244        /**
    245         * Removes an object.
    246         *
    247         * @param rowKey  the row key.
    248         * @param columnKey  the column key.
    249         */
    250        public void removeObject(Comparable rowKey, Comparable columnKey) {
    251            setObject(null, rowKey, columnKey);
    252            // actually, a null value is different to a value that doesn't exist
    253            // at all, need to fix this code.
    254        }
    255
    256        /**
    257         * Removes a row.
    258         *
    259         * @param rowIndex  the row index.
    260         */
    261        public void removeRow(int rowIndex) {
    262            this.rowKeys.remove(rowIndex);
    263            this.rows.remove(rowIndex);
    264        }
    265
    266        /**
    267         * Removes a row.
    268         *
    269         * @param rowKey  the row key.
    270         */
    271        public void removeRow(Comparable rowKey) {
    272            removeRow(getRowIndex(rowKey));
    273        }
    274
    275        /**
    276         * Removes a column.
    277         *
    278         * @param columnIndex  the column index.
    279         */
    280        public void removeColumn(int columnIndex) {
    281            Comparable columnKey = getColumnKey(columnIndex);
    282            removeColumn(columnKey);
    283        }
    284
    285        /**
    286         * Removes a column.
    287         *
    288         * @param columnKey  the column key.
    289         */
    290        public void removeColumn(Comparable columnKey) {
    291            Iterator iterator = this.rows.iterator();
    292            while (iterator.hasNext()) {
    293                KeyedObjects rowData = (KeyedObjects) iterator.next();
    294                rowData.removeValue(columnKey);
    295            }
    296            this.columnKeys.remove(columnKey);
    297        }
    298
    299        /**
    300         * Tests this object for equality with an arbitrary object.
    301         *
    302         * @param obj  the object to test (<code>null</code> permitted).
    303         *
    304         * @return A boolean.
    305         */
    306        public boolean equals(Object obj) {
    307
    308            if (obj == null) {
    309                return false;
    310            }
    311
    312            if (obj == this) {
    313                return true;
    314            }
    315
    316            if (!(obj instanceof KeyedObjects2D)) {
    317                return false;
    318            }
    319
    320            KeyedObjects2D ko2D = (KeyedObjects2D) obj;
    321            if (!getRowKeys().equals(ko2D.getRowKeys())) {
    322                return false;
    323            }
    324            if (!getColumnKeys().equals(ko2D.getColumnKeys())) {
    325                return false;
    326            }
    327            int rowCount = getRowCount();
    328            if (rowCount != ko2D.getRowCount()) {
    329                return false;
    330            }
    331
    332            int colCount = getColumnCount();
    333            if (colCount != ko2D.getColumnCount()) {
    334                return false;
    335            }
    336
    337            for (int r = 0; r < rowCount; r++) {
    338                for (int c = 0; c < colCount; c++) {
    339                    Object v1 = getObject(r, c);
    340                    Object v2 = ko2D.getObject(r, c);
    341                    if (v1 == null) {
    342                        if (v2 != null) {
    343                            return false;
    344                        }
    345                    }
    346                    else {
    347                        if (!v1.equals(v2)) {
    348                            return false;
    349                        }
    350                    }
    351                }
    352            }
    353            return true;
    354        }
    355
    356        /**
    357         * Returns a hashcode for this object.
    358         *
    359         * @return A hashcode.
    360         */
    361        public int hashCode() {
    362            int result;
    363            result = this.rowKeys.hashCode();
    364            result = 29 * result + this.columnKeys.hashCode();
    365            result = 29 * result + this.rows.hashCode();
    366            return result;
    367        }
    368
    369        /**
    370         * Returns a clone.
    371         *
    372         * @return A clone.
    373         *
    374         * @throws CloneNotSupportedException  this class will not throw this
    375         *         exception, but subclasses (if any) might.
    376         */
    377        public Object clone() throws CloneNotSupportedException {
    378            return super.clone();
    379        }
    380
    381    }