KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > table > TableRowSorter


1 /*
2  * @(#)TableRowSorter.java 1.8 06/03/31
3  *
4  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.table;
8
9 import java.text.Collator JavaDoc;
10 import java.util.*;
11 import javax.swing.DefaultRowSorter JavaDoc;
12 import javax.swing.RowFilter JavaDoc;
13 import javax.swing.SortOrder JavaDoc;
14
15 /**
16  * An implementation of <code>RowSorter</code> that provides sorting
17  * and filtering using a <code>TableModel</code>.
18  * The following example shows adding sorting to a <code>JTable</code>:
19  * <pre>
20  * TableModel myModel = createMyTableModel();
21  * JTable table = new JTable(myModel);
22  * table.setRowSorter(new TableRowSorter(myModel));
23  * </pre>
24  * This will do all the wiring such that when the user does the appropriate
25  * gesture, such as clicking on the column header, the table will
26  * visually sort.
27  * <p>
28  * <code>JTable</code>'s row-based methods and <code>JTable</code>'s
29  * selection model refer to the view and not the underlying
30  * model. Therefore, it is necessary to convert between the two. For
31  * example, to get the selection in terms of <code>myModel</code>
32  * you need to convert the indices:
33  * <pre>
34  * int[] selection = table.getSelectedRows();
35  * for (int i = 0; i &lt; selection.length; i++) {
36  * selection[i] = table.convertRowIndexToModel(selection[i]);
37  * }
38  * </pre>
39  * Similarly to select a row in <code>JTable</code> based on
40  * a coordinate from the underlying model do the inverse:
41  * <pre>
42  * table.setRowSelectionInterval(table.convertRowIndexToView(row),
43  * table.convertRowIndexToView(row));
44  * </pre>
45  * <p>
46  * The previous example assumes you have not enabled filtering. If you
47  * have enabled filtering <code>convertRowIndexToView</code> will return
48  * -1 for locations that are not visible in the view.
49  * <p>
50  * <code>TableRowSorter</code> uses <code>Comparator</code>s for doing
51  * comparisons. The following defines how a <code>Comparator</code> is
52  * chosen for a column:
53  * <ol>
54  * <li>If a <code>Comparator</code> has been specified for the column by the
55  * <code>setComparator</code> method, use it.
56  * <li>If the column class as returned by <code>getColumnClass</code> is
57  * <code>String</code>, use the <code>Comparator</code> returned by
58  * <code>Collator.getInstance()</code>.
59  * <li>If the column class implements <code>Comparable</code>, use a
60  * <code>Comparator</code> that invokes the <code>compareTo</code>
61  * method.
62  * <li>If a <code>TableStringConverter</code> has been specified, use it
63  * to convert the values to <code>String</code>s and then use the
64  * <code>Comparator</code> returned by <code>Collator.getInstance()</code>.
65  * <li>Otherwise use the <code>Comparator</code> returned by
66  * <code>Collator.getInstance()</code> on the results from
67  * calling <code>toString</code> on the objects.
68  * </ol>
69  * <p>
70  * In addition to sorting <code>TableRowSorter</code> provides the ability
71  * to filter. A filter is specified using the <code>setFilter</code>
72  * method. The following example will only show rows containing the string
73  * "foo":
74  * <pre>
75  * TableModel myModel = createMyTableModel();
76  * TableRowSorter sorter = new TableRowSorter(myModel);
77  * sorter.setRowFilter(RowFilter.regexFilter(".*foo.*"));
78  * JTable table = new JTable(myModel);
79  * table.setRowSorter(sorter);
80  * </pre>
81  * <p>
82  * If the underlying model structure changes (the
83  * <code>modelStructureChanged</code> method is invoked) the following
84  * are reset to their default values: <code>Comparator</code>s by
85  * column, current sort order, and whether each column is sortable. The default
86  * sort order is natural (the same as the model), and columns are
87  * sortable by default.
88  * <p>
89  * <code>TableRowSorter</code> has one formal type parameter: the type
90  * of the model. Passing in a type that corresponds exactly to your
91  * model allows you to filter based on your model without casting.
92  * Refer to the documentation of <code>RowFilter</code> for an example
93  * of this.
94  * <p>
95  * <b>WARNING:</b> <code>DefaultTableModel</code> returns a column
96  * class of <code>Object</code>. As such all comparisons will
97  * be done using <code>toString</code>. This may be unnecessarily
98  * expensive. If the column only contains one type of value, such as
99  * an <code>Integer</code>, you should override <code>getColumnClass</code> and
100  * return the appropriate <code>Class</code>. This will dramatically
101  * increase the performance of this class.
102  *
103  * @param <M> the type of the model, which must be an implementation of
104  * <code>TableModel</code>
105  * @version 1.8 03/31/06
106  * @see javax.swing.JTable
107  * @see javax.swing.RowFilter
108  * @see javax.swing.table.DefaultTableModel
109  * @see java.text.Collator
110  * @see java.util.Comparator
111  * @since 1.6
112  */

113 public class TableRowSorter<M extends TableModel JavaDoc> extends DefaultRowSorter JavaDoc<M, Integer JavaDoc> {
114     /**
115      * Comparator that uses compareTo on the contents.
116      */

117     private static final Comparator COMPARABLE_COMPARATOR =
118             new ComparableComparator();
119
120     /**
121      * Underlying model.
122      */

123     private M tableModel;
124
125     /**
126      * For toString conversions.
127      */

128     private TableStringConverter JavaDoc stringConverter;
129
130
131     /**
132      * Creates a <code>TableRowSorter</code> with an empty model.
133      */

134     public TableRowSorter() {
135         this(null);
136     }
137
138     /**
139      * Creates a <code>TableRowSorter</code> using <code>model</code>
140      * as the underlying <code>TableModel</code>.
141      *
142      * @param model the underlying <code>TableModel</code> to use,
143      * <code>null</code> is treated as an empty model
144      */

145     public TableRowSorter(M model) {
146         setModel(model);
147     }
148
149     /**
150      * Sets the <code>TableModel</code> to use as the underlying model
151      * for this <code>TableRowSorter</code>. A value of <code>null</code>
152      * can be used to set an empty model.
153      *
154      * @param model the underlying model to use, or <code>null</code>
155      */

156     public void setModel(M model) {
157         tableModel = model;
158         setModelWrapper(new TableRowSorterModelWrapper());
159     }
160
161     /**
162      * Sets the object responsible for converting values from the
163      * model to strings. If non-<code>null</code> this
164      * is used to convert any object values, that do not have a
165      * registered <code>Comparator</code>, to strings.
166      *
167      * @param stringConverter the object responsible for converting values
168      * from the model to strings
169      */

170     public void setStringConverter(TableStringConverter JavaDoc stringConverter) {
171         this.stringConverter = stringConverter;
172     }
173
174     /**
175      * Returns the object responsible for converting values from the
176      * model to strings.
177      *
178      * @return object responsible for converting values to strings.
179      */

180     public TableStringConverter JavaDoc getStringConverter() {
181         return stringConverter;
182     }
183
184     /**
185      * Returns the <code>Comparator</code> for the specified
186      * column. If a <code>Comparator</code> has not been specified using
187      * the <code>setComparator</code> method a <code>Comparator</code>
188      * will be returned based on the column class
189      * (<code>TableModel.getColumnClass</code>) of the specified column.
190      * If the column class is <code>String</code>,
191      * <code>Collator.getInstance</code> is returned. If the
192      * column class implements <code>Comparable</code> a private
193      * <code>Comparator</code> is returned that invokes the
194      * <code>compareTo</code> method. Otherwise
195      * <code>Collator.getInstance</code> is returned.
196      *
197      * @throws IndexOutOfBoundsException {@inheritDoc}
198      */

199     public Comparator<?> getComparator(int column) {
200         Comparator comparator = super.getComparator(column);
201         if (comparator != null) {
202             return comparator;
203         }
204         Class JavaDoc columnClass = getModel().getColumnClass(column);
205         if (columnClass == String JavaDoc.class) {
206             return Collator.getInstance();
207         }
208         if (Comparable JavaDoc.class.isAssignableFrom(columnClass)) {
209             return COMPARABLE_COMPARATOR;
210         }
211         return Collator.getInstance();
212     }
213
214     /**
215      * {@inheritDoc}
216      *
217      * @throws IndexOutOfBoundsException {@inheritDoc}
218      */

219     protected boolean useToString(int column) {
220         Comparator comparator = super.getComparator(column);
221         if (comparator != null) {
222             return false;
223         }
224         Class JavaDoc columnClass = getModel().getColumnClass(column);
225         if (columnClass == String JavaDoc.class) {
226             return false;
227         }
228         if (Comparable JavaDoc.class.isAssignableFrom(columnClass)) {
229             return false;
230         }
231         return true;
232     }
233
234     /**
235      * Implementation of DefaultRowSorter.ModelWrapper that delegates to a
236      * TableModel.
237      */

238     private class TableRowSorterModelWrapper extends ModelWrapper<M,Integer JavaDoc> {
239         public M getModel() {
240             return tableModel;
241         }
242
243         public int getColumnCount() {
244             return (tableModel == null) ? 0 : tableModel.getColumnCount();
245         }
246
247         public int getRowCount() {
248             return (tableModel == null) ? 0 : tableModel.getRowCount();
249         }
250
251         public Object JavaDoc getValueAt(int row, int column) {
252             return tableModel.getValueAt(row, column);
253         }
254
255         public String JavaDoc getStringValueAt(int row, int column) {
256             TableStringConverter JavaDoc converter = getStringConverter();
257             if (converter != null) {
258                 // Use the converter
259
String JavaDoc value = converter.toString(
260                         tableModel, row, column);
261                 if (value != null) {
262                     return value;
263                 }
264                 return "";
265             }
266
267             // No converter, use getValueAt followed by toString
268
Object JavaDoc o = getValueAt(row, column);
269             if (o == null) {
270                 return "";
271             }
272             String JavaDoc string = o.toString();
273             if (string == null) {
274                 return "";
275             }
276             return string;
277         }
278
279         public Integer JavaDoc getIdentifier(int index) {
280             return index;
281         }
282     }
283
284
285     private static class ComparableComparator implements Comparator {
286         @SuppressWarnings JavaDoc("unchecked")
287         public int compare(Object JavaDoc o1, Object JavaDoc o2) {
288             return ((Comparable JavaDoc)o1).compareTo(o2);
289         }
290     }
291 }
292
Popular Tags