KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > jga > swing > GenericTableModel


1 // ============================================================================
2
// $Id: GenericTableModel.java,v 1.14 2005/08/02 23:45:21 davidahall Exp $
3
// Copyright (c) 2003-2005 David A. Hall
4
// ============================================================================
5
// The contents of this file are subject to the Common Development and
6
// Distribution License (CDDL), Version 1.0 (the License); you may not use this
7
// file except in compliance with the License. You should have received a copy
8
// of the the License along with this file: if not, a copy of the License is
9
// available from Sun Microsystems, Inc.
10
//
11
// http://www.sun.com/cddl/cddl.html
12
//
13
// From time to time, the license steward (initially Sun Microsystems, Inc.) may
14
// publish revised and/or new versions of the License. You may not use,
15
// distribute, or otherwise make this file available under subsequent versions
16
// of the License.
17
//
18
// Alternatively, the contents of this file may be used under the terms of the
19
// GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
20
// case the provisions of the LGPL are applicable instead of those above. If you
21
// wish to allow use of your version of this file only under the terms of the
22
// LGPL, and not to allow others to use your version of this file under the
23
// terms of the CDDL, indicate your decision by deleting the provisions above
24
// and replace them with the notice and other provisions required by the LGPL.
25
// If you do not delete the provisions above, a recipient may use your version
26
// of this file under the terms of either the CDDL or the LGPL.
27
//
28
// This library is distributed in the hope that it will be useful,
29
// but WITHOUT ANY WARRANTY; without even the implied warranty of
30
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
31
// ============================================================================
32
package net.sf.jga.swing;
33
34 import java.util.Iterator JavaDoc;
35 import java.util.List JavaDoc;
36 import javax.swing.table.AbstractTableModel JavaDoc;
37 import javax.swing.table.DefaultTableColumnModel JavaDoc;
38 import javax.swing.table.TableCellEditor JavaDoc;
39 import javax.swing.table.TableCellRenderer JavaDoc;
40 import javax.swing.table.TableColumnModel JavaDoc;
41 import net.sf.jga.fn.BinaryFunctor;
42 import net.sf.jga.fn.EvaluationException;
43 import net.sf.jga.fn.UnaryFunctor;
44 import net.sf.jga.fn.property.ConstructUnary;
45 import net.sf.jga.fn.property.GetProperty;
46 import net.sf.jga.fn.property.SetProperty;
47 import net.sf.jga.fn.string.DefaultFormat;
48 import net.sf.jga.fn.string.FormatValue;
49 import net.sf.jga.fn.string.ParseFormat;
50 import net.sf.jga.fn.adaptor.Identity;
51
52 /**
53  * TableModel that uses a list of data for storage, and whose columns contain
54  * functors that read (and possibly write) properties of the objects in the
55  * list.
56  * <p>
57  * This class uses GenericTableColumns to store information about each specific
58  * column. To keep the correct column classes in use by the table, it is
59  * important to build the table using the constructor that takes both the data
60  * model and the column model, as shown in the code sample below. Otherwise,
61  * the table will build a default TableColumnModel of its own, and additions
62  * of columns to the data model won't be reflected in the column model.
63  * <p>
64  * Another caveat on the use of this class is that if columns are to be added to
65  * the model after it has been given to a table, then the table's
66  * autoCreateColumnsFromModel flag must be false (otherwise, the table will
67  * discard the existing columns and attempt to build new ones: JTable won't know
68  * how to create instances of the generic classes.
69  * <P>
70  * Working with this class can be fairly simple. To build a simple table that
71  * allows for the display and editing of a typical business object (Item, in
72  * this example),
73  * <p>
74  * <pre>
75  * List<Item> data = // initialized from somewhere
76  * GenericTableModel<Item> model =
77  * new GenericTableModel<Item>(Item.class, data);
78  *
79  * // adds a read-only column for the object's id
80  * model.addColumn(Integer.class, "ID");
81  *
82  * // adds a read-only column for the object's name
83  * model.addColumn(String.class, "Name");
84  *
85  * // adds an editable column for the object's description
86  * model.addColumn(String.class, "Desc", true);
87  *
88  * // adds an editable column for the object's count
89  * model.addColumn(Integer.class, "Count", true);
90  *
91  * // adds an editable column for the object's price
92  * model.addColumn(BigDecimal.class, "Price", true);
93  *
94  * JTable table = new JTable(model, model.getColumnModel());
95  * </pre>
96  * <p>
97  * In this example, the Item class is presumed to have the appropriate
98  * getter/setter methods defined.
99  * <p>
100  * Copyright &copy; 2003-2005 David A. Hall
101  *
102  * @author <a HREF="mailto:davidahall@users.sf.net">David A. Hall</a>
103  */

104
105 // TODO: there should be an associated GenericTableColumnModel to go along
106
// with this. It might be possible for addColumn to be safe after the
107
// table has been assigned (if the table consults the TableColumnModel
108
// when it rebuilds (but it probably doesn't))
109
// NOTE: Tried this -- there are problems. Specifically, the column model
110
// really wants to share (or take over)some of the internal state. It
111
// leads to having column, model, and column model, all of which need to
112
// be used together or not at all. The only real way to keep everything
113
// in sync is to create a GenericTable that overrides the default class
114
// used for model,column,and column model. I didn't want to go that far.
115

116 // TODO: this should wrap a ListModel
117

118 public class GenericTableModel<T> extends AbstractTableModel JavaDoc {
119     
120     static final long serialVersionUID = 8996104516840561845L;
121
122     private Class JavaDoc<T> _rowtype;
123     private List JavaDoc<T> _values;
124
125     private DefaultTableColumnModel JavaDoc _columnModel = new DefaultTableColumnModel JavaDoc();
126     
127     /**
128      * Builds a GenericTableModel for the given list of data. The columns
129      * must be added separately before the table may be rendered.
130      */

131     public GenericTableModel (Class JavaDoc<T> rowtype, List JavaDoc<T> values) {
132         _rowtype = rowtype;
133         _values = values;
134     }
135     
136     /**
137      * Builds a GenericTableModel for the given list of data, using the
138      * given list of columns.
139      */

140     public GenericTableModel (Class JavaDoc<T> rowtype, List JavaDoc<T> values,
141                               List JavaDoc<GenericTableColumn<T,?>> columns)
142     {
143         _rowtype = rowtype;
144         _values = values;
145         Iterator JavaDoc<GenericTableColumn<T,?>> iter = columns.iterator();
146         while(iter.hasNext())
147             _columnModel.addColumn(iter.next());
148     }
149
150     /**
151      * Returns the column model that should be used in conjunction with this
152      * data model.
153      */

154
155     public TableColumnModel JavaDoc getColumnModel() {
156         return _columnModel;
157     }
158     
159     /**
160      * Returns the value that corresponds to the given row of the table
161      */

162     public T getRowValue(int row) {
163         return _values.get(row);
164     }
165
166     // Flag that determines if the columns' names are to be used in the table
167
// header. Generally, that will be the case, so this defaults to true.
168
private boolean _nameUsedInHeader = true;
169     
170     /**
171      * Enables/Disables use of property names in the column headers of all
172      * columns subsequently added to the table. Existing header values will
173      * not be changed when this value changes. Defaults to true (enabled).
174      */

175     public void setNameUsedInHeader(boolean b) { _nameUsedInHeader = b; }
176
177     
178     /**
179      * Returns true if property names are to be used in the headers of the
180      * corresponding columns.
181      */

182     public boolean isNameUsedInHeader() { return _nameUsedInHeader; }
183     
184     /**
185      * Adds a read-only column that uses a GetProperty functor for the named
186      * property. Do not call this method after the model has been given to a
187      * table unless the table's autoCreateColumnsFromModel flag is unset.
188      */

189     
190     public <C> GenericTableColumn<T,C> addColumn(Class JavaDoc<C> coltype, String JavaDoc name){
191         GetProperty<T,C> getter = new GetProperty<T,C>(_rowtype, name);
192         return addColumnImpl(name, new GenericTableColumn<T,C>(coltype, getter));
193     }
194     
195     /**
196      * Adds a possibly editable column that uses a GetProperty functor for
197      * the named property, and a SetProperty functor if the column is
198      * editable. Do not call this method after the model has been given to
199      * a table unless the table's autoCreateColumnsFromModel flag is unset.
200      */

201     
202     public <C> GenericTableColumn<T,C> addColumn(Class JavaDoc<C> coltype, String JavaDoc name,
203                                                  boolean editable)
204     {
205         GetProperty<T,C> getter = new GetProperty<T,C>(_rowtype, name);
206         SetProperty<T,C> setter = editable ? new SetProperty<T,C>(_rowtype, name, coltype) : null;
207         return addColumnImpl(name, new GenericTableColumn<T,C>(coltype, getter, setter));
208     }
209         
210     /**
211      * Adds a read-only column that uses a GetProperty functor for the named
212      * property and renders the property value in the given formatter. Do not
213      * call this method after the model has been given to a table unless the
214      * table's autoCreateColumnsFromModel flag is unset.
215      */

216     public <C> GenericTableColumn<T,C> addColumn(Class JavaDoc<C> coltype, String JavaDoc name,
217                                                  UnaryFunctor<C,String JavaDoc> formatter)
218     {
219         GetProperty<T,C> getter = new GetProperty<T,C>(_rowtype, name);
220         return addColumnImpl(name, new GenericTableColumn<T,C>(coltype,getter,null,formatter,null));
221     }
222     
223
224     /**
225      * Adds an editable column that uses a GetProperty functor for
226      * the named property, and a SetProperty functor if the column is
227      * editable, and is rendered (and edited) using the given format. Do not
228      * call this method after the model has been given to a table unless the
229      * table's autoCreateColumnsFromModel flag is unset.
230      */

231     public <C> GenericTableColumn<T,C> addColumn(Class JavaDoc<C> coltype, String JavaDoc name,
232                                                  UnaryFunctor<C,String JavaDoc> formatter,
233                                                  UnaryFunctor<String JavaDoc,C> parser)
234     {
235         GetProperty<T,C> getter = new GetProperty<T,C>(_rowtype, name);
236         SetProperty<T,C> setter = (parser != null) ?
237             new SetProperty<T,C>(_rowtype, name, coltype) : null;
238
239         return addColumnImpl(name,
240                              new GenericTableColumn<T,C>(coltype,getter,setter,formatter,parser));
241     }
242
243
244     /**
245      * Completes the configuration of a new column and adds it to the table
246      */

247     private <C> GenericTableColumn<T,C> addColumnImpl(String JavaDoc name, GenericTableColumn<T,C> column) {
248         if (_nameUsedInHeader)
249             column.setHeaderValue(name);
250         
251         addColumn(column);
252         return column;
253     }
254
255     /**
256      * Adds the given column to the table. Do not call this method
257      * after the model has been given to a table unless the table's
258      * autoCreateColumnsFromModel flag is unset.
259      */

260     
261     public void addColumn(GenericTableColumn<T,?> col) {
262         col.setModelIndex(getColumnCount());
263         _columnModel.addColumn(col);
264     }
265
266     /**
267      * Returns the GenericTableColumn associated with the given column index.
268      */

269     
270     public GenericTableColumn<T,?> getGenericColumn(int col) {
271         // @SuppressWarnings
272
//
273
return (GenericTableColumn<T,?>) _columnModel.getColumn(col);
274     }
275     
276     // -------------------------------------------------------------
277
// TableModel interface
278
// -------------------------------------------------------------
279

280     public int getRowCount() {
281         return _values.size();
282     }
283
284     public int getColumnCount() {
285         return _columnModel.getColumnCount();
286     }
287
288     public Class JavaDoc getColumnClass(int col) {
289         return getGenericColumn(col).getColumnClass();
290     }
291     
292     public String JavaDoc getColumnName(int col) {
293         GenericTableColumn<T,?> column = getGenericColumn(col);
294         Object JavaDoc name = column.getHeaderValue();
295         return (name != null) ? name.toString() : super.getColumnName(col);
296     }
297     
298     public boolean isCellEditable(int row, int col) {
299         return getGenericColumn(col).isEditable();
300     }
301
302     public Object JavaDoc getValueAt(int row, int col) {
303         T rowvalue = getRowValue(row);
304         GenericTableColumn<T,?> column = getGenericColumn(col);
305         try {
306             return column.getValueAt(rowvalue);
307         }
308         catch (EvaluationException x) {
309             x.printStackTrace();
310             return "### ERROR ###";
311         }
312     }
313
314     public void setValueAt(Object JavaDoc value, int row, int col) {
315         T rowvalue = getRowValue(row);
316         GenericTableColumn<T,?> column = getGenericColumn(col);
317         assert column.getColumnClass().isInstance(value);
318         
319         column.setValueAt(rowvalue, value);
320         fireTableCellUpdated(row,col);
321     }
322 }
323
Popular Tags