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