API Flaws in 0.5 1). The checkDefaultDataModel() method in the JTable used "instanceOf" to see if its model was a DefaultTableModel. The following methods in the JTable relied on checkDefaultDataModel(): removeColumn(Object) addColumn(Object columnIdentifier, Vector columnData) addColumn(Object, int, TableCellRender, TableCellEditor, Vector) removeColumn(Object columnIdentifier) addRow(Vector rowData) addRow(Object[] rowData) insertRow(int rowIndex, Vector rowData) insertRow(int rowIndex, Object[] rowData) removeRow(int rowIndex) moveRow(int startIndex, int endIndex, int toIndex) setNumRows(int newSize) setDataVector(Vector newData, Vector columnIds) setDataVector(Object[][] newData, Object[] columnIds) checkDefaultTableModel() This made it difficult to tell from the API which methods would work with other models. None of the above methods could have the same meaning unless the model was a DefaultTableModel. Solution: The checkDefaultDataModel() method and all the above methods have been removed from the JTable on the grounds that they require "instanceof" and are mostly cover methods. The constructors: JTable(int numColumns, int numRows) JTable(Vector data, Vector columnNames) JTable(Object[][] data, Object[] columnNames) remain as conveniences because they allocate the DefaultTableModel themselves. 2. Sorting in the DefaultTableModel The sorting solution in the DefaultTableModel had the following issues: a) Customization was achieved by subclassing DefaultTableModel:doCompare(). b) The "quicksort" implementation was faulty - did not put things in order. c) Qsort is unstable, so can't be used for "windows-style" compounding. d) The sorting parts of the API were only designed for sorting by one key. e) It was not possible to sort models other than the DefaultTableModel. f) Comparing rows by dynamically switching on cell type did not guarantee a transitive comparison. This is a required condition of most sorts. Solution: Since the qsort implementation was broken we deleted all of the sorting code in the DefaultTableModel expecting that no-one would be dependent on it. 3). Using identifiers and indices to access cell values. a). AbstractTableModel getColumnIdentifier(int columnIndex) getColumnIndex(Object columnIdentifier) The mechanism by which the table retrieved data from the model caused a great deal of confusion by "invisibly" using the above methods to map identifiers to integers and then retrieving the data by integer access. The "default" implementation of getColumnIndex() in the AbstractTableModel assumed that identifiers were Integer objects and returned -1 when called with an identifier with a different type. This caused the JTable to fail during initialization with internal out-of-bounds errors when columns were submitted with other identifiers. b). The implementation of getColumnIndex() in the DefaultTableColumnModel did not assume identifiers were Integers but performed a linear search of the available columns using the equals method. This was a performance bottleneck, taking 80% of rendering CPU in some (fairly pathological) cases and 8% in "typical" cases with the current renderers. c). The APIs concerning access to cells were duplicated with different types and different orders. Eg. TableModel, AbstractTableModel, DefaultTableModel public Object getValueAt(int row, int column) JTable public Object getValueAt(int column, int row) public Object getValueAt(Object columnIdentifier, int rowIndex) Similarly setValueAt() isCellEditable() d). The row and column selection models (DefaultListSelectionModels) were integer based and the cover methods in the JTable API reflected this: public void setColumnSelectionInterval(int index0, int index1) public void addColumnSelectionInterval(int index0, int index1) public void removeColumnSelectionInterval(int index0, int index1) public int getSelectedColumn() public int[] getSelectedColumns() If the identifier approach was to be complete, cover methods were required to convert the integer ranges in the underlying SelectionModel to to sets of identifiers which would make sense in the space of an identifier based model. Solution: We decided we had to make one consistent choice of access mechanism, and that, whichever method was chosen, the whole API needed to be made as consistent as possible with it. At the very least, the methods that were (row, column) based in one place and (column, row) based in another would have to be changed. The results of the analysis on which mechanism we should use are in a separate document.