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 }