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:       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:     if (columnData != null)
 358:     {
 359:       // check columnData array for cases where the number of items
 360:       // doesn't match the number of rows in the existing table
 361:       if (columnData.length > dataVector.size()) 
 362:       {
 363:         int rowsToAdd = columnData.length - dataVector.size();
 364:         addExtraRows(rowsToAdd, columnIdentifiers.size());
 365:       }
 366:       else if (columnData.length < dataVector.size())
 367:       {
 368:         Object[] tmp = new Object[dataVector.size()];
 369:         System.arraycopy(columnData, 0, tmp, 0, columnData.length);
 370:         columnData = tmp;
 371:       }
 372:     }
 373:     for (int i = 0; i < dataVector.size(); ++i)
 374:       {
 375:         ((Vector) dataVector.get(i)).add(columnData == null ? null : columnData[i]);
 376:       }
 377:     columnIdentifiers.add(columnName);
 378:     fireTableStructureChanged();
 379:   }
 380: 
 381:   /**
 382:    * Adds a new row containing the specified data to the table and sends a
 383:    * {@link TableModelEvent} to all registered listeners.
 384:    * 
 385:    * @param rowData the row data (<code>null</code> permitted).
 386:    */
 387:   public void addRow(Vector rowData) {
 388:     int rowIndex = dataVector.size();
 389:     dataVector.add(rowData);
 390:     newRowsAdded(new TableModelEvent(
 391:       this, rowIndex, rowIndex, -1, TableModelEvent.INSERT)
 392:     );
 393:   }
 394: 
 395:   /**
 396:    * Adds a new row containing the specified data to the table and sends a
 397:    * {@link TableModelEvent} to all registered listeners.
 398:    * 
 399:    * @param rowData the row data (<code>null</code> permitted).
 400:    */
 401:   public void addRow(Object[] rowData) {
 402:     addRow(convertToVector(rowData));
 403:   }
 404: 
 405:   /**
 406:    * Inserts a new row into the table.
 407:    * 
 408:    * @param row the row index.
 409:    * @param rowData the row data.
 410:    */
 411:   public void insertRow(int row, Vector rowData) {
 412:     dataVector.add(row, rowData);
 413:     fireTableRowsInserted(row,row);
 414:   }
 415: 
 416:   /**
 417:    * Inserts a new row into the table.
 418:    * 
 419:    * @param row the row index.
 420:    * @param rowData the row data.
 421:    */
 422:   public void insertRow(int row, Object[] rowData) {
 423:     insertRow(row, convertToVector(rowData));
 424:   }
 425: 
 426:   /**
 427:    * Moves the rows from <code>startIndex</code> to <code>endIndex</code>
 428:    * (inclusive) to the specified row.
 429:    * 
 430:    * @param startIndex the start row.
 431:    * @param endIndex the end row.
 432:    * @param toIndex the row to move to.
 433:    */
 434:   public void moveRow(int startIndex, int endIndex, int toIndex) {
 435:     Vector removed = new Vector();
 436:     for (int i = endIndex; i >= startIndex; i--)
 437:     {
 438:       removed.add(this.dataVector.remove(i));
 439:     }
 440:     for (int i = 0; i <= endIndex - startIndex; i++) 
 441:     {
 442:       dataVector.insertElementAt(removed.get(i), toIndex);  
 443:     }
 444:     int firstRow = Math.min(startIndex, toIndex);
 445:     int lastRow = Math.max(endIndex, toIndex + (endIndex - startIndex));
 446:     fireTableRowsUpdated(firstRow, lastRow);
 447:   }
 448: 
 449:   /**
 450:    * Removes a row from the table and sends a {@link TableModelEvent} to
 451:    * all registered listeners.
 452:    * 
 453:    * @param row the row index.
 454:    */
 455:   public void removeRow(int row) {
 456:     dataVector.remove(row);
 457:     fireTableRowsDeleted(row,row);
 458:   }
 459: 
 460:   /**
 461:    * Returns the number of rows in the model.
 462:    * 
 463:    * @return The row count.
 464:    */
 465:   public int getRowCount() {
 466:     return dataVector.size();
 467:   }
 468: 
 469:   /**
 470:    * Returns the number of columns in the model.
 471:    * 
 472:    * @return The column count.
 473:    */
 474:   public int getColumnCount() {
 475:     return (columnIdentifiers == null ? 0 : columnIdentifiers.size());
 476:   }
 477: 
 478:   /**
 479:    * Get the name of the column. If the column has the column identifier set,
 480:    * the return value is the result of the .toString() method call on that
 481:    * identifier. If the identifier is not explicitly set, the returned value
 482:    * is calculated by {@link AbstractTableModel#getColumnName(int)}.
 483:    * 
 484:    * @param column the column index.
 485:    * 
 486:    * @return The column name.
 487:    */
 488:   public String getColumnName(int column) {
 489:     String result = "";
 490:     if (columnIdentifiers == null) 
 491:       result = super.getColumnName(column);
 492:     else 
 493:     {
 494:       if (column < getColumnCount())
 495:       {
 496:         checkSize();
 497:         Object id = columnIdentifiers.get(column);
 498:         if (id != null) 
 499:           result = id.toString();
 500:         else
 501:           result = super.getColumnName(column);
 502:       }
 503:       else
 504:         result = super.getColumnName(column);
 505:     }
 506:     return result;
 507:   }
 508: 
 509:   /**
 510:    * Returns <code>true</code> if the specified cell can be modified, and
 511:    * <code>false</code> otherwise.  For this implementation, the method
 512:    * always returns <code>true</code>.
 513:    * 
 514:    * @param row the row index.
 515:    * @param column the column index.
 516:    * 
 517:    * @return <code>true</code> in all cases.
 518:    */
 519:   public boolean isCellEditable(int row, int column) {
 520:     return true;
 521:   }
 522: 
 523:   /**
 524:    * Returns the value at the specified cell in the table.
 525:    * 
 526:    * @param row the row index.
 527:    * @param column the column index.
 528:    * 
 529:    * @return The value (<code>Object</code>, possibly <code>null</code>) at 
 530:    *         the specified cell in the table.
 531:    */
 532:   public Object getValueAt(int row, int column) {
 533:     return ((Vector) dataVector.get(row)).get(column);
 534:   }
 535: 
 536:   /**
 537:    * Sets the value for the specified cell in the table and sends a 
 538:    * {@link TableModelEvent} to all registered listeners.
 539:    * 
 540:    * @param value the value (<code>Object</code>, <code>null</code> permitted).
 541:    * @param row the row index.
 542:    * @param column the column index.
 543:    */
 544:   public void setValueAt(Object value, int row, int column) {
 545:     ((Vector) dataVector.get(row)).set(column, value);
 546:     fireTableCellUpdated(row,column);
 547:   }
 548: 
 549:   /**
 550:    * Converts the data array to a <code>Vector</code>.
 551:    * 
 552:    * @param data the data array (<code>null</code> permitted).
 553:    * 
 554:    * @return A vector (or <code>null</code> if the data array 
 555:    *         is <code>null</code>).
 556:    */
 557:   protected static Vector convertToVector(Object[] data) {
 558:     if (data == null)
 559:       return null;
 560:     Vector vector = new Vector(data.length);
 561:     for (int i = 0; i < data.length; i++) 
 562:       vector.add(data[i]);
 563:     return vector;          
 564:   }
 565:   
 566:   /**
 567:    * Converts the data array to a <code>Vector</code> of rows.
 568:    * 
 569:    * @param data the data array (<code>null</code> permitted).
 570:    * 
 571:    * @return A vector (or <code>null</code> if the data array 
 572:    *         is <code>null</code>.
 573:    */
 574:   protected static Vector convertToVector(Object[][] data) {
 575:     if (data == null)
 576:       return null;
 577:     Vector vector = new Vector(data.length);
 578:     for (int i = 0; i < data.length; i++)
 579:       vector.add(convertToVector(data[i]));
 580:     return vector;
 581:   }
 582: 
 583:   /**
 584:    * This method adds some rows to <code>dataVector</code>.
 585:    *
 586:    * @param rowsToAdd number of rows to add
 587:    * @param nbColumns size of the added rows
 588:    */
 589:   private void addExtraRows(int rowsToAdd, int nbColumns)
 590:   {
 591:     for (int i = 0; i < rowsToAdd; i++) 
 592:       {
 593:         Vector tmp = new Vector();
 594:         tmp.setSize(columnIdentifiers.size());
 595:         dataVector.add(tmp);
 596:       } 
 597:   }
 598: 
 599:   /**
 600:    * Checks the real columns/rows sizes against the ones returned by
 601:    * <code>getColumnCount()</code> and <code>getRowCount()</code>.
 602:    * If the supposed one are bigger, then we grow <code>columIdentifiers</code>
 603:    * and <code>dataVector</code> to their expected size.
 604:    */
 605:   private void checkSize()
 606:   {
 607:     int columnCount = getColumnCount();
 608:     int rowCount = getRowCount();
 609:     
 610:     if (columnCount > columnIdentifiers.size())
 611:       columnIdentifiers.setSize(columnCount);
 612:            
 613:     if (rowCount > dataVector.size())
 614:       {
 615:         int rowsToAdd = rowCount - dataVector.size();
 616:         addExtraRows(rowsToAdd, columnCount);
 617:       }
 618:   }
 619: }