KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > util > ObjectTable


1 /* ========================================================================
2  * JCommon : a free general purpose class 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/jcommon/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
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
25  * in the United States and other countries.]
26  *
27  * ----------------
28  * ObjectTable.java
29  * ----------------
30  * (C) Copyright 2003, 2004, by Object Refinery Limited.
31  *
32  * Original Author: David Gilbert (for Object Refinery Limited);
33  * Contributor(s): -;
34  *
35  * $Id: ObjectTable.java,v 1.9 2006/11/05 14:34:15 taqua Exp $
36  *
37  * Changes
38  * -------
39  * 29-Apr-2003 : Version 1, based on PaintTable class (DG);
40  * 21-May-2003 : Copied the array based implementation of StrokeTable and
41  * fixed the serialisation behaviour (TM).
42  */

43
44 package org.jfree.util;
45
46 import java.io.IOException JavaDoc;
47 import java.io.ObjectInputStream JavaDoc;
48 import java.io.ObjectOutputStream JavaDoc;
49 import java.io.Serializable JavaDoc;
50 import java.util.Arrays JavaDoc;
51
52 /**
53  * A lookup table for objects. This implementation is not synchronized, it is up
54  * to the caller to synchronize it properly.
55  *
56  * @author Thomas Morgner
57  */

58 public class ObjectTable implements Serializable JavaDoc
59 {
60
61   /**
62    * For serialization.
63    */

64   private static final long serialVersionUID = -3968322452944912066L;
65
66   /**
67    * The number of rows.
68    */

69   private int rows;
70
71   /**
72    * The number of columns.
73    */

74   private int columns;
75
76   /**
77    * An array of objects. The array may contain <code>null</code> values.
78    */

79   private transient Object JavaDoc[][] data;
80
81   /**
82    * Defines how many object-slots get reserved each time we run out of
83    * space.
84    */

85   private int rowIncrement;
86
87   /**
88    * Defines how many object-slots get reserved each time we run out of
89    * space.
90    */

91   private int columnIncrement;
92
93   /**
94    * Creates a new table.
95    */

96   public ObjectTable()
97   {
98     this(5, 5);
99   }
100
101   /**
102    * Creates a new table.
103    *
104    * @param increment the row and column size increment.
105    */

106   public ObjectTable(final int increment)
107   {
108     this(increment, increment);
109   }
110
111   /**
112    * Creates a new table.
113    *
114    * @param rowIncrement the row size increment.
115    * @param colIncrement the column size increment.
116    */

117   public ObjectTable(final int rowIncrement, final int colIncrement)
118   {
119     if (rowIncrement < 1)
120     {
121       throw new IllegalArgumentException JavaDoc("Increment must be positive.");
122     }
123
124     if (colIncrement < 1)
125     {
126       throw new IllegalArgumentException JavaDoc("Increment must be positive.");
127     }
128
129     this.rows = 0;
130     this.columns = 0;
131     this.rowIncrement = rowIncrement;
132     this.columnIncrement = colIncrement;
133
134     this.data = new Object JavaDoc[rowIncrement][];
135   }
136
137   /**
138    * Returns the column size increment.
139    *
140    * @return the increment.
141    */

142   public int getColumnIncrement()
143   {
144     return this.columnIncrement;
145   }
146
147   /**
148    * Returns the row size increment.
149    *
150    * @return the increment.
151    */

152   public int getRowIncrement()
153   {
154     return this.rowIncrement;
155   }
156
157   /**
158    * Checks that there is storage capacity for the specified row and resizes
159    * if necessary.
160    *
161    * @param row the row index.
162    */

163   protected void ensureRowCapacity(final int row)
164   {
165
166     // does this increase the number of rows? if yes, create new storage
167
if (row >= this.data.length)
168     {
169
170       final Object JavaDoc[][] enlarged = new Object JavaDoc[row + this.rowIncrement][];
171       System.arraycopy(this.data, 0, enlarged, 0, this.data.length);
172       // do not create empty arrays - this is more expensive than checking
173
// for null-values.
174
this.data = enlarged;
175     }
176   }
177
178   /**
179    * Ensures that there is storage capacity for the specified item.
180    *
181    * @param row the row index.
182    * @param column the column index.
183    */

184   public void ensureCapacity(final int row, final int column)
185   {
186
187     if (row < 0)
188     {
189       throw new IndexOutOfBoundsException JavaDoc("Row is invalid. " + row);
190     }
191     if (column < 0)
192     {
193       throw new IndexOutOfBoundsException JavaDoc("Column is invalid. " + column);
194     }
195
196     ensureRowCapacity(row);
197
198     final Object JavaDoc[] current = this.data[row];
199     if (current == null)
200     {
201       final Object JavaDoc[] enlarged
202           = new Object JavaDoc[Math.max(column + 1, this.columnIncrement)];
203       this.data[row] = enlarged;
204     }
205     else if (column >= current.length)
206     {
207       final Object JavaDoc[] enlarged = new Object JavaDoc[column + this.columnIncrement];
208       System.arraycopy(current, 0, enlarged, 0, current.length);
209       this.data[row] = enlarged;
210     }
211   }
212
213   /**
214    * Returns the number of rows in the table.
215    *
216    * @return The row count.
217    */

218   public int getRowCount()
219   {
220     return this.rows;
221   }
222
223   /**
224    * Returns the number of columns in the table.
225    *
226    * @return The column count.
227    */

228   public int getColumnCount()
229   {
230     return this.columns;
231   }
232
233   /**
234    * Returns the object from a particular cell in the table. Returns null, if
235    * there is no object at the given position.
236    * <p/>
237    * Note: throws IndexOutOfBoundsException if row or column is negative.
238    *
239    * @param row the row index (zero-based).
240    * @param column the column index (zero-based).
241    * @return The object.
242    */

243   protected Object JavaDoc getObject(final int row, final int column)
244   {
245
246     if (row < this.data.length)
247     {
248       final Object JavaDoc[] current = this.data[row];
249       if (current == null)
250       {
251         return null;
252       }
253       if (column < current.length)
254       {
255         return current[column];
256       }
257     }
258     return null;
259
260   }
261
262   /**
263    * Sets the object for a cell in the table. The table is expanded if
264    * necessary.
265    *
266    * @param row the row index (zero-based).
267    * @param column the column index (zero-based).
268    * @param object the object.
269    */

270   protected void setObject(final int row, final int column,
271                            final Object JavaDoc object)
272   {
273
274     ensureCapacity(row, column);
275
276     this.data[row][column] = object;
277     this.rows = Math.max(this.rows, row + 1);
278     this.columns = Math.max(this.columns, column + 1);
279   }
280
281   /**
282    * Tests this paint table for equality with another object (typically also
283    * an <code>ObjectTable</code>).
284    *
285    * @param o the other object.
286    * @return A boolean.
287    */

288   public boolean equals(final Object JavaDoc o)
289   {
290
291     if (o == null)
292     {
293       return false;
294     }
295
296     if (this == o)
297     {
298       return true;
299     }
300
301     if ((o instanceof ObjectTable) == false)
302     {
303       return false;
304     }
305
306     final ObjectTable ot = (ObjectTable) o;
307     if (getRowCount() != ot.getRowCount())
308     {
309       return false;
310     }
311
312     if (getColumnCount() != ot.getColumnCount())
313     {
314       return false;
315     }
316
317     for (int r = 0; r < getRowCount(); r++)
318     {
319       for (int c = 0; c < getColumnCount(); c++)
320       {
321         if (ObjectUtilities.equal(getObject(r, c),
322             ot.getObject(r, c)) == false)
323         {
324           return false;
325         }
326       }
327     }
328     return true;
329   }
330
331   /**
332    * Returns a hash code value for the object.
333    *
334    * @return the hashcode
335    */

336   public int hashCode()
337   {
338     int result;
339     result = this.rows;
340     result = 29 * result + this.columns;
341     return result;
342   }
343
344   /**
345    * Handles serialization.
346    *
347    * @param stream the output stream.
348    * @throws java.io.IOException if there is an I/O problem.
349    */

350   private void writeObject(final ObjectOutputStream JavaDoc stream)
351       throws IOException JavaDoc
352   {
353     stream.defaultWriteObject();
354     final int rowCount = this.data.length;
355     stream.writeInt(rowCount);
356     for (int r = 0; r < rowCount; r++)
357     {
358       final Object JavaDoc[] column = this.data[r];
359       stream.writeBoolean(column != null);
360       if (column != null)
361       {
362         final int columnCount = column.length;
363         stream.writeInt(columnCount);
364         for (int c = 0; c < columnCount; c++)
365         {
366           writeSerializedData(stream, column[c]);
367         }
368       }
369     }
370   }
371
372   /**
373    * Handles the serialization of an single element of this table.
374    *
375    * @param stream the stream which should write the object
376    * @param o the object that should be serialized
377    * @throws IOException if an IO error occured
378    */

379   protected void writeSerializedData(final ObjectOutputStream JavaDoc stream,
380                                      final Object JavaDoc o)
381       throws IOException JavaDoc
382   {
383     stream.writeObject(o);
384   }
385
386   /**
387    * Restores a serialized object.
388    *
389    * @param stream the input stream.
390    * @throws java.io.IOException if there is an I/O problem.
391    * @throws ClassNotFoundException if a class cannot be found.
392    */

393   private void readObject(final ObjectInputStream JavaDoc stream)
394       throws IOException JavaDoc, ClassNotFoundException JavaDoc
395   {
396     stream.defaultReadObject();
397     final int rowCount = stream.readInt();
398     this.data = new Object JavaDoc[rowCount][];
399     for (int r = 0; r < rowCount; r++)
400     {
401       final boolean isNotNull = stream.readBoolean();
402       if (isNotNull)
403       {
404         final int columnCount = stream.readInt();
405         final Object JavaDoc[] column = new Object JavaDoc[columnCount];
406         this.data[r] = column;
407         for (int c = 0; c < columnCount; c++)
408         {
409           column[c] = readSerializedData(stream);
410         }
411       }
412     }
413   }
414
415   /**
416    * Handles the deserialization of a single element of the table.
417    *
418    * @param stream the object input stream from which to read the object.
419    * @return the deserialized object
420    * @throws ClassNotFoundException if a class cannot be found.
421    * @throws IOException Any of the usual Input/Output related
422    * exceptions.
423    */

424   protected Object JavaDoc readSerializedData(final ObjectInputStream JavaDoc stream)
425       throws ClassNotFoundException JavaDoc, IOException JavaDoc
426   {
427     return stream.readObject();
428   }
429
430   /**
431    * Clears the table.
432    */

433   public void clear()
434   {
435     this.rows = 0;
436     this.columns = 0;
437     for (int i = 0; i < this.data.length; i++)
438     {
439       if (this.data[i] != null)
440       {
441         Arrays.fill(this.data[i], null);
442       }
443     }
444   }
445
446   /**
447    * Copys the contents of the old column to the new column.
448    *
449    * @param oldColumn the index of the old (source) column
450    * @param newColumn the index of the new column
451    */

452   protected void copyColumn(final int oldColumn, final int newColumn)
453   {
454     for (int i = 0; i < getRowCount(); i++)
455     {
456       setObject(i, newColumn, getObject(i, oldColumn));
457     }
458   }
459
460   /**
461    * Copys the contents of the old row to the new row. This uses raw access to
462    * the data and is remarkably faster than manual copying.
463    *
464    * @param oldRow the index of the old row
465    * @param newRow the index of the new row
466    */

467   protected void copyRow(final int oldRow, final int newRow)
468   {
469     this.ensureCapacity(newRow, getColumnCount());
470     final Object JavaDoc[] oldRowStorage = this.data[oldRow];
471     if (oldRowStorage == null)
472     {
473       final Object JavaDoc[] newRowStorage = this.data[newRow];
474       if (newRowStorage != null)
475       {
476         Arrays.fill(newRowStorage, null);
477       }
478     }
479     else
480     {
481       this.data[newRow] = (Object JavaDoc[]) oldRowStorage.clone();
482     }
483   }
484
485   protected void setData(final Object JavaDoc[][] data, final int colCount)
486   {
487     if (data == null) {
488       throw new NullPointerException JavaDoc();
489     }
490     if (colCount < 0) {
491       throw new IndexOutOfBoundsException JavaDoc();
492     }
493
494     this.data = data;
495     this.rows = data.length;
496     this.columns = colCount;
497   }
498
499   protected Object JavaDoc[][] getData()
500   {
501     return data;
502   }
503 }
504
505
Popular Tags