001/* DefaultTableModel.java -- 002 Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. 003 004This file is part of GNU Classpath. 005 006GNU Classpath is free software; you can redistribute it and/or modify 007it under the terms of the GNU General Public License as published by 008the Free Software Foundation; either version 2, or (at your option) 009any later version. 010 011GNU Classpath is distributed in the hope that it will be useful, but 012WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014General Public License for more details. 015 016You should have received a copy of the GNU General Public License 017along with GNU Classpath; see the file COPYING. If not, write to the 018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01902110-1301 USA. 020 021Linking this library statically or dynamically with other modules is 022making a combined work based on this library. Thus, the terms and 023conditions of the GNU General Public License cover the whole 024combination. 025 026As a special exception, the copyright holders of this library give you 027permission to link this library with independent modules to produce an 028executable, regardless of the license terms of these independent 029modules, and to copy and distribute the resulting executable under 030terms of your choice, provided that you also meet, for each linked 031independent module, the terms and conditions of the license of that 032module. An independent module is a module which is not derived from 033or based on this library. If you modify this library, you may extend 034this exception to your version of the library, but you are not 035obligated to do so. If you do not wish to do so, delete this 036exception statement from your version. */ 037 038 039package javax.swing.table; 040 041import java.io.Serializable; 042import java.util.Vector; 043 044import javax.swing.event.TableModelEvent; 045 046/** 047 * A two dimensional data structure used to store <code>Object</code> 048 * instances, usually for display in a <code>JTable</code> component. 049 * 050 * @author Andrew Selkirk 051 */ 052public class DefaultTableModel extends AbstractTableModel 053 implements Serializable 054{ 055 static final long serialVersionUID = 6680042567037222321L; 056 057 /** 058 * Storage for the rows in the table (each row is itself 059 * a <code>Vector</code>). 060 */ 061 protected Vector dataVector; 062 063 /** 064 * Storage for the column identifiers. 065 */ 066 protected Vector columnIdentifiers; 067 068 /** 069 * Creates an empty table with zero rows and zero columns. 070 */ 071 public DefaultTableModel() 072 { 073 this(0, 0); 074 } 075 076 /** 077 * Creates a new table with the specified number of rows and columns. 078 * All cells in the table are initially empty (set to <code>null</code>). 079 * 080 * @param numRows the number of rows. 081 * @param numColumns the number of columns. 082 */ 083 public DefaultTableModel(int numRows, int numColumns) 084 { 085 Vector defaultNames = new Vector(numColumns); 086 Vector data = new Vector(numRows); 087 for (int i = 0; i < numColumns; i++) 088 { 089 defaultNames.add(super.getColumnName(i)); 090 } 091 for (int r = 0; r < numRows; r++) 092 { 093 Vector tmp = new Vector(numColumns); 094 tmp.setSize(numColumns); 095 data.add(tmp); 096 } 097 setDataVector(data, defaultNames); 098 } 099 100 /** 101 * Creates a new table with the specified column names and number of 102 * rows. The number of columns is determined by the number of column 103 * names supplied. 104 * 105 * @param columnNames the column names. 106 * @param numRows the number of rows. 107 */ 108 public DefaultTableModel(Vector columnNames, int numRows) 109 { 110 if (numRows < 0) 111 throw new IllegalArgumentException("numRows < 0"); 112 Vector data = new Vector(); 113 int numColumns = 0; 114 115 if (columnNames != null) 116 numColumns = columnNames.size(); 117 118 while (0 < numRows--) 119 { 120 Vector rowData = new Vector(); 121 rowData.setSize(numColumns); 122 data.add(rowData); 123 } 124 setDataVector(data, columnNames); 125 } 126 127 /** 128 * Creates a new table with the specified column names and row count. 129 * 130 * @param columnNames the column names. 131 * @param numRows the number of rows. 132 */ 133 public DefaultTableModel(Object[] columnNames, int numRows) 134 { 135 this(convertToVector(columnNames), numRows); 136 } 137 138 /** 139 * Creates a new table with the specified data values and column names. 140 * 141 * @param data the data values. 142 * @param columnNames the column names. 143 */ 144 public DefaultTableModel(Vector data, Vector columnNames) 145 { 146 setDataVector(data, columnNames); 147 } 148 149 /** 150 * Creates a new table with the specified data values and column names. 151 * 152 * @param data the data values. 153 * @param columnNames the column names. 154 */ 155 public DefaultTableModel(Object[][] data, Object[] columnNames) 156 { 157 this(convertToVector(data), convertToVector(columnNames)); 158 } 159 160 /** 161 * Returns the vector containing the row data for the table. 162 * 163 * @return The data vector. 164 */ 165 public Vector getDataVector() 166 { 167 return dataVector; 168 } 169 170 /** 171 * Sets the data and column identifiers for the table. The data vector 172 * contains a <code>Vector</code> for each row in the table - if the 173 * number of objects in each row does not match the number of column 174 * names specified, the row data is truncated or expanded (by adding 175 * <code>null</code> values) as required. 176 * 177 * @param data the data for the table (a vector of row vectors). 178 * @param columnNames the column names. 179 * 180 * @throws NullPointerException if either argument is <code>null</code>. 181 */ 182 public void setDataVector(Vector data, Vector columnNames) 183 { 184 if (data == null) 185 dataVector = new Vector(); 186 else 187 dataVector = data; 188 setColumnIdentifiers(columnNames); 189 } 190 191 /** 192 * Sets the data and column identifiers for the table. 193 * 194 * @param data the data for the table. 195 * @param columnNames the column names. 196 * 197 * @throws NullPointerException if either argument is <code>null</code>. 198 */ 199 public void setDataVector(Object[][] data, Object[] columnNames) 200 { 201 setDataVector(convertToVector(data), 202 convertToVector(columnNames)); 203 } 204 205 /** 206 * Sends the specified <code>event</code> to all registered listeners. 207 * This method is equivalent to 208 * {@link AbstractTableModel#fireTableChanged(TableModelEvent)}. 209 * 210 * @param event the event. 211 */ 212 public void newDataAvailable(TableModelEvent event) 213 { 214 fireTableChanged(event); 215 } 216 217 /** 218 * Sends the specified <code>event</code> to all registered listeners. 219 * This method is equivalent to 220 * {@link AbstractTableModel#fireTableChanged(TableModelEvent)}. 221 * 222 * @param event the event. 223 */ 224 public void newRowsAdded(TableModelEvent event) 225 { 226 fireTableChanged(event); 227 } 228 229 /** 230 * Sends the specified <code>event</code> to all registered listeners. 231 * This method is equivalent to 232 * {@link AbstractTableModel#fireTableChanged(TableModelEvent)}. 233 * 234 * @param event the event. 235 */ 236 public void rowsRemoved(TableModelEvent event) 237 { 238 fireTableChanged(event); 239 } 240 241 /** 242 * Sets the column identifiers, updates the data rows (truncating 243 * or padding each row with <code>null</code> values) to match the 244 * number of columns, and sends a {@link TableModelEvent} to all 245 * registered listeners. 246 * 247 * @param columnIdentifiers the column identifiers. 248 */ 249 public void setColumnIdentifiers(Vector columnIdentifiers) 250 { 251 this.columnIdentifiers = columnIdentifiers; 252 setColumnCount(columnIdentifiers == null ? 0 : columnIdentifiers.size()); 253 } 254 255 /** 256 * Sets the column identifiers, updates the data rows (truncating 257 * or padding each row with <code>null</code> values) to match the 258 * number of columns, and sends a {@link TableModelEvent} to all 259 * registered listeners. 260 * 261 * @param columnIdentifiers the column identifiers. 262 */ 263 public void setColumnIdentifiers(Object[] columnIdentifiers) 264 { 265 setColumnIdentifiers(convertToVector(columnIdentifiers)); 266 } 267 268 /** 269 * This method is obsolete, use {@link #setRowCount(int)} instead. 270 * 271 * @param numRows the number of rows. 272 */ 273 public void setNumRows(int numRows) 274 { 275 setRowCount(numRows); 276 } 277 278 /** 279 * Sets the number of rows in the table. If <code>rowCount</code> is less 280 * than the current number of rows in the table, rows are discarded. 281 * If <code>rowCount</code> is greater than the current number of rows in 282 * the table, new (empty) rows are added. 283 * 284 * @param rowCount the row count. 285 */ 286 public void setRowCount(int rowCount) 287 { 288 int existingRowCount = dataVector.size(); 289 if (rowCount < existingRowCount) 290 { 291 dataVector.setSize(rowCount); 292 fireTableRowsDeleted(rowCount, existingRowCount - 1); 293 } 294 else 295 { 296 int rowsToAdd = rowCount - existingRowCount; 297 addExtraRows(rowsToAdd, columnIdentifiers.size()); 298 fireTableRowsInserted(existingRowCount, rowCount - 1); 299 } 300 } 301 302 /** 303 * Sets the number of columns in the table. Existing rows are truncated 304 * or padded with <code>null</code> values to match the new column count. 305 * A {@link TableModelEvent} is sent to all registered listeners. 306 * 307 * @param columnCount the column count. 308 */ 309 public void setColumnCount(int columnCount) 310 { 311 for (int i = 0; i < dataVector.size(); ++i) 312 { 313 ((Vector) dataVector.get(i)).setSize(columnCount); 314 } 315 if (columnIdentifiers != null) 316 columnIdentifiers.setSize(columnCount); 317 fireTableStructureChanged(); 318 } 319 320 /** 321 * Adds a column with the specified name to the table. All cell values 322 * for the column are initially set to <code>null</code>. 323 * 324 * @param columnName the column name (<code>null</code> permitted). 325 */ 326 public void addColumn(Object columnName) 327 { 328 addColumn(columnName, (Object[]) null); 329 } 330 331 /** 332 * Adds a column with the specified name and data values to the table. 333 * 334 * @param columnName the column name (<code>null</code> permitted). 335 * @param columnData the column data. 336 */ 337 public void addColumn(Object columnName, Vector columnData) 338 { 339 Object[] dataArray = null; 340 if (columnData != null) 341 { 342 int rowCount = dataVector.size(); 343 if (columnData.size() < rowCount) 344 columnData.setSize(rowCount); 345 dataArray = columnData.toArray(); 346 } 347 addColumn(columnName, dataArray); 348 } 349 350 /** 351 * Adds a column with the specified name and data values to the table. 352 * 353 * @param columnName the column name (<code>null</code> permitted). 354 * @param columnData the column data. 355 */ 356 public void addColumn(Object columnName, Object[] columnData) 357 { 358 if (columnData != null) 359 { 360 // check columnData array for cases where the number of items 361 // doesn't match the number of rows in the existing table 362 if (columnData.length > dataVector.size()) 363 { 364 int rowsToAdd = columnData.length - dataVector.size(); 365 addExtraRows(rowsToAdd, columnIdentifiers.size()); 366 } 367 else if (columnData.length < dataVector.size()) 368 { 369 Object[] tmp = new Object[dataVector.size()]; 370 System.arraycopy(columnData, 0, tmp, 0, columnData.length); 371 columnData = tmp; 372 } 373 } 374 for (int i = 0; i < dataVector.size(); ++i) 375 { 376 ((Vector) dataVector.get(i)).add(columnData == null ? null : columnData[i]); 377 } 378 columnIdentifiers.add(columnName); 379 fireTableStructureChanged(); 380 } 381 382 /** 383 * Adds a new row containing the specified data to the table and sends a 384 * {@link TableModelEvent} to all registered listeners. 385 * 386 * @param rowData the row data (<code>null</code> permitted). 387 */ 388 public void addRow(Vector rowData) 389 { 390 int rowIndex = dataVector.size(); 391 dataVector.add(rowData); 392 newRowsAdded(new TableModelEvent( 393 this, rowIndex, rowIndex, -1, TableModelEvent.INSERT) 394 ); 395 } 396 397 /** 398 * Adds a new row containing the specified data to the table and sends a 399 * {@link TableModelEvent} to all registered listeners. 400 * 401 * @param rowData the row data (<code>null</code> permitted). 402 */ 403 public void addRow(Object[] rowData) 404 { 405 addRow(convertToVector(rowData)); 406 } 407 408 /** 409 * Inserts a new row into the table. 410 * 411 * @param row the row index. 412 * @param rowData the row data. 413 */ 414 public void insertRow(int row, Vector rowData) 415 { 416 dataVector.add(row, rowData); 417 fireTableRowsInserted(row, row); 418 } 419 420 /** 421 * Inserts a new row into the table. 422 * 423 * @param row the row index. 424 * @param rowData the row data. 425 */ 426 public void insertRow(int row, Object[] rowData) 427 { 428 insertRow(row, convertToVector(rowData)); 429 } 430 431 /** 432 * Moves the rows from <code>startIndex</code> to <code>endIndex</code> 433 * (inclusive) to the specified row. 434 * 435 * @param startIndex the start row. 436 * @param endIndex the end row. 437 * @param toIndex the row to move to. 438 */ 439 public void moveRow(int startIndex, int endIndex, int toIndex) 440 { 441 Vector removed = new Vector(); 442 for (int i = endIndex; i >= startIndex; i--) 443 { 444 removed.add(this.dataVector.remove(i)); 445 } 446 for (int i = 0; i <= endIndex - startIndex; i++) 447 { 448 dataVector.insertElementAt(removed.get(i), toIndex); 449 } 450 int firstRow = Math.min(startIndex, toIndex); 451 int lastRow = Math.max(endIndex, toIndex + (endIndex - startIndex)); 452 fireTableRowsUpdated(firstRow, lastRow); 453 } 454 455 /** 456 * Removes a row from the table and sends a {@link TableModelEvent} to 457 * all registered listeners. 458 * 459 * @param row the row index. 460 */ 461 public void removeRow(int row) 462 { 463 dataVector.remove(row); 464 fireTableRowsDeleted(row, row); 465 } 466 467 /** 468 * Returns the number of rows in the model. 469 * 470 * @return The row count. 471 */ 472 public int getRowCount() 473 { 474 return dataVector.size(); 475 } 476 477 /** 478 * Returns the number of columns in the model. 479 * 480 * @return The column count. 481 */ 482 public int getColumnCount() 483 { 484 return columnIdentifiers == null ? 0 : columnIdentifiers.size(); 485 } 486 487 /** 488 * Get the name of the column. If the column has the column identifier set, 489 * the return value is the result of the .toString() method call on that 490 * identifier. If the identifier is not explicitly set, the returned value 491 * is calculated by {@link AbstractTableModel#getColumnName(int)}. 492 * 493 * @param column the column index. 494 * 495 * @return The column name. 496 */ 497 public String getColumnName(int column) 498 { 499 String result = ""; 500 if (columnIdentifiers == null) 501 result = super.getColumnName(column); 502 else 503 { 504 if (column < getColumnCount()) 505 { 506 checkSize(); 507 Object id = columnIdentifiers.get(column); 508 if (id != null) 509 result = id.toString(); 510 else 511 result = super.getColumnName(column); 512 } 513 else 514 result = super.getColumnName(column); 515 } 516 return result; 517 } 518 519 /** 520 * Returns <code>true</code> if the specified cell can be modified, and 521 * <code>false</code> otherwise. For this implementation, the method 522 * always returns <code>true</code>. 523 * 524 * @param row the row index. 525 * @param column the column index. 526 * 527 * @return <code>true</code> in all cases. 528 */ 529 public boolean isCellEditable(int row, int column) 530 { 531 return true; 532 } 533 534 /** 535 * Returns the value at the specified cell in the table. 536 * 537 * @param row the row index. 538 * @param column the column index. 539 * 540 * @return The value (<code>Object</code>, possibly <code>null</code>) at 541 * the specified cell in the table. 542 */ 543 public Object getValueAt(int row, int column) 544 { 545 return ((Vector) dataVector.get(row)).get(column); 546 } 547 548 /** 549 * Sets the value for the specified cell in the table and sends a 550 * {@link TableModelEvent} to all registered listeners. 551 * 552 * @param value the value (<code>Object</code>, <code>null</code> permitted). 553 * @param row the row index. 554 * @param column the column index. 555 */ 556 public void setValueAt(Object value, int row, int column) 557 { 558 ((Vector) dataVector.get(row)).set(column, value); 559 fireTableCellUpdated(row, column); 560 } 561 562 /** 563 * Converts the data array to a <code>Vector</code>. 564 * 565 * @param data the data array (<code>null</code> permitted). 566 * 567 * @return A vector (or <code>null</code> if the data array 568 * is <code>null</code>). 569 */ 570 protected static Vector convertToVector(Object[] data) 571 { 572 if (data == null) 573 return null; 574 Vector vector = new Vector(data.length); 575 for (int i = 0; i < data.length; i++) 576 vector.add(data[i]); 577 return vector; 578 } 579 580 /** 581 * Converts the data array to a <code>Vector</code> of rows. 582 * 583 * @param data the data array (<code>null</code> permitted). 584 * 585 * @return A vector (or <code>null</code> if the data array 586 * is <code>null</code>. 587 */ 588 protected static Vector convertToVector(Object[][] data) 589 { 590 if (data == null) 591 return null; 592 Vector vector = new Vector(data.length); 593 for (int i = 0; i < data.length; i++) 594 vector.add(convertToVector(data[i])); 595 return vector; 596 } 597 598 /** 599 * This method adds some rows to <code>dataVector</code>. 600 * 601 * @param rowsToAdd number of rows to add 602 * @param nbColumns size of the added rows 603 */ 604 private void addExtraRows(int rowsToAdd, int nbColumns) 605 { 606 for (int i = 0; i < rowsToAdd; i++) 607 { 608 Vector tmp = new Vector(); 609 tmp.setSize(columnIdentifiers.size()); 610 dataVector.add(tmp); 611 } 612 } 613 614 /** 615 * Checks the real columns/rows sizes against the ones returned by 616 * <code>getColumnCount()</code> and <code>getRowCount()</code>. 617 * If the supposed one are bigger, then we grow <code>columIdentifiers</code> 618 * and <code>dataVector</code> to their expected size. 619 */ 620 private void checkSize() 621 { 622 int columnCount = getColumnCount(); 623 int rowCount = getRowCount(); 624 625 if (columnCount > columnIdentifiers.size()) 626 columnIdentifiers.setSize(columnCount); 627 628 if (dataVector != null && rowCount > dataVector.size()) 629 { 630 int rowsToAdd = rowCount - dataVector.size(); 631 addExtraRows(rowsToAdd, columnCount); 632 } 633 } 634}