KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > data > DefaultKeyedValues2D


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  * DefaultKeyedValues2D.java
28  * -------------------------
29  * (C) Copyright 2002-2005, by Object Refinery Limited.
30  *
31  * Original Author: David Gilbert (for Object Refinery Limited);
32  * Contributor(s): Andreas Schroeder;
33  *
34  * $Id: DefaultKeyedValues2D.java,v 1.7 2005/05/19 10:34:07 mungady Exp $
35  *
36  * Changes
37  * -------
38  * 28-Oct-2002 : Version 1 (DG);
39  * 21-Jan-2003 : Updated Javadocs (DG);
40  * 13-Mar-2003 : Implemented Serializable (DG);
41  * 18-Aug-2003 : Implemented Cloneable (DG);
42  * 31-Mar-2004 : Made the rows optionally sortable by a flag (AS);
43  * 01-Apr-2004 : Implemented remove method (AS);
44  * 05-Apr-2004 : Added clear() method (DG);
45  * 15-Sep-2004 : Fixed clone() method (DG);
46  * 12-Jan-2005 : Fixed bug in getValue() method (DG);
47  * 23-Mar-2005 : Implemented PublicCloneable (DG);
48  *
49  */

50
51 package org.jfree.data;
52
53 import java.io.Serializable JavaDoc;
54 import java.util.Collections JavaDoc;
55 import java.util.Iterator JavaDoc;
56 import java.util.List JavaDoc;
57
58 import org.jfree.util.ObjectUtilities;
59 import org.jfree.util.PublicCloneable;
60
61 /**
62  * A data structure that stores zero, one or many values, where each value
63  * is associated with two keys (a 'row' key and a 'column' key). The keys
64  * should be (a) instances of {@link Comparable} and (b) immutable.
65  */

66 public class DefaultKeyedValues2D implements KeyedValues2D,
67                                              PublicCloneable, Cloneable JavaDoc,
68                                              Serializable JavaDoc {
69
70     /** For serialization. */
71     private static final long serialVersionUID = -5514169970951994748L;
72     
73     /** The row keys. */
74     private List JavaDoc rowKeys;
75
76     /** The column keys. */
77     private List JavaDoc columnKeys;
78
79     /** The row data. */
80     private List JavaDoc rows;
81     
82     /** If the row keys should be sorted by their comparable order. */
83     private boolean sortRowKeys;
84
85     /**
86      * Creates a new instance (initially empty).
87      */

88     public DefaultKeyedValues2D() {
89         this(false);
90     }
91
92     /**
93      * Creates a new instance (initially empty).
94      *
95      * @param sortRowKeys if the row keys should be sorted.
96      */

97     public DefaultKeyedValues2D(boolean sortRowKeys) {
98         this.rowKeys = new java.util.ArrayList JavaDoc();
99         this.columnKeys = new java.util.ArrayList JavaDoc();
100         this.rows = new java.util.ArrayList JavaDoc();
101         this.sortRowKeys = sortRowKeys;
102     }
103
104     /**
105      * Returns the row count.
106      *
107      * @return The row count.
108      */

109     public int getRowCount() {
110         return this.rowKeys.size();
111     }
112
113     /**
114      * Returns the column count.
115      *
116      * @return The column count.
117      */

118     public int getColumnCount() {
119         return this.columnKeys.size();
120     }
121
122     /**
123      * Returns the value for a given row and column.
124      *
125      * @param row the row index.
126      * @param column the column index.
127      *
128      * @return The value.
129      */

130     public Number JavaDoc getValue(int row, int column) {
131         Number JavaDoc result = null;
132         DefaultKeyedValues rowData = (DefaultKeyedValues) this.rows.get(row);
133         if (rowData != null) {
134             Comparable JavaDoc columnKey = (Comparable JavaDoc) this.columnKeys.get(column);
135             // the row may not have an entry for this key, in which case the
136
// return value is null
137
int index = rowData.getIndex(columnKey);
138             if (index >= 0) {
139                 result = rowData.getValue(index);
140             }
141         }
142         return result;
143     }
144
145     /**
146      * Returns the key for a given row.
147      *
148      * @param row the row index (zero based).
149      *
150      * @return The row index.
151      */

152     public Comparable JavaDoc getRowKey(int row) {
153         return (Comparable JavaDoc) this.rowKeys.get(row);
154     }
155
156     /**
157      * Returns the row index for a given key.
158      *
159      * @param key the key (<code>null</code> not permitted).
160      *
161      * @return The row index.
162      */

163     public int getRowIndex(Comparable JavaDoc key) {
164         if (key == null) {
165             throw new IllegalArgumentException JavaDoc("Null 'key' argument.");
166         }
167         if (this.sortRowKeys) {
168             return Collections.binarySearch(this.rowKeys, key);
169         }
170         else {
171             return this.rowKeys.indexOf(key);
172         }
173     }
174
175     /**
176      * Returns the row keys.
177      *
178      * @return The row keys.
179      */

180     public List JavaDoc getRowKeys() {
181         return Collections.unmodifiableList(this.rowKeys);
182     }
183
184     /**
185      * Returns the key for a given column.
186      *
187      * @param column the column.
188      *
189      * @return The key.
190      */

191     public Comparable JavaDoc getColumnKey(int column) {
192         return (Comparable JavaDoc) this.columnKeys.get(column);
193     }
194
195     /**
196      * Returns the column index for a given key.
197      *
198      * @param key the key (<code>null</code> not permitted).
199      *
200      * @return The column index.
201      */

202     public int getColumnIndex(Comparable JavaDoc key) {
203         if (key == null) {
204             throw new IllegalArgumentException JavaDoc("Null 'key' argument.");
205         }
206         return this.columnKeys.indexOf(key);
207     }
208
209     /**
210      * Returns the column keys.
211      *
212      * @return The column keys.
213      */

214     public List JavaDoc getColumnKeys() {
215         return Collections.unmodifiableList(this.columnKeys);
216     }
217
218     /**
219      * Returns the value for the given row and column keys.
220      *
221      * @param rowKey the row key (<code>null</code> not permitted).
222      * @param columnKey the column key (<code>null</code> not permitted).
223      *
224      * @return The value.
225      */

226     public Number JavaDoc getValue(Comparable JavaDoc rowKey, Comparable JavaDoc columnKey) {
227         if (rowKey == null) {
228             throw new IllegalArgumentException JavaDoc("Null 'rowKey' argument.");
229         }
230         if (columnKey == null) {
231             throw new IllegalArgumentException JavaDoc("Null 'columnKey' argument.");
232         }
233         Number JavaDoc result = null;
234         int row = getRowIndex(rowKey);
235         
236         if (row >= 0) {
237             DefaultKeyedValues rowData
238                 = (DefaultKeyedValues) this.rows.get(row);
239             result = rowData.getValue(columnKey);
240         }
241         return result;
242     }
243
244     /**
245      * Adds a value to the table. Performs the same function as
246      * #setValue(Number, Comparable, Comparable).
247      *
248      * @param value the value (<code>null</code> permitted).
249      * @param rowKey the row key (<code>null</code> not permitted).
250      * @param columnKey the column key (<code>null</code> not permitted).
251      */

252     public void addValue(Number JavaDoc value, Comparable JavaDoc rowKey,
253                          Comparable JavaDoc columnKey) {
254         // defer argument checking
255
setValue(value, rowKey, columnKey);
256     }
257
258     /**
259      * Adds or updates a value.
260      *
261      * @param value the value (<code>null</code> permitted).
262      * @param rowKey the row key (<code>null</code> not permitted).
263      * @param columnKey the column key (<code>null</code> not permitted).
264      */

265     public void setValue(Number JavaDoc value, Comparable JavaDoc rowKey,
266                          Comparable JavaDoc columnKey) {
267
268         DefaultKeyedValues row;
269         int rowIndex = getRowIndex(rowKey);
270         
271         if (rowIndex >= 0) {
272             row = (DefaultKeyedValues) this.rows.get(rowIndex);
273         }
274         else {
275             row = new DefaultKeyedValues();
276             if (this.sortRowKeys) {
277                 rowIndex = -rowIndex - 1;
278                 this.rowKeys.add(rowIndex, rowKey);
279                 this.rows.add(rowIndex, row);
280             }
281             else {
282                 this.rowKeys.add(rowKey);
283                 this.rows.add(row);
284             }
285         }
286         row.setValue(columnKey, value);
287         
288         int columnIndex = this.columnKeys.indexOf(columnKey);
289         if (columnIndex < 0) {
290             this.columnKeys.add(columnKey);
291         }
292     }
293
294     /**
295      * Removes a value.
296      *
297      * @param rowKey the row key (<code>null</code> not permitted).
298      * @param columnKey the column key (<code>null</code> not permitted).
299      */

300     public void removeValue(Comparable JavaDoc rowKey, Comparable JavaDoc columnKey) {
301         setValue(null, rowKey, columnKey);
302         
303         // 1. check whether the row is now empty.
304
boolean allNull = true;
305         int rowIndex = getRowIndex(rowKey);
306         DefaultKeyedValues row = (DefaultKeyedValues) this.rows.get(rowIndex);
307
308         for (int item = 0, itemCount = row.getItemCount(); item < itemCount;
309              item++) {
310             if (row.getValue(item) != null) {
311                 allNull = false;
312                 break;
313             }
314         }
315         
316         if (allNull) {
317             this.rowKeys.remove(rowIndex);
318             this.rows.remove(rowIndex);
319         }
320         
321         // 2. check whether the column is now empty.
322
allNull = true;
323         int columnIndex = getColumnIndex(columnKey);
324         
325         for (int item = 0, itemCount = this.rows.size(); item < itemCount;
326              item++) {
327             row = (DefaultKeyedValues) this.rows.get(item);
328             if (row.getValue(columnIndex) != null) {
329                 allNull = false;
330                 break;
331             }
332         }
333         
334         if (allNull) {
335             for (int item = 0, itemCount = this.rows.size(); item < itemCount;
336                  item++) {
337                 row = (DefaultKeyedValues) this.rows.get(item);
338                 row.removeValue(columnIndex);
339             }
340             this.columnKeys.remove(columnIndex);
341         }
342     }
343
344     /**
345      * Removes a row.
346      *
347      * @param rowIndex the row index.
348      */

349     public void removeRow(int rowIndex) {
350         this.rowKeys.remove(rowIndex);
351         this.rows.remove(rowIndex);
352     }
353
354     /**
355      * Removes a row.
356      *
357      * @param rowKey the row key.
358      */

359     public void removeRow(Comparable JavaDoc rowKey) {
360         removeRow(getRowIndex(rowKey));
361     }
362
363     /**
364      * Removes a column.
365      *
366      * @param columnIndex the column index.
367      */

368     public void removeColumn(int columnIndex) {
369         Comparable JavaDoc columnKey = getColumnKey(columnIndex);
370         removeColumn(columnKey);
371     }
372
373     /**
374      * Removes a column.
375      *
376      * @param columnKey the column key (<code>null</code> not permitted).
377      */

378     public void removeColumn(Comparable JavaDoc columnKey) {
379         Iterator JavaDoc iterator = this.rows.iterator();
380         while (iterator.hasNext()) {
381             DefaultKeyedValues rowData = (DefaultKeyedValues) iterator.next();
382             rowData.removeValue(columnKey);
383         }
384         this.columnKeys.remove(columnKey);
385     }
386
387     /**
388      * Clears all the data and associated keys.
389      */

390     public void clear() {
391         this.rowKeys.clear();
392         this.columnKeys.clear();
393         this.rows.clear();
394     }
395     
396     /**
397      * Tests if this object is equal to another.
398      *
399      * @param o the other object (<code>null</code> permitted).
400      *
401      * @return A boolean.
402      */

403     public boolean equals(Object JavaDoc o) {
404
405         if (o == null) {
406             return false;
407         }
408         if (o == this) {
409             return true;
410         }
411
412         if (!(o instanceof KeyedValues2D)) {
413             return false;
414         }
415         KeyedValues2D kv2D = (KeyedValues2D) o;
416         if (!getRowKeys().equals(kv2D.getRowKeys())) {
417             return false;
418         }
419         if (!getColumnKeys().equals(kv2D.getColumnKeys())) {
420             return false;
421         }
422         int rowCount = getRowCount();
423         if (rowCount != kv2D.getRowCount()) {
424             return false;
425         }
426
427         int colCount = getColumnCount();
428         if (colCount != kv2D.getColumnCount()) {
429             return false;
430         }
431
432         for (int r = 0; r < rowCount; r++) {
433             for (int c = 0; c < colCount; c++) {
434                 Number JavaDoc v1 = getValue(r, c);
435                 Number JavaDoc v2 = kv2D.getValue(r, c);
436                 if (v1 == null) {
437                     if (v2 != null) {
438                         return false;
439                     }
440                 }
441                 else {
442                     if (!v1.equals(v2)) {
443                         return false;
444                     }
445                 }
446             }
447         }
448         return true;
449     }
450
451     /**
452      * Returns a hash code.
453      *
454      * @return A hash code.
455      */

456     public int hashCode() {
457         int result;
458         result = this.rowKeys.hashCode();
459         result = 29 * result + this.columnKeys.hashCode();
460         result = 29 * result + this.rows.hashCode();
461         return result;
462     }
463
464     /**
465      * Returns a clone.
466      *
467      * @return A clone.
468      *
469      * @throws CloneNotSupportedException this class will not throw this
470      * exception, but subclasses (if any) might.
471      */

472     public Object JavaDoc clone() throws CloneNotSupportedException JavaDoc {
473         DefaultKeyedValues2D clone = (DefaultKeyedValues2D) super.clone();
474         // for the keys, a shallow copy should be fine because keys
475
// should be immutable...
476
clone.columnKeys = new java.util.ArrayList JavaDoc(this.columnKeys);
477         clone.rowKeys = new java.util.ArrayList JavaDoc(this.rowKeys);
478         
479         // but the row data requires a deep copy
480
clone.rows = (List JavaDoc) ObjectUtilities.deepClone(this.rows);
481         return clone;
482     }
483
484 }
485
Popular Tags