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 }