Source for javax.swing.table.DefaultTableModel

   1: /* DefaultTableModel.java --
   2:    Copyright (C) 2002, 2004, 2005,  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing.table;
  40: 
  41: import java.io.Serializable;
  42: import java.util.Vector;
  43: 
  44: import javax.swing.event.TableModelEvent;
  45: 
  46: /**
  47:  * A two dimensional data structure used to store <code>Object</code> 
  48:  * instances, usually for display in a <code>JTable</code> component.
  49:  * 
  50:  * @author    Andrew Selkirk
  51:  */
  52: public class DefaultTableModel extends AbstractTableModel
  53:   implements Serializable
  54: {
  55:   static final long serialVersionUID = 6680042567037222321L;
  56: 
  57:   /**
  58:    * Storage for the rows in the table (each row is itself 
  59:    * a <code>Vector</code>).
  60:    */
  61:   protected Vector dataVector;
  62: 
  63:   /**
  64:    * Storage for the column identifiers.
  65:    */
  66:   protected Vector columnIdentifiers;
  67: 
  68:   /**
  69:    * Creates an empty table with zero rows and zero columns.
  70:    */
  71:   public DefaultTableModel() 
  72:   {
  73:     this(0, 0);
  74:   }
  75:   
  76:   /**
  77:    * Creates a new table with the specified number of rows and columns.
  78:    * All cells in the table are initially empty (set to <code>null</code>).
  79:    * 
  80:    * @param numRows  the number of rows.
  81:    * @param numColumns  the number of columns.
  82:    */
  83:   public DefaultTableModel(int numRows, int numColumns) 
  84:   {
  85:     Vector defaultNames = new Vector(numColumns);
  86:     Vector data = new Vector(numRows);
  87:     for (int i = 0; i < numColumns; i++) 
  88:       {
  89:         defaultNames.add(super.getColumnName(i));
  90:       }          
  91:     for (int r = 0; r < numRows; r++) 
  92:       {
  93:         Vector tmp = new Vector(numColumns);
  94:         tmp.setSize(numColumns);
  95:         data.add(tmp);
  96:       }
  97:     setDataVector(data, defaultNames);
  98:   }
  99:   
 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:       for (int i = 0; i < rowsToAdd; i++) 
 298:         {
 299:           Vector tmp = new Vector();
 300:           tmp.setSize(columnIdentifiers.size());
 301:           dataVector.add(tmp);
 302:         } 
 303:       fireTableRowsInserted(existingRowCount,rowCount-1);
 304:     }
 305:   }
 306: 
 307:   /**
 308:    * Sets the number of columns in the table.  Existing rows are truncated
 309:    * or padded with <code>null</code> values to match the new column count.
 310:    * A {@link TableModelEvent} is sent to all registered listeners.
 311:    * 
 312:    * @param columnCount the column count.
 313:    */
 314:   public void setColumnCount(int columnCount) 
 315:   {
 316:     for (int i = 0; i < dataVector.size(); ++i)
 317:       {
 318:         ((Vector) dataVector.get(i)).setSize(columnCount);
 319:       }
 320:     if (columnIdentifiers != null)  
 321:       columnIdentifiers.setSize(columnCount);
 322:     fireTableStructureChanged();
 323:   }
 324: 
 325:   /**
 326:    * Adds a column with the specified name to the table.  All cell values
 327:    * for the column are initially set to <code>null</code>.
 328:    * 
 329:    * @param columnName the column name (<code>null</code> permitted).
 330:    */
 331:   public void addColumn(Object columnName) 
 332:   {
 333:     addColumn(columnName, (Object[]) null);
 334:   }
 335: 
 336:   /**
 337:    * Adds a column with the specified name and data values to the table.  
 338:    * 
 339:    * @param columnName the column name (<code>null</code> permitted).
 340:    * @param columnData the column data.
 341:    */
 342:   public void addColumn(Object columnName, Vector columnData) 
 343:   {
 344:     Object[] dataArray = null;
 345:     if (columnData != null) 
 346:     {
 347:       int rowCount = dataVector.size();
 348:       if (columnData.size() < rowCount)
 349:         columnData.setSize(rowCount);
 350:       dataArray = columnData.toArray();
 351:     }
 352:     addColumn(columnName, dataArray);
 353:   }
 354: 
 355:   /**
 356:    * Adds a column with the specified name and data values to the table.
 357:    * 
 358:    * @param columnName the column name (<code>null</code> permitted).
 359:    * @param columnData the column data.
 360:    */
 361:   public void addColumn(Object columnName, Object[] columnData) {
 362:     if (columnData != null)
 363:     {
 364:       // check columnData array for cases where the number of items
 365:       // doesn't match the number of rows in the existing table
 366:       if (columnData.length > dataVector.size()) 
 367:       {
 368:         int rowsToAdd = columnData.length - dataVector.size();
 369:         for (int i = 0; i < rowsToAdd; i++) 
 370:         {
 371:           Vector tmp = new Vector();
 372:           tmp.setSize(columnIdentifiers.size());
 373:           dataVector.add(tmp);
 374:         }
 375:       }
 376:       else if (columnData.length < dataVector.size())
 377:       {
 378:         Object[] tmp = new Object[dataVector.size()];
 379:         System.arraycopy(columnData, 0, tmp, 0, columnData.length);
 380:         columnData = tmp;
 381:       }
 382:     }
 383:     for (int i = 0; i < dataVector.size(); ++i)
 384:       {
 385:         ((Vector) dataVector.get(i)).add(columnData == null ? null : columnData[i]);
 386:       }
 387:     columnIdentifiers.add(columnName);
 388:     fireTableStructureChanged();
 389:   }
 390: 
 391:   /**
 392:    * Adds a new row containing the specified data to the table and sends a
 393:    * {@link TableModelEvent} to all registered listeners.
 394:    * 
 395:    * @param rowData the row data (<code>null</code> permitted).
 396:    */
 397:   public void addRow(Vector rowData) {
 398:     int rowIndex = dataVector.size();
 399:     dataVector.add(rowData);
 400:     newRowsAdded(new TableModelEvent(
 401:       this, rowIndex, rowIndex, -1, TableModelEvent.INSERT)
 402:     );
 403:   }
 404: 
 405:   /**
 406:    * Adds a new row containing the specified data to the table and sends a
 407:    * {@link TableModelEvent} to all registered listeners.
 408:    * 
 409:    * @param rowData the row data (<code>null</code> permitted).
 410:    */
 411:   public void addRow(Object[] rowData) {
 412:     addRow(convertToVector(rowData));
 413:   }
 414: 
 415:   /**
 416:    * Inserts a new row into the table.
 417:    * 
 418:    * @param row the row index.
 419:    * @param rowData the row data.
 420:    */
 421:   public void insertRow(int row, Vector rowData) {
 422:     dataVector.add(row, rowData);
 423:     fireTableRowsInserted(row,row);
 424:   }
 425: 
 426:   /**
 427:    * Inserts a new row into the table.
 428:    * 
 429:    * @param row the row index.
 430:    * @param rowData the row data.
 431:    */
 432:   public void insertRow(int row, Object[] rowData) {
 433:     insertRow(row, convertToVector(rowData));
 434:   }
 435: 
 436:   /**
 437:    * Moves the rows from <code>startIndex</code> to <code>endIndex</code>
 438:    * (inclusive) to the specified row.
 439:    * 
 440:    * @param startIndex the start row.
 441:    * @param endIndex the end row.
 442:    * @param toIndex the row to move to.
 443:    */
 444:   public void moveRow(int startIndex, int endIndex, int toIndex) {
 445:     Vector removed = new Vector();
 446:     for (int i = endIndex; i >= startIndex; i--)
 447:     {
 448:       removed.add(this.dataVector.remove(i));
 449:     }
 450:     for (int i = 0; i <= endIndex - startIndex; i++) 
 451:     {
 452:       dataVector.insertElementAt(removed.get(i), toIndex);  
 453:     }
 454:     int firstRow = Math.min(startIndex, toIndex);
 455:     int lastRow = Math.max(endIndex, toIndex + (endIndex - startIndex));
 456:     fireTableRowsUpdated(firstRow, lastRow);
 457:   }
 458: 
 459:   /**
 460:    * Removes a row from the table and sends a {@link TableModelEvent} to
 461:    * all registered listeners.
 462:    * 
 463:    * @param row the row index.
 464:    */
 465:   public void removeRow(int row) {
 466:     dataVector.remove(row);
 467:     fireTableRowsDeleted(row,row);
 468:   }
 469: 
 470:   /**
 471:    * Returns the number of rows in the model.
 472:    * 
 473:    * @return The row count.
 474:    */
 475:   public int getRowCount() {
 476:     return dataVector.size();
 477:   }
 478: 
 479:   /**
 480:    * Returns the number of columns in the model.
 481:    * 
 482:    * @return The column count.
 483:    */
 484:   public int getColumnCount() {
 485:     return (columnIdentifiers == null ? 0 : columnIdentifiers.size());
 486:   }
 487: 
 488:   /**
 489:    * Returns the name of the specified column.
 490:    * 
 491:    * @param column the column index.
 492:    * 
 493:    * @return The column name.
 494:    */
 495:   public String getColumnName(int column) {
 496:     String result = "";
 497:     if (columnIdentifiers == null) 
 498:       result = super.getColumnName(column);
 499:     else 
 500:     {
 501:       if (column < getColumnCount())
 502:       {  
 503:         Object id = columnIdentifiers.get(column);
 504:         if (id != null) 
 505:           result = id.toString();
 506:         else
 507:           result = super.getColumnName(column);
 508:       }
 509:       else
 510:         result = super.getColumnName(column);
 511:     }
 512:     return result;
 513:   }
 514: 
 515:   /**
 516:    * Returns <code>true</code> if the specified cell can be modified, and
 517:    * <code>false</code> otherwise.  For this implementation, the method
 518:    * always returns <code>true</code>.
 519:    * 
 520:    * @param row the row index.
 521:    * @param column the column index.
 522:    * 
 523:    * @return <code>true</code> in all cases.
 524:    */
 525:   public boolean isCellEditable(int row, int column) {
 526:     return true;
 527:   }
 528: 
 529:   /**
 530:    * Returns the value at the specified cell in the table.
 531:    * 
 532:    * @param row the row index.
 533:    * @param column the column index.
 534:    * 
 535:    * @return The value (<code>Object</code>, possibly <code>null</code>) at 
 536:    *         the specified cell in the table.
 537:    */
 538:   public Object getValueAt(int row, int column) {
 539:     return ((Vector) dataVector.get(row)).get(column);
 540:   }
 541: 
 542:   /**
 543:    * Sets the value for the specified cell in the table and sends a 
 544:    * {@link TableModelEvent} to all registered listeners.
 545:    * 
 546:    * @param value the value (<code>Object</code>, <code>null</code> permitted).
 547:    * @param row the row index.
 548:    * @param column the column index.
 549:    */
 550:   public void setValueAt(Object value, int row, int column) {
 551:     ((Vector) dataVector.get(row)).set(column, value);
 552:     fireTableCellUpdated(row,column);
 553:   }
 554: 
 555:   /**
 556:    * Converts the data array to a <code>Vector</code>.
 557:    * 
 558:    * @param data the data array (<code>null</code> permitted).
 559:    * 
 560:    * @return A vector (or <code>null</code> if the data array 
 561:    *         is <code>null</code>).
 562:    */
 563:   protected static Vector convertToVector(Object[] data) {
 564:     if (data == null)
 565:       return null;
 566:     Vector vector = new Vector(data.length);
 567:     for (int i = 0; i < data.length; i++) 
 568:       vector.add(data[i]);
 569:     return vector;          
 570:   }
 571:   
 572:   /**
 573:    * Converts the data array to a <code>Vector</code> of rows.
 574:    * 
 575:    * @param data the data array (<code>null</code> permitted).
 576:    * 
 577:    * @return A vector (or <code>null</code> if the data array 
 578:    *         is <code>null</code>.
 579:    */
 580:   protected static Vector convertToVector(Object[][] data) {
 581:     if (data == null)
 582:       return null;
 583:     Vector vector = new Vector(data.length);
 584:     for (int i = 0; i < data.length; i++)
 585:       vector.add(convertToVector(data[i]));
 586:     return vector;
 587:   }
 588: }