Frames | No Frames |
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: }