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