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 }