Source for javax.swing.table.DefaultTableModel

   1: /* DefaultTableModel.java --
   2:    Copyright (C) 2002, 2004, 2005, 2006, 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:       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: }