KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > table > DefaultTableModel


1 /*
2  * @(#)DefaultTableModel.java 1.39 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.table;
9
10 import java.io.Serializable JavaDoc;
11 import java.util.Vector JavaDoc;
12 import java.util.Enumeration JavaDoc;
13 import javax.swing.event.TableModelEvent JavaDoc;
14
15
16 /**
17  * This is an implementation of <code>TableModel</code> that
18  * uses a <code>Vector</code> of <code>Vectors</code> to store the
19  * cell value objects.
20  * <p>
21  * <strong>Warning:</strong>
22  * Serialized objects of this class will not be compatible with
23  * future Swing releases. The current serialization support is
24  * appropriate for short term storage or RMI between applications running
25  * the same version of Swing. As of 1.4, support for long term storage
26  * of all JavaBeans<sup><font size="-2">TM</font></sup>
27  * has been added to the <code>java.beans</code> package.
28  * Please see {@link java.beans.XMLEncoder}.
29  *
30  * @version 1.39 12/19/03
31  * @author Philip Milne
32  *
33  * @see TableModel
34  * @see #getDataVector
35  */

36 public class DefaultTableModel extends AbstractTableModel JavaDoc implements Serializable JavaDoc {
37
38 //
39
// Instance Variables
40
//
41

42     /**
43      * The <code>Vector</code> of <code>Vectors</code> of
44      * <code>Object</code> values.
45      */

46     protected Vector JavaDoc dataVector;
47
48     /** The <code>Vector</code> of column identifiers. */
49     protected Vector JavaDoc columnIdentifiers;
50
51 //
52
// Constructors
53
//
54

55     /**
56      * Constructs a default <code>DefaultTableModel</code>
57      * which is a table of zero columns and zero rows.
58      */

59     public DefaultTableModel() {
60         this(0, 0);
61     }
62
63     private static Vector JavaDoc newVector(int size) {
64     Vector JavaDoc v = new Vector JavaDoc(size);
65     v.setSize(size);
66     return v;
67     }
68
69     /**
70      * Constructs a <code>DefaultTableModel</code> with
71      * <code>rowCount</code> and <code>columnCount</code> of
72      * <code>null</code> object values.
73      *
74      * @param rowCount the number of rows the table holds
75      * @param columnCount the number of columns the table holds
76      *
77      * @see #setValueAt
78      */

79     public DefaultTableModel(int rowCount, int columnCount) {
80         this(newVector(columnCount), rowCount);
81     }
82
83     /**
84      * Constructs a <code>DefaultTableModel</code> with as many columns
85      * as there are elements in <code>columnNames</code>
86      * and <code>rowCount</code> of <code>null</code>
87      * object values. Each column's name will be taken from
88      * the <code>columnNames</code> vector.
89      *
90      * @param columnNames <code>vector</code> containing the names
91      * of the new columns; if this is
92      * <code>null</code> then the model has no columns
93      * @param rowCount the number of rows the table holds
94      * @see #setDataVector
95      * @see #setValueAt
96      */

97     public DefaultTableModel(Vector JavaDoc columnNames, int rowCount) {
98         setDataVector(newVector(rowCount), columnNames);
99     }
100
101     /**
102      * Constructs a <code>DefaultTableModel</code> with as many
103      * columns as there are elements in <code>columnNames</code>
104      * and <code>rowCount</code> of <code>null</code>
105      * object values. Each column's name will be taken from
106      * the <code>columnNames</code> array.
107      *
108      * @param columnNames <code>array</code> containing the names
109      * of the new columns; if this is
110      * <code>null</code> then the model has no columns
111      * @param rowCount the number of rows the table holds
112      * @see #setDataVector
113      * @see #setValueAt
114      */

115     public DefaultTableModel(Object JavaDoc[] columnNames, int rowCount) {
116         this(convertToVector(columnNames), rowCount);
117     }
118
119     /**
120      * Constructs a <code>DefaultTableModel</code> and initializes the table
121      * by passing <code>data</code> and <code>columnNames</code>
122      * to the <code>setDataVector</code> method.
123      *
124      * @param data the data of the table, a <code>Vector</code>
125      * of <code>Vector</code>s of <code>Object</code>
126      * values
127      * @param columnNames <code>vector</code> containing the names
128      * of the new columns
129      * @see #getDataVector
130      * @see #setDataVector
131      */

132     public DefaultTableModel(Vector JavaDoc data, Vector JavaDoc columnNames) {
133         setDataVector(data, columnNames);
134     }
135
136     /**
137      * Constructs a <code>DefaultTableModel</code> and initializes the table
138      * by passing <code>data</code> and <code>columnNames</code>
139      * to the <code>setDataVector</code>
140      * method. The first index in the <code>Object[][]</code> array is
141      * the row index and the second is the column index.
142      *
143      * @param data the data of the table
144      * @param columnNames the names of the columns
145      * @see #getDataVector
146      * @see #setDataVector
147      */

148     public DefaultTableModel(Object JavaDoc[][] data, Object JavaDoc[] columnNames) {
149         setDataVector(data, columnNames);
150     }
151
152     /**
153      * Returns the <code>Vector</code> of <code>Vectors</code>
154      * that contains the table's
155      * data values. The vectors contained in the outer vector are
156      * each a single row of values. In other words, to get to the cell
157      * at row 1, column 5: <p>
158      *
159      * <code>((Vector)getDataVector().elementAt(1)).elementAt(5);</code><p>
160      *
161      * @return the vector of vectors containing the tables data values
162      *
163      * @see #newDataAvailable
164      * @see #newRowsAdded
165      * @see #setDataVector
166      */

167     public Vector JavaDoc getDataVector() {
168         return dataVector;
169     }
170
171     private static Vector JavaDoc nonNullVector(Vector JavaDoc v) {
172     return (v != null) ? v : new Vector JavaDoc();
173     }
174
175     /**
176      * Replaces the current <code>dataVector</code> instance variable
177      * with the new <code>Vector</code> of rows, <code>dataVector</code>.
178      * Each row is represented in <code>dataVector</code> as a
179      * <code>Vector</code> of <code>Object</code> values.
180      * <code>columnIdentifiers</code> are the names of the new
181      * columns. The first name in <code>columnIdentifiers</code> is
182      * mapped to column 0 in <code>dataVector</code>. Each row in
183      * <code>dataVector</code> is adjusted to match the number of
184      * columns in <code>columnIdentifiers</code>
185      * either by truncating the <code>Vector</code> if it is too long,
186      * or adding <code>null</code> values if it is too short.
187      * <p>Note that passing in a <code>null</code> value for
188      * <code>dataVector</code> results in unspecified behavior,
189      * an possibly an exception.
190      *
191      * @param dataVector the new data vector
192      * @param columnIdentifiers the names of the columns
193      * @see #getDataVector
194      */

195     public void setDataVector(Vector JavaDoc dataVector, Vector JavaDoc columnIdentifiers) {
196         this.dataVector = nonNullVector(dataVector);
197         this.columnIdentifiers = nonNullVector(columnIdentifiers);
198     justifyRows(0, getRowCount());
199         fireTableStructureChanged();
200     }
201
202     /**
203      * Replaces the value in the <code>dataVector</code> instance
204      * variable with the values in the array <code>dataVector</code>.
205      * The first index in the <code>Object[][]</code>
206      * array is the row index and the second is the column index.
207      * <code>columnIdentifiers</code> are the names of the new columns.
208      *
209      * @param dataVector the new data vector
210      * @param columnIdentifiers the names of the columns
211      * @see #setDataVector(Vector, Vector)
212      */

213     public void setDataVector(Object JavaDoc[][] dataVector, Object JavaDoc[] columnIdentifiers) {
214         setDataVector(convertToVector(dataVector), convertToVector(columnIdentifiers));
215     }
216
217     /**
218      * Equivalent to <code>fireTableChanged</code>.
219      *
220      * @param event the change event
221      *
222      */

223     public void newDataAvailable(TableModelEvent JavaDoc event) {
224         fireTableChanged(event);
225     }
226
227 //
228
// Manipulating rows
229
//
230

231     private void justifyRows(int from, int to) {
232     // Sometimes the DefaultTableModel is subclassed
233
// instead of the AbstractTableModel by mistake.
234
// Set the number of rows for the case when getRowCount
235
// is overridden.
236
dataVector.setSize(getRowCount());
237
238         for (int i = from; i < to; i++) {
239         if (dataVector.elementAt(i) == null) {
240         dataVector.setElementAt(new Vector JavaDoc(), i);
241         }
242         ((Vector JavaDoc)dataVector.elementAt(i)).setSize(getColumnCount());
243     }
244     }
245
246     /**
247      * Ensures that the new rows have the correct number of columns.
248      * This is accomplished by using the <code>setSize</code> method in
249      * <code>Vector</code> which truncates vectors
250      * which are too long, and appends <code>null</code>s if they
251      * are too short.
252      * This method also sends out a <code>tableChanged</code>
253      * notification message to all the listeners.
254      *
255      * @param e this <code>TableModelEvent</code> describes
256      * where the rows were added.
257      * If <code>null</code> it assumes
258      * all the rows were newly added
259      * @see #getDataVector
260      */

261     public void newRowsAdded(TableModelEvent JavaDoc e) {
262         justifyRows(e.getFirstRow(), e.getLastRow() + 1);
263         fireTableChanged(e);
264     }
265
266     /**
267      * Equivalent to <code>fireTableChanged</code>.
268      *
269      * @param event the change event
270      *
271      */

272     public void rowsRemoved(TableModelEvent JavaDoc event) {
273         fireTableChanged(event);
274     }
275
276     /**
277      * Obsolete as of Java 2 platform v1.3. Please use <code>setRowCount</code> instead.
278      */

279     /*
280      * Sets the number of rows in the model. If the new size is greater
281      * than the current size, new rows are added to the end of the model
282      * If the new size is less than the current size, all
283      * rows at index <code>rowCount</code> and greater are discarded. <p>
284      *
285      * @param rowCount the new number of rows
286      * @see #setRowCount
287      */

288     public void setNumRows(int rowCount) {
289         int old = getRowCount();
290     if (old == rowCount) {
291         return;
292     }
293     dataVector.setSize(rowCount);
294         if (rowCount <= old) {
295             fireTableRowsDeleted(rowCount, old-1);
296         }
297         else {
298         justifyRows(old, rowCount);
299             fireTableRowsInserted(old, rowCount-1);
300         }
301     }
302
303     /**
304      * Sets the number of rows in the model. If the new size is greater
305      * than the current size, new rows are added to the end of the model
306      * If the new size is less than the current size, all
307      * rows at index <code>rowCount</code> and greater are discarded. <p>
308      *
309      * @see #setColumnCount
310      */

311     public void setRowCount(int rowCount) {
312     setNumRows(rowCount);
313     }
314
315     /**
316      * Adds a row to the end of the model. The new row will contain
317      * <code>null</code> values unless <code>rowData</code> is specified.
318      * Notification of the row being added will be generated.
319      *
320      * @param rowData optional data of the row being added
321      */

322     public void addRow(Vector JavaDoc rowData) {
323         insertRow(getRowCount(), rowData);
324     }
325
326     /**
327      * Adds a row to the end of the model. The new row will contain
328      * <code>null</code> values unless <code>rowData</code> is specified.
329      * Notification of the row being added will be generated.
330      *
331      * @param rowData optional data of the row being added
332      */

333     public void addRow(Object JavaDoc[] rowData) {
334         addRow(convertToVector(rowData));
335     }
336
337     /**
338      * Inserts a row at <code>row</code> in the model. The new row
339      * will contain <code>null</code> values unless <code>rowData</code>
340      * is specified. Notification of the row being added will be generated.
341      *
342      * @param row the row index of the row to be inserted
343      * @param rowData optional data of the row being added
344      * @exception ArrayIndexOutOfBoundsException if the row was invalid
345      */

346     public void insertRow(int row, Vector JavaDoc rowData) {
347     dataVector.insertElementAt(rowData, row);
348     justifyRows(row, row+1);
349         fireTableRowsInserted(row, row);
350     }
351
352     /**
353      * Inserts a row at <code>row</code> in the model. The new row
354      * will contain <code>null</code> values unless <code>rowData</code>
355      * is specified. Notification of the row being added will be generated.
356      *
357      * @param row the row index of the row to be inserted
358      * @param rowData optional data of the row being added
359      * @exception ArrayIndexOutOfBoundsException if the row was invalid
360      */

361     public void insertRow(int row, Object JavaDoc[] rowData) {
362         insertRow(row, convertToVector(rowData));
363     }
364
365     private static int gcd(int i, int j) {
366     return (j == 0) ? i : gcd(j, i%j);
367     }
368
369     private static void rotate(Vector JavaDoc v, int a, int b, int shift) {
370     int size = b - a;
371     int r = size - shift;
372     int g = gcd(size, r);
373     for(int i = 0; i < g; i++) {
374         int to = i;
375         Object JavaDoc tmp = v.elementAt(a + to);
376         for(int from = (to + r) % size; from != i; from = (to + r) % size) {
377         v.setElementAt(v.elementAt(a + from), a + to);
378         to = from;
379         }
380         v.setElementAt(tmp, a + to);
381     }
382     }
383
384     /**
385      * Moves one or more rows from the inclusive range <code>start</code> to
386      * <code>end</code> to the <code>to</code> position in the model.
387      * After the move, the row that was at index <code>start</code>
388      * will be at index <code>to</code>.
389      * This method will send a <code>tableChanged</code> notification
390      * message to all the listeners. <p>
391      *
392      * <pre>
393      * Examples of moves:
394      * <p>
395      * 1. moveRow(1,3,5);
396      * a|B|C|D|e|f|g|h|i|j|k - before
397      * a|e|f|g|h|B|C|D|i|j|k - after
398      * <p>
399      * 2. moveRow(6,7,1);
400      * a|b|c|d|e|f|G|H|i|j|k - before
401      * a|G|H|b|c|d|e|f|i|j|k - after
402      * <p>
403      * </pre>
404      *
405      * @param start the starting row index to be moved
406      * @param end the ending row index to be moved
407      * @param to the destination of the rows to be moved
408      * @exception ArrayIndexOutOfBoundsException if any of the elements
409      * would be moved out of the table's range
410      *
411      */

412     public void moveRow(int start, int end, int to) {
413     int shift = to - start;
414     int first, last;
415     if (shift < 0) {
416         first = to;
417         last = end;
418     }
419     else {
420         first = start;
421         last = to + end - start;
422     }
423         rotate(dataVector, first, last + 1, shift);
424
425         fireTableRowsUpdated(first, last);
426     }
427
428     /**
429      * Removes the row at <code>row</code> from the model. Notification
430      * of the row being removed will be sent to all the listeners.
431      *
432      * @param row the row index of the row to be removed
433      * @exception ArrayIndexOutOfBoundsException if the row was invalid
434      */

435     public void removeRow(int row) {
436         dataVector.removeElementAt(row);
437         fireTableRowsDeleted(row, row);
438     }
439
440 //
441
// Manipulating columns
442
//
443

444     /**
445      * Replaces the column identifiers in the model. If the number of
446      * <code>newIdentifier</code>s is greater than the current number
447      * of columns, new columns are added to the end of each row in the model.
448      * If the number of <code>newIdentifier</code>s is less than the current
449      * number of columns, all the extra columns at the end of a row are
450      * discarded. <p>
451      *
452      * @param columnIdentifiers vector of column identifiers. If
453      * <code>null</code>, set the model
454      * to zero columns
455      * @see #setNumRows
456      */

457     public void setColumnIdentifiers(Vector JavaDoc columnIdentifiers) {
458     setDataVector(dataVector, columnIdentifiers);
459     }
460
461     /**
462      * Replaces the column identifiers in the model. If the number of
463      * <code>newIdentifier</code>s is greater than the current number
464      * of columns, new columns are added to the end of each row in the model.
465      * If the number of <code>newIdentifier</code>s is less than the current
466      * number of columns, all the extra columns at the end of a row are
467      * discarded. <p>
468      *
469      * @param newIdentifiers array of column identifiers.
470      * If <code>null</code>, set
471      * the model to zero columns
472      * @see #setNumRows
473      */

474     public void setColumnIdentifiers(Object JavaDoc[] newIdentifiers) {
475         setColumnIdentifiers(convertToVector(newIdentifiers));
476     }
477
478     /**
479      * Sets the number of columns in the model. If the new size is greater
480      * than the current size, new columns are added to the end of the model
481      * with <code>null</code> cell values.
482      * If the new size is less than the current size, all columns at index
483      * <code>columnCount</code> and greater are discarded.
484      *
485      * @param columnCount the new number of columns in the model
486      *
487      * @see #setColumnCount
488      */

489     public void setColumnCount(int columnCount) {
490     columnIdentifiers.setSize(columnCount);
491     justifyRows(0, getRowCount());
492     fireTableStructureChanged();
493     }
494
495     /**
496      * Adds a column to the model. The new column will have the
497      * identifier <code>columnName</code>, which may be null. This method
498      * will send a
499      * <code>tableChanged</code> notification message to all the listeners.
500      * This method is a cover for <code>addColumn(Object, Vector)</code> which
501      * uses <code>null</code> as the data vector.
502      *
503      * @param columnName the identifier of the column being added
504      */

505     public void addColumn(Object JavaDoc columnName) {
506         addColumn(columnName, (Vector JavaDoc)null);
507     }
508
509     /**
510      * Adds a column to the model. The new column will have the
511      * identifier <code>columnName</code>, which may be null.
512      * <code>columnData</code> is the
513      * optional vector of data for the column. If it is <code>null</code>
514      * the column is filled with <code>null</code> values. Otherwise,
515      * the new data will be added to model starting with the first
516      * element going to row 0, etc. This method will send a
517      * <code>tableChanged</code> notification message to all the listeners.
518      *
519      * @param columnName the identifier of the column being added
520      * @param columnData optional data of the column being added
521      */

522     public void addColumn(Object JavaDoc columnName, Vector JavaDoc columnData) {
523         columnIdentifiers.addElement(columnName);
524     if (columnData != null) {
525             int columnSize = columnData.size();
526             if (columnSize > getRowCount()) {
527             dataVector.setSize(columnSize);
528             }
529         justifyRows(0, getRowCount());
530         int newColumn = getColumnCount() - 1;
531         for(int i = 0; i < columnSize; i++) {
532           Vector JavaDoc row = (Vector JavaDoc)dataVector.elementAt(i);
533           row.setElementAt(columnData.elementAt(i), newColumn);
534         }
535     }
536         else {
537         justifyRows(0, getRowCount());
538         }
539
540         fireTableStructureChanged();
541     }
542
543     /**
544      * Adds a column to the model. The new column will have the
545      * identifier <code>columnName</code>. <code>columnData</code> is the
546      * optional array of data for the column. If it is <code>null</code>
547      * the column is filled with <code>null</code> values. Otherwise,
548      * the new data will be added to model starting with the first
549      * element going to row 0, etc. This method will send a
550      * <code>tableChanged</code> notification message to all the listeners.
551      *
552      * @see #addColumn(Object, Vector)
553      */

554     public void addColumn(Object JavaDoc columnName, Object JavaDoc[] columnData) {
555         addColumn(columnName, convertToVector(columnData));
556     }
557
558 //
559
// Implementing the TableModel interface
560
//
561

562     /**
563      * Returns the number of rows in this data table.
564      * @return the number of rows in the model
565      */

566     public int getRowCount() {
567         return dataVector.size();
568     }
569
570     /**
571      * Returns the number of columns in this data table.
572      * @return the number of columns in the model
573      */

574     public int getColumnCount() {
575         return columnIdentifiers.size();
576     }
577
578     /**
579      * Returns the column name.
580      *
581      * @return a name for this column using the string value of the
582      * appropriate member in <code>columnIdentifiers</code>.
583      * If <code>columnIdentifiers</code> does not have an entry
584      * for this index, returns the default
585      * name provided by the superclass
586      */

587     public String JavaDoc getColumnName(int column) {
588         Object JavaDoc id = null;
589     // This test is to cover the case when
590
// getColumnCount has been subclassed by mistake ...
591
if (column < columnIdentifiers.size()) {
592         id = columnIdentifiers.elementAt(column);
593     }
594         return (id == null) ? super.getColumnName(column)
595                             : id.toString();
596     }
597
598     /**
599      * Returns true regardless of parameter values.
600      *
601      * @param row the row whose value is to be queried
602      * @param column the column whose value is to be queried
603      * @return true
604      * @see #setValueAt
605      */

606     public boolean isCellEditable(int row, int column) {
607         return true;
608     }
609
610     /**
611      * Returns an attribute value for the cell at <code>row</code>
612      * and <code>column</code>.
613      *
614      * @param row the row whose value is to be queried
615      * @param column the column whose value is to be queried
616      * @return the value Object at the specified cell
617      * @exception ArrayIndexOutOfBoundsException if an invalid row or
618      * column was given
619      */

620     public Object JavaDoc getValueAt(int row, int column) {
621         Vector JavaDoc rowVector = (Vector JavaDoc)dataVector.elementAt(row);
622         return rowVector.elementAt(column);
623     }
624
625     /**
626      * Sets the object value for the cell at <code>column</code> and
627      * <code>row</code>. <code>aValue</code> is the new value. This method
628      * will generate a <code>tableChanged</code> notification.
629      *
630      * @param aValue the new value; this can be null
631      * @param row the row whose value is to be changed
632      * @param column the column whose value is to be changed
633      * @exception ArrayIndexOutOfBoundsException if an invalid row or
634      * column was given
635      */

636     public void setValueAt(Object JavaDoc aValue, int row, int column) {
637         Vector JavaDoc rowVector = (Vector JavaDoc)dataVector.elementAt(row);
638         rowVector.setElementAt(aValue, column);
639         fireTableCellUpdated(row, column);
640     }
641
642 //
643
// Protected Methods
644
//
645

646     /**
647      * Returns a vector that contains the same objects as the array.
648      * @param anArray the array to be converted
649      * @return the new vector; if <code>anArray</code> is <code>null</code>,
650      * returns <code>null</code>
651      */

652     protected static Vector JavaDoc convertToVector(Object JavaDoc[] anArray) {
653         if (anArray == null) {
654             return null;
655     }
656         Vector JavaDoc v = new Vector JavaDoc(anArray.length);
657         for (int i=0; i < anArray.length; i++) {
658             v.addElement(anArray[i]);
659         }
660         return v;
661     }
662
663     /**
664      * Returns a vector of vectors that contains the same objects as the array.
665      * @param anArray the double array to be converted
666      * @return the new vector of vectors; if <code>anArray</code> is
667      * <code>null</code>, returns <code>null</code>
668      */

669     protected static Vector JavaDoc convertToVector(Object JavaDoc[][] anArray) {
670         if (anArray == null) {
671             return null;
672     }
673         Vector JavaDoc v = new Vector JavaDoc(anArray.length);
674         for (int i=0; i < anArray.length; i++) {
675             v.addElement(convertToVector(anArray[i]));
676         }
677         return v;
678     }
679
680 } // End of class DefaultTableModel
681
Popular Tags