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             * &quot;SalesPoint&quot; 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    }