001 package util.swing; 002 003 import java.util.Comparator; 004 005 import util.ReverseOrderComparator; 006 007 /** 008 * A {@link javax.swing.table.TableModel} that models a list of records rather than a matrix of cells. 009 * 010 * <p>Usage of this TableModel is always recommendable when the data that is to be displayed consists of 011 * a list of uniformly structured records and you want to display a selection of attributes for each record. 012 * As the data management classes ({@link data.Catalog}, {@link data.Stock}, {@link data.DataBasket}) of the 013 * "SalesPoint" framework match this scheme, there are concrete subclasses of this model for each of 014 * those classes.</p> 015 * 016 * <p><code>util.swing.AbstractTableModel</code> will give one row in the table to each record of the model. 017 * The record that is to be displayed in a certain row is determined by the {@link #getRecord} method which is 018 * <i>abstract</i> and must be overridden in subclasses. Thus, subclasses have the opportunity to define what 019 * type (class) of records they use and how they are derived from the actual data source in the background. 020 * There's only one more method that subclasses will have to override: 021 * {@link javax.swing.table.TableModel#getRowCount}.</p> 022 * 023 * <p>A {@link TableEntryDescriptor} will be used to determine how individual records are represented in one 024 * row of the table model, i.e. how many columns there are and what is displayed in the cells as well as 025 * formatting and editing issues.</p> 026 * 027 * @see JAbstractTable 028 * 029 * @author Steffen Zschaler 030 * @version 2.0 28/07/1999 031 * @since v2.0 032 */ 033 public abstract class AbstractTableModel extends javax.swing.table.AbstractTableModel { 034 035 /** 036 * The {@link TableEntryDescriptor} that is used to split records into columns. 037 * 038 * @serial 039 */ 040 private TableEntryDescriptor m_tedEntryDescriptor; 041 042 /** 043 * Set the table's data. 044 * @param data the new data 045 * @throws Exception 046 */ 047 public abstract void setData(Object data); 048 049 /** 050 * Create a new AbstractTableModel. 051 * 052 * @param ted the {@link TableEntryDescriptor} that is to be used to split records into columns. 053 */ 054 public AbstractTableModel(TableEntryDescriptor ted) { 055 super(); 056 057 m_tedEntryDescriptor = ted; 058 } 059 060 /** 061 * Get the {@link TableEntryDescriptor} that is used to split records into columns. 062 * 063 * @override Never 064 */ 065 public TableEntryDescriptor getEntryDescriptor() { 066 return m_tedEntryDescriptor; 067 } 068 069 /** 070 * Get the number of columns in this {@link javax.swing.table.TableModel}. 071 * 072 * @return the number of columns in the associated {@link TableEntryDescriptor}. 073 * 074 * @override Never 075 * 076 * @see TableEntryDescriptor#getColumnCount 077 */ 078 public int getColumnCount() { 079 return m_tedEntryDescriptor.getColumnCount(); 080 } 081 082 /** 083 * Get the name of the given column in this {@link javax.swing.table.TableModel}. 084 * 085 * @param nIdx the column's index. Columns indices run from 0 to 086 * {@link #getColumnCount getColumnCount() - 1}. 087 * 088 * @return the name of the column in the associated {@link TableEntryDescriptor}. 089 * 090 * @override Never 091 * 092 * @see TableEntryDescriptor#getColumnName 093 */ 094 public String getColumnName(int nIdx) { 095 return m_tedEntryDescriptor.getColumnName(nIdx); 096 } 097 098 /** 099 * Get the class of the given column in this {@link javax.swing.table.TableModel}. 100 * 101 * @param nIdx the column's index. Columns indices run from 0 to 102 * {@link #getColumnCount getColumnCount() - 1}. 103 * 104 * @return the class of the column in the associated {@link TableEntryDescriptor}. 105 * 106 * @override Never 107 * 108 * @see TableEntryDescriptor#getColumnClass 109 */ 110 public Class<?> getColumnClass(int nIdx) { 111 return m_tedEntryDescriptor.getColumnClass(nIdx); 112 } 113 114 /** 115 * Get the value of the given cell in this {@link javax.swing.table.TableModel}. 116 * 117 * <p>First determines the record associated to the row by calling {@link #getRecord}, then calls 118 * {@link TableEntryDescriptor#getValueAt getValueAt()} in the associated TableEntryDescriptor.</p> 119 * 120 * @param row the row index for which to determine the value. This will be passed on to {@link #getRecord}. 121 * Row indices run from 0 to {@link javax.swing.table.TableModel#getRowCount getRowCount() - 1}. 122 * @param col the column's index. Columns indices run from 0 to 123 * {@link #getColumnCount getColumnCount() - 1}. 124 * 125 * @return the value returned by {@link TableEntryDescriptor#getValueAt}. 126 * 127 * @override Never 128 */ 129 public Object getValueAt(int row, int col) { 130 Object oRecord = getRecord(row); 131 if (oRecord != null) { 132 return m_tedEntryDescriptor.getValueAt(oRecord, col); 133 } else { 134 return null; 135 } 136 } 137 138 /** 139 * Check whether the given cell is editable in this {@link javax.swing.table.TableModel}. 140 * 141 * <p>First determines the record associated to the row by calling {@link #getRecord}, then calls 142 * {@link TableEntryDescriptor#isElementEditable isElementEditable()} in the associated 143 * TableEntryDescriptor.</p> 144 * 145 * @param row the row index for which to determine editability. This will be passed on to {@link #getRecord}. 146 * Row indices run from 0 to {@link javax.swing.table.TableModel#getRowCount getRowCount() - 1}. 147 * @param col the column's index. Columns indices run from 0 to 148 * {@link #getColumnCount getColumnCount() - 1}. 149 * 150 * @return the value returned by {@link TableEntryDescriptor#isElementEditable}. 151 * 152 * @override Never 153 */ 154 public boolean isCellEditable(int row, int col) { 155 Object oRecord = getRecord(row); 156 if (oRecord != null) { 157 return m_tedEntryDescriptor.isElementEditable(oRecord, col); 158 } else { 159 return false; 160 } 161 } 162 163 /** 164 * Set the value of the given cell in this {@link javax.swing.table.TableModel}. 165 * 166 * <p>First determines the record associated to the row by calling {@link #getRecord}, then calls 167 * {@link TableEntryDescriptor#setValueAt setValueAt()} in the associated TableEntryDescriptor.</p> 168 * 169 * @param oValue the new value for the cell. This will be passed on to 170 * {@link TableEntryDescriptor#setValueAt} as the <code>oValue</code> parameter. 171 * @param row the row index for which to set the value. This will be passed on to {@link #getRecord}. 172 * Row indices run from 0 to {@link javax.swing.table.TableModel#getRowCount getRowCount() - 1}. 173 * @param col the column's index. Columns indices run from 0 to 174 * {@link #getColumnCount getColumnCount() - 1}. 175 * 176 * @override Never 177 */ 178 public void setValueAt(Object oValue, int row, int col) { 179 Object oRecord = getRecord(row); 180 if (oRecord != null) { 181 m_tedEntryDescriptor.setValueAt(oRecord, col, oValue); 182 183 fireTableCellUpdated(row, col); 184 } 185 } 186 187 /** 188 * Reorders the table by the specified column if that's possible. 189 * 190 * @param nIdx the index of the column by which to sort 191 * @param fAscending if false orders the records in descending order 192 * 193 * @see #reOrderBy 194 * 195 * @override Never 196 * 197 * @since v3.0 12/14/2000 198 */ 199 public void orderByColumn(int nIdx, boolean fAscending) { 200 if (m_tedEntryDescriptor.canSortByColumn(nIdx)) { 201 Comparator<Object> cmp = m_tedEntryDescriptor.getColumnOrder(nIdx); 202 203 if (!fAscending) { 204 cmp = new ReverseOrderComparator(cmp); 205 } 206 207 reOrderBy(cmp); 208 } 209 } 210 211 /** 212 * Get the record associated to the given row. 213 * 214 * <p>Subclasses must indicate the class of the record in their documentation.</p> 215 * 216 * @param row the row index for which to return the record. Row indices run from 0 to 217 * {@link javax.swing.table.TableModel#getRowCount getRowCount() - 1}. 218 * 219 * @return the record associated to the given row. May return <code>null</code>, instead of throwing an exception, 220 * if the given index is without its bounds. 221 * 222 * @override Always You must override this method to define and incorporate your own type of record. 223 * Subclasses should specify what class of record is returned. 224 */ 225 public abstract Object getRecord(int row); 226 227 /** 228 * Reorder the records displayed according to the specified comparator. 229 * 230 * @param cmp the comparator by which to order. 231 * 232 * @override Sometimes Override this method if you want sorting by column for your derived models. The 233 * default implementation does nothing. 234 * Subclasses should specify what class of record is maintained and whether the comparators must compare 235 * whole records or just specific attributes. 236 * 237 * @since v3.0 12/14/2000 238 */ 239 protected void reOrderBy(Comparator cmp) { 240 } 241 }