001 /*
002 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.swing.table;
027
028 import java.io.Serializable;
029 import java.util.Vector;
030 import java.util.Enumeration;
031 import javax.swing.event.TableModelEvent;
032
033 /**
034 * This is an implementation of <code>TableModel</code> that
035 * uses a <code>Vector</code> of <code>Vectors</code> to store the
036 * cell value objects.
037 * <p>
038 * <strong>Warning:</strong> <code>DefaultTableModel</code> returns a
039 * column class of <code>Object</code>. When
040 * <code>DefaultTableModel</code> is used with a
041 * <code>TableRowSorter</code> this will result in extensive use of
042 * <code>toString</code>, which for non-<code>String</code> data types
043 * is expensive. If you use <code>DefaultTableModel</code> with a
044 * <code>TableRowSorter</code> you are strongly encouraged to override
045 * <code>getColumnClass</code> to return the appropriate type.
046 * <p>
047 * <strong>Warning:</strong>
048 * Serialized objects of this class will not be compatible with
049 * future Swing releases. The current serialization support is
050 * appropriate for short term storage or RMI between applications running
051 * the same version of Swing. As of 1.4, support for long term storage
052 * of all JavaBeans<sup><font size="-2">TM</font></sup>
053 * has been added to the <code>java.beans</code> package.
054 * Please see {@link java.beans.XMLEncoder}.
055 *
056 * @version 1.49 05/05/07
057 * @author Philip Milne
058 *
059 * @see TableModel
060 * @see #getDataVector
061 */
062 public class DefaultTableModel extends AbstractTableModel implements
063 Serializable {
064
065 //
066 // Instance Variables
067 //
068
069 /**
070 * The <code>Vector</code> of <code>Vectors</code> of
071 * <code>Object</code> values.
072 */
073 protected Vector dataVector;
074
075 /** The <code>Vector</code> of column identifiers. */
076 protected Vector columnIdentifiers;
077
078 //
079 // Constructors
080 //
081
082 /**
083 * Constructs a default <code>DefaultTableModel</code>
084 * which is a table of zero columns and zero rows.
085 */
086 public DefaultTableModel() {
087 this (0, 0);
088 }
089
090 private static Vector newVector(int size) {
091 Vector v = new Vector(size);
092 v.setSize(size);
093 return v;
094 }
095
096 /**
097 * Constructs a <code>DefaultTableModel</code> with
098 * <code>rowCount</code> and <code>columnCount</code> of
099 * <code>null</code> object values.
100 *
101 * @param rowCount the number of rows the table holds
102 * @param columnCount the number of columns the table holds
103 *
104 * @see #setValueAt
105 */
106 public DefaultTableModel(int rowCount, int columnCount) {
107 this (newVector(columnCount), rowCount);
108 }
109
110 /**
111 * Constructs a <code>DefaultTableModel</code> with as many columns
112 * as there are elements in <code>columnNames</code>
113 * and <code>rowCount</code> of <code>null</code>
114 * object values. Each column's name will be taken from
115 * the <code>columnNames</code> vector.
116 *
117 * @param columnNames <code>vector</code> containing the names
118 * of the new columns; if this is
119 * <code>null</code> then the model has no columns
120 * @param rowCount the number of rows the table holds
121 * @see #setDataVector
122 * @see #setValueAt
123 */
124 public DefaultTableModel(Vector columnNames, int rowCount) {
125 setDataVector(newVector(rowCount), columnNames);
126 }
127
128 /**
129 * Constructs a <code>DefaultTableModel</code> with as many
130 * columns as there are elements in <code>columnNames</code>
131 * and <code>rowCount</code> of <code>null</code>
132 * object values. Each column's name will be taken from
133 * the <code>columnNames</code> array.
134 *
135 * @param columnNames <code>array</code> containing the names
136 * of the new columns; if this is
137 * <code>null</code> then the model has no columns
138 * @param rowCount the number of rows the table holds
139 * @see #setDataVector
140 * @see #setValueAt
141 */
142 public DefaultTableModel(Object[] columnNames, int rowCount) {
143 this (convertToVector(columnNames), rowCount);
144 }
145
146 /**
147 * Constructs a <code>DefaultTableModel</code> and initializes the table
148 * by passing <code>data</code> and <code>columnNames</code>
149 * to the <code>setDataVector</code> method.
150 *
151 * @param data the data of the table, a <code>Vector</code>
152 * of <code>Vector</code>s of <code>Object</code>
153 * values
154 * @param columnNames <code>vector</code> containing the names
155 * of the new columns
156 * @see #getDataVector
157 * @see #setDataVector
158 */
159 public DefaultTableModel(Vector data, Vector columnNames) {
160 setDataVector(data, columnNames);
161 }
162
163 /**
164 * Constructs a <code>DefaultTableModel</code> and initializes the table
165 * by passing <code>data</code> and <code>columnNames</code>
166 * to the <code>setDataVector</code>
167 * method. The first index in the <code>Object[][]</code> array is
168 * the row index and the second is the column index.
169 *
170 * @param data the data of the table
171 * @param columnNames the names of the columns
172 * @see #getDataVector
173 * @see #setDataVector
174 */
175 public DefaultTableModel(Object[][] data, Object[] columnNames) {
176 setDataVector(data, columnNames);
177 }
178
179 /**
180 * Returns the <code>Vector</code> of <code>Vectors</code>
181 * that contains the table's
182 * data values. The vectors contained in the outer vector are
183 * each a single row of values. In other words, to get to the cell
184 * at row 1, column 5: <p>
185 *
186 * <code>((Vector)getDataVector().elementAt(1)).elementAt(5);</code><p>
187 *
188 * @return the vector of vectors containing the tables data values
189 *
190 * @see #newDataAvailable
191 * @see #newRowsAdded
192 * @see #setDataVector
193 */
194 public Vector getDataVector() {
195 return dataVector;
196 }
197
198 private static Vector nonNullVector(Vector v) {
199 return (v != null) ? v : new Vector();
200 }
201
202 /**
203 * Replaces the current <code>dataVector</code> instance variable
204 * with the new <code>Vector</code> of rows, <code>dataVector</code>.
205 * Each row is represented in <code>dataVector</code> as a
206 * <code>Vector</code> of <code>Object</code> values.
207 * <code>columnIdentifiers</code> are the names of the new
208 * columns. The first name in <code>columnIdentifiers</code> is
209 * mapped to column 0 in <code>dataVector</code>. Each row in
210 * <code>dataVector</code> is adjusted to match the number of
211 * columns in <code>columnIdentifiers</code>
212 * either by truncating the <code>Vector</code> if it is too long,
213 * or adding <code>null</code> values if it is too short.
214 * <p>Note that passing in a <code>null</code> value for
215 * <code>dataVector</code> results in unspecified behavior,
216 * an possibly an exception.
217 *
218 * @param dataVector the new data vector
219 * @param columnIdentifiers the names of the columns
220 * @see #getDataVector
221 */
222 public void setDataVector(Vector dataVector,
223 Vector columnIdentifiers) {
224 this .dataVector = nonNullVector(dataVector);
225 this .columnIdentifiers = nonNullVector(columnIdentifiers);
226 justifyRows(0, getRowCount());
227 fireTableStructureChanged();
228 }
229
230 /**
231 * Replaces the value in the <code>dataVector</code> instance
232 * variable with the values in the array <code>dataVector</code>.
233 * The first index in the <code>Object[][]</code>
234 * array is the row index and the second is the column index.
235 * <code>columnIdentifiers</code> are the names of the new columns.
236 *
237 * @param dataVector the new data vector
238 * @param columnIdentifiers the names of the columns
239 * @see #setDataVector(Vector, Vector)
240 */
241 public void setDataVector(Object[][] dataVector,
242 Object[] columnIdentifiers) {
243 setDataVector(convertToVector(dataVector),
244 convertToVector(columnIdentifiers));
245 }
246
247 /**
248 * Equivalent to <code>fireTableChanged</code>.
249 *
250 * @param event the change event
251 *
252 */
253 public void newDataAvailable(TableModelEvent event) {
254 fireTableChanged(event);
255 }
256
257 //
258 // Manipulating rows
259 //
260
261 private void justifyRows(int from, int to) {
262 // Sometimes the DefaultTableModel is subclassed
263 // instead of the AbstractTableModel by mistake.
264 // Set the number of rows for the case when getRowCount
265 // is overridden.
266 dataVector.setSize(getRowCount());
267
268 for (int i = from; i < to; i++) {
269 if (dataVector.elementAt(i) == null) {
270 dataVector.setElementAt(new Vector(), i);
271 }
272 ((Vector) dataVector.elementAt(i))
273 .setSize(getColumnCount());
274 }
275 }
276
277 /**
278 * Ensures that the new rows have the correct number of columns.
279 * This is accomplished by using the <code>setSize</code> method in
280 * <code>Vector</code> which truncates vectors
281 * which are too long, and appends <code>null</code>s if they
282 * are too short.
283 * This method also sends out a <code>tableChanged</code>
284 * notification message to all the listeners.
285 *
286 * @param e this <code>TableModelEvent</code> describes
287 * where the rows were added.
288 * If <code>null</code> it assumes
289 * all the rows were newly added
290 * @see #getDataVector
291 */
292 public void newRowsAdded(TableModelEvent e) {
293 justifyRows(e.getFirstRow(), e.getLastRow() + 1);
294 fireTableChanged(e);
295 }
296
297 /**
298 * Equivalent to <code>fireTableChanged</code>.
299 *
300 * @param event the change event
301 *
302 */
303 public void rowsRemoved(TableModelEvent event) {
304 fireTableChanged(event);
305 }
306
307 /**
308 * Obsolete as of Java 2 platform v1.3. Please use <code>setRowCount</code> instead.
309 */
310 /*
311 * Sets the number of rows in the model. If the new size is greater
312 * than the current size, new rows are added to the end of the model
313 * If the new size is less than the current size, all
314 * rows at index <code>rowCount</code> and greater are discarded. <p>
315 *
316 * @param rowCount the new number of rows
317 * @see #setRowCount
318 */
319 public void setNumRows(int rowCount) {
320 int old = getRowCount();
321 if (old == rowCount) {
322 return;
323 }
324 dataVector.setSize(rowCount);
325 if (rowCount <= old) {
326 fireTableRowsDeleted(rowCount, old - 1);
327 } else {
328 justifyRows(old, rowCount);
329 fireTableRowsInserted(old, rowCount - 1);
330 }
331 }
332
333 /**
334 * Sets the number of rows in the model. If the new size is greater
335 * than the current size, new rows are added to the end of the model
336 * If the new size is less than the current size, all
337 * rows at index <code>rowCount</code> and greater are discarded. <p>
338 *
339 * @see #setColumnCount
340 * @since 1.3
341 */
342 public void setRowCount(int rowCount) {
343 setNumRows(rowCount);
344 }
345
346 /**
347 * Adds a row to the end of the model. The new row will contain
348 * <code>null</code> values unless <code>rowData</code> is specified.
349 * Notification of the row being added will be generated.
350 *
351 * @param rowData optional data of the row being added
352 */
353 public void addRow(Vector rowData) {
354 insertRow(getRowCount(), rowData);
355 }
356
357 /**
358 * Adds a row to the end of the model. The new row will contain
359 * <code>null</code> values unless <code>rowData</code> is specified.
360 * Notification of the row being added will be generated.
361 *
362 * @param rowData optional data of the row being added
363 */
364 public void addRow(Object[] rowData) {
365 addRow(convertToVector(rowData));
366 }
367
368 /**
369 * Inserts a row at <code>row</code> in the model. The new row
370 * will contain <code>null</code> values unless <code>rowData</code>
371 * is specified. Notification of the row being added will be generated.
372 *
373 * @param row the row index of the row to be inserted
374 * @param rowData optional data of the row being added
375 * @exception ArrayIndexOutOfBoundsException if the row was invalid
376 */
377 public void insertRow(int row, Vector rowData) {
378 dataVector.insertElementAt(rowData, row);
379 justifyRows(row, row + 1);
380 fireTableRowsInserted(row, row);
381 }
382
383 /**
384 * Inserts a row at <code>row</code> in the model. The new row
385 * will contain <code>null</code> values unless <code>rowData</code>
386 * is specified. Notification of the row being added will be generated.
387 *
388 * @param row the row index of the row to be inserted
389 * @param rowData optional data of the row being added
390 * @exception ArrayIndexOutOfBoundsException if the row was invalid
391 */
392 public void insertRow(int row, Object[] rowData) {
393 insertRow(row, convertToVector(rowData));
394 }
395
396 private static int gcd(int i, int j) {
397 return (j == 0) ? i : gcd(j, i % j);
398 }
399
400 private static void rotate(Vector v, int a, int b, int shift) {
401 int size = b - a;
402 int r = size - shift;
403 int g = gcd(size, r);
404 for (int i = 0; i < g; i++) {
405 int to = i;
406 Object tmp = v.elementAt(a + to);
407 for (int from = (to + r) % size; from != i; from = (to + r)
408 % size) {
409 v.setElementAt(v.elementAt(a + from), a + to);
410 to = from;
411 }
412 v.setElementAt(tmp, a + to);
413 }
414 }
415
416 /**
417 * Moves one or more rows from the inclusive range <code>start</code> to
418 * <code>end</code> to the <code>to</code> position in the model.
419 * After the move, the row that was at index <code>start</code>
420 * will be at index <code>to</code>.
421 * This method will send a <code>tableChanged</code> notification
422 * message to all the listeners. <p>
423 *
424 * <pre>
425 * Examples of moves:
426 * <p>
427 * 1. moveRow(1,3,5);
428 * a|B|C|D|e|f|g|h|i|j|k - before
429 * a|e|f|g|h|B|C|D|i|j|k - after
430 * <p>
431 * 2. moveRow(6,7,1);
432 * a|b|c|d|e|f|G|H|i|j|k - before
433 * a|G|H|b|c|d|e|f|i|j|k - after
434 * <p>
435 * </pre>
436 *
437 * @param start the starting row index to be moved
438 * @param end the ending row index to be moved
439 * @param to the destination of the rows to be moved
440 * @exception ArrayIndexOutOfBoundsException if any of the elements
441 * would be moved out of the table's range
442 *
443 */
444 public void moveRow(int start, int end, int to) {
445 int shift = to - start;
446 int first, last;
447 if (shift < 0) {
448 first = to;
449 last = end;
450 } else {
451 first = start;
452 last = to + end - start;
453 }
454 rotate(dataVector, first, last + 1, shift);
455
456 fireTableRowsUpdated(first, last);
457 }
458
459 /**
460 * Removes the row at <code>row</code> from the model. Notification
461 * of the row being removed will be sent to all the listeners.
462 *
463 * @param row the row index of the row to be removed
464 * @exception ArrayIndexOutOfBoundsException if the row was invalid
465 */
466 public void removeRow(int row) {
467 dataVector.removeElementAt(row);
468 fireTableRowsDeleted(row, row);
469 }
470
471 //
472 // Manipulating columns
473 //
474
475 /**
476 * Replaces the column identifiers in the model. If the number of
477 * <code>newIdentifier</code>s is greater than the current number
478 * of columns, new columns are added to the end of each row in the model.
479 * If the number of <code>newIdentifier</code>s is less than the current
480 * number of columns, all the extra columns at the end of a row are
481 * discarded. <p>
482 *
483 * @param columnIdentifiers vector of column identifiers. If
484 * <code>null</code>, set the model
485 * to zero columns
486 * @see #setNumRows
487 */
488 public void setColumnIdentifiers(Vector columnIdentifiers) {
489 setDataVector(dataVector, columnIdentifiers);
490 }
491
492 /**
493 * Replaces the column identifiers in the model. If the number of
494 * <code>newIdentifier</code>s is greater than the current number
495 * of columns, new columns are added to the end of each row in the model.
496 * If the number of <code>newIdentifier</code>s is less than the current
497 * number of columns, all the extra columns at the end of a row are
498 * discarded. <p>
499 *
500 * @param newIdentifiers array of column identifiers.
501 * If <code>null</code>, set
502 * the model to zero columns
503 * @see #setNumRows
504 */
505 public void setColumnIdentifiers(Object[] newIdentifiers) {
506 setColumnIdentifiers(convertToVector(newIdentifiers));
507 }
508
509 /**
510 * Sets the number of columns in the model. If the new size is greater
511 * than the current size, new columns are added to the end of the model
512 * with <code>null</code> cell values.
513 * If the new size is less than the current size, all columns at index
514 * <code>columnCount</code> and greater are discarded.
515 *
516 * @param columnCount the new number of columns in the model
517 *
518 * @see #setColumnCount
519 * @since 1.3
520 */
521 public void setColumnCount(int columnCount) {
522 columnIdentifiers.setSize(columnCount);
523 justifyRows(0, getRowCount());
524 fireTableStructureChanged();
525 }
526
527 /**
528 * Adds a column to the model. The new column will have the
529 * identifier <code>columnName</code>, which may be null. This method
530 * will send a
531 * <code>tableChanged</code> notification message to all the listeners.
532 * This method is a cover for <code>addColumn(Object, Vector)</code> which
533 * uses <code>null</code> as the data vector.
534 *
535 * @param columnName the identifier of the column being added
536 */
537 public void addColumn(Object columnName) {
538 addColumn(columnName, (Vector) null);
539 }
540
541 /**
542 * Adds a column to the model. The new column will have the
543 * identifier <code>columnName</code>, which may be null.
544 * <code>columnData</code> is the
545 * optional vector of data for the column. If it is <code>null</code>
546 * the column is filled with <code>null</code> values. Otherwise,
547 * the new data will be added to model starting with the first
548 * element going to row 0, etc. This method will send a
549 * <code>tableChanged</code> notification message to all the listeners.
550 *
551 * @param columnName the identifier of the column being added
552 * @param columnData optional data of the column being added
553 */
554 public void addColumn(Object columnName, Vector columnData) {
555 columnIdentifiers.addElement(columnName);
556 if (columnData != null) {
557 int columnSize = columnData.size();
558 if (columnSize > getRowCount()) {
559 dataVector.setSize(columnSize);
560 }
561 justifyRows(0, getRowCount());
562 int newColumn = getColumnCount() - 1;
563 for (int i = 0; i < columnSize; i++) {
564 Vector row = (Vector) dataVector.elementAt(i);
565 row.setElementAt(columnData.elementAt(i), newColumn);
566 }
567 } else {
568 justifyRows(0, getRowCount());
569 }
570
571 fireTableStructureChanged();
572 }
573
574 /**
575 * Adds a column to the model. The new column will have the
576 * identifier <code>columnName</code>. <code>columnData</code> is the
577 * optional array of data for the column. If it is <code>null</code>
578 * the column is filled with <code>null</code> values. Otherwise,
579 * the new data will be added to model starting with the first
580 * element going to row 0, etc. This method will send a
581 * <code>tableChanged</code> notification message to all the listeners.
582 *
583 * @see #addColumn(Object, Vector)
584 */
585 public void addColumn(Object columnName, Object[] columnData) {
586 addColumn(columnName, convertToVector(columnData));
587 }
588
589 //
590 // Implementing the TableModel interface
591 //
592
593 /**
594 * Returns the number of rows in this data table.
595 * @return the number of rows in the model
596 */
597 public int getRowCount() {
598 return dataVector.size();
599 }
600
601 /**
602 * Returns the number of columns in this data table.
603 * @return the number of columns in the model
604 */
605 public int getColumnCount() {
606 return columnIdentifiers.size();
607 }
608
609 /**
610 * Returns the column name.
611 *
612 * @return a name for this column using the string value of the
613 * appropriate member in <code>columnIdentifiers</code>.
614 * If <code>columnIdentifiers</code> does not have an entry
615 * for this index, returns the default
616 * name provided by the superclass.
617 */
618 public String getColumnName(int column) {
619 Object id = null;
620 // This test is to cover the case when
621 // getColumnCount has been subclassed by mistake ...
622 if (column < columnIdentifiers.size() && (column >= 0)) {
623 id = columnIdentifiers.elementAt(column);
624 }
625 return (id == null) ? super .getColumnName(column) : id
626 .toString();
627 }
628
629 /**
630 * Returns true regardless of parameter values.
631 *
632 * @param row the row whose value is to be queried
633 * @param column the column whose value is to be queried
634 * @return true
635 * @see #setValueAt
636 */
637 public boolean isCellEditable(int row, int column) {
638 return true;
639 }
640
641 /**
642 * Returns an attribute value for the cell at <code>row</code>
643 * and <code>column</code>.
644 *
645 * @param row the row whose value is to be queried
646 * @param column the column whose value is to be queried
647 * @return the value Object at the specified cell
648 * @exception ArrayIndexOutOfBoundsException if an invalid row or
649 * column was given
650 */
651 public Object getValueAt(int row, int column) {
652 Vector rowVector = (Vector) dataVector.elementAt(row);
653 return rowVector.elementAt(column);
654 }
655
656 /**
657 * Sets the object value for the cell at <code>column</code> and
658 * <code>row</code>. <code>aValue</code> is the new value. This method
659 * will generate a <code>tableChanged</code> notification.
660 *
661 * @param aValue the new value; this can be null
662 * @param row the row whose value is to be changed
663 * @param column the column whose value is to be changed
664 * @exception ArrayIndexOutOfBoundsException if an invalid row or
665 * column was given
666 */
667 public void setValueAt(Object aValue, int row, int column) {
668 Vector rowVector = (Vector) dataVector.elementAt(row);
669 rowVector.setElementAt(aValue, column);
670 fireTableCellUpdated(row, column);
671 }
672
673 //
674 // Protected Methods
675 //
676
677 /**
678 * Returns a vector that contains the same objects as the array.
679 * @param anArray the array to be converted
680 * @return the new vector; if <code>anArray</code> is <code>null</code>,
681 * returns <code>null</code>
682 */
683 protected static Vector convertToVector(Object[] anArray) {
684 if (anArray == null) {
685 return null;
686 }
687 Vector v = new Vector(anArray.length);
688 for (int i = 0; i < anArray.length; i++) {
689 v.addElement(anArray[i]);
690 }
691 return v;
692 }
693
694 /**
695 * Returns a vector of vectors that contains the same objects as the array.
696 * @param anArray the double array to be converted
697 * @return the new vector of vectors; if <code>anArray</code> is
698 * <code>null</code>, returns <code>null</code>
699 */
700 protected static Vector convertToVector(Object[][] anArray) {
701 if (anArray == null) {
702 return null;
703 }
704 Vector v = new Vector(anArray.length);
705 for (int i = 0; i < anArray.length; i++) {
706 v.addElement(convertToVector(anArray[i]));
707 }
708 return v;
709 }
710
711 } // End of class DefaultTableModel
|