KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > RowSorter


1 /*
2  * @(#)RowSorter.java 1.7 06/06/23
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;
8
9 import javax.swing.SortOrder JavaDoc;
10 import javax.swing.event.*;
11 import java.util.*;
12
13 /**
14  * <code>RowSorter</code> provides the basis for sorting and filtering.
15  * Beyond creating and installing a <code>RowSorter</code>, you very rarely
16  * need to interact with one directly. Refer to
17  * {@link javax.swing.table.TableRowSorter TableRowSorter} for a concrete
18  * implementation of <code>RowSorter</code> for <code>JTable</code>.
19  * <p>
20  * <code>RowSorter</code>'s primary role is to provide a mapping between
21  * two coordinate systems: that of the view (for example a
22  * <code>JTable</code>) and that of the underlying data source, typically a
23  * model.
24  * <p>
25  * The view invokes the following methods on the <code>RowSorter</code>:
26  * <ul>
27  * <li><code>toggleSortOrder</code> &#151; The view invokes this when the
28  * appropriate user gesture has occurred to trigger a sort. For example,
29  * the user clicked a column header in a table.
30  * <li>One of the model change methods &#151; The view invokes a model
31  * change method when the underlying model
32  * has changed. There may be order dependencies in how the events are
33  * delivered, so a <code>RowSorter</code> should not update its mapping
34  * until one of these methods is invoked.
35  * </ul>
36  * Because the view makes extensive use of the
37  * <code>convertRowIndexToModel</code>,
38  * <code>convertRowIndexToView</code> and <code>getViewRowCount</code> methods,
39  * these methods need to be fast.
40  * <p>
41  * <code>RowSorter</code> provides notification of changes by way of
42  * <code>RowSorterListener</code>. Two types of notification are sent:
43  * <ul>
44  * <li><code>RowSorterEvent.Type.SORT_ORDER_CHANGED</code> &#151; notifies
45  * listeners that the sort order has changed. This is typically followed
46  * by a notification that the sort has changed.
47  * <li><code>RowSorterEvent.Type.SORTED</code> &#151; notifies listeners that
48  * the mapping maintained by the <code>RowSorter</code> has changed in
49  * some way.
50  * </ul>
51  * <code>RowSorter</code> implementations typically don't have a one-to-one
52  * mapping with the underlying model, but they can.
53  * For example, if a database does the sorting,
54  * <code>toggleSortOrder</code> might call through to the database
55  * (on a background thread), and override the mapping methods to return the
56  * argument that is passed in.
57  * <p>
58  * Concrete implementations of <code>RowSorter</code>
59  * need to reference a model such as <code>TableModel</code> or
60  * <code>ListModel</code>. The view classes, such as
61  * <code>JTable</code> and <code>JList</code>, will also have a
62  * reference to the model. To avoid ordering dependencies,
63  * <code>RowSorter</code> implementations should not install a
64  * listener on the model. Instead the view class will call into the
65  * <code>RowSorter</code> when the model changes. For
66  * example, if a row is updated in a <code>TableModel</code>
67  * <code>JTable</code> invokes <code>rowsUpdated</code>.
68  * When the model changes, the view may call into any of the following methods:
69  * <code>modelStructureChanged</code>, <code>allRowsChanged</code>,
70  * <code>rowsInserted</code>, <code>rowsDeleted</code> and
71  * <code>rowsUpdated</code>.
72  *
73  * @param <M> the type of the underlying model
74  * @version 1.7 06/23/06
75  * @see javax.swing.table.TableRowSorter
76  * @since 1.6
77  */

78 public abstract class RowSorter<M> {
79     private EventListenerList listenerList = new EventListenerList();
80
81     /**
82      * Creates a <code>RowSorter</code>.
83      */

84     public RowSorter() {
85     }
86
87     /**
88      * Returns the underlying model.
89      *
90      * @return the underlying model
91      */

92     public abstract M getModel();
93
94     /**
95      * Reverses the sort order of the specified column. It is up to
96      * subclasses to provide the exact behavior when invoked. Typically
97      * this will reverse the sort order from ascending to descending (or
98      * descending to ascending) if the specified column is already the
99      * primary sorted column; otherwise, makes the specified column
100      * the primary sorted column, with an ascending sort order. If
101      * the specified column is not sortable, this method has no
102      * effect.
103      * <p>
104      * If this results in changing the sort order and sorting, the
105      * appropriate <code>RowSorterListener</code> notification will be
106      * sent.
107      *
108      * @param column the column to toggle the sort ordering of, in
109      * terms of the underlying model
110      * @throws IndexOutOfBoundsException if column is outside the range of
111      * the underlying model
112      */

113     public abstract void toggleSortOrder(int column);
114
115     /**
116      * Returns the location of <code>index</code> in terms of the
117      * underlying model. That is, for the row <code>index</code> in
118      * the coordinates of the view this returns the row index in terms
119      * of the underlying model.
120      *
121      * @param index the row index in terms of the underlying view
122      * @return row index in terms of the view
123      * @throws IndexOutOfBoundsException if <code>index</code> is outside the
124      * range of the view
125      */

126     public abstract int convertRowIndexToModel(int index);
127
128     /**
129      * Returns the location of <code>index</code> in terms of the
130      * view. That is, for the row <code>index</code> in the
131      * coordinates of the underlying model this returns the row index
132      * in terms of the view.
133      *
134      * @param index the row index in terms of the underlying model
135      * @return row index in terms of the view, or -1 if index has been
136      * filtered out of the view
137      * @throws IndexOutOfBoundsException if <code>index</code> is outside
138      * the range of the model
139      */

140     public abstract int convertRowIndexToView(int index);
141
142     /**
143      * Sets the current sort keys.
144      *
145      * @param keys the new <code>SortKeys</code>; <code>null</code>
146      * is a shorthand for specifying an empty list,
147      * indicating that the view should be unsorted
148      */

149     public abstract void setSortKeys(List<? extends SortKey> keys);
150
151     /**
152      * Returns the current sort keys. This must return a {@code
153      * non-null List} and may return an unmodifiable {@code List}. If
154      * you need to change the sort keys, make a copy of the returned
155      * {@code List}, mutate the copy and invoke {@code setSortKeys}
156      * with the new list.
157      *
158      * @return the current sort order
159      */

160     public abstract List<? extends SortKey> getSortKeys();
161
162     /**
163      * Returns the number of rows in the view. If the contents have
164      * been filtered this might differ from the row count of the
165      * underlying model.
166      *
167      * @return number of rows in the view
168      * @see #getModelRowCount
169      */

170     public abstract int getViewRowCount();
171
172     /**
173      * Returns the number of rows in the underlying model.
174      *
175      * @return number of rows in the underlying model
176      * @see #getViewRowCount
177      */

178     public abstract int getModelRowCount();
179
180     /**
181      * Invoked when the underlying model structure has completely
182      * changed. For example, if the number of columns in a
183      * <code>TableModel</code> changed, this method would be invoked.
184      * <p>
185      * You normally do not call this method. This method is public
186      * to allow view classes to call it.
187      */

188     public abstract void modelStructureChanged();
189
190     /**
191      * Invoked when the contents of the underlying model have
192      * completely changed. The structure of the table is the same,
193      * only the contents have changed. This is typically sent when it
194      * is too expensive to characterize the change in terms of the
195      * other methods.
196      * <p>
197      * You normally do not call this method. This method is public
198      * to allow view classes to call it.
199      */

200     public abstract void allRowsChanged();
201
202     /**
203      * Invoked when rows have been inserted into the underlying model
204      * in the specified range (inclusive).
205      * <p>
206      * The arguments give the indices of the effected range.
207      * The first argument is in terms of the model before the change, and
208      * must be less than or equal to the size of the model before the change.
209      * The second argument is in terms of the model after the change and must
210      * be less than the size of the model after the change. For example,
211      * if you have a 5-row model and add 3 items to the end of the model
212      * the indices are 5, 7.
213      * <p>
214      * You normally do not call this method. This method is public
215      * to allow view classes to call it.
216      *
217      * @param firstRow the first row
218      * @param endRow the last row
219      * @throws IndexOutOfBoundsException if either argument is invalid, or
220      * <code>firstRow</code> &gt; <code>endRow</code>
221      */

222     public abstract void rowsInserted(int firstRow, int endRow);
223
224     /**
225      * Invoked when rows have been deleted from the underlying model
226      * in the specified range (inclusive).
227      * <p>
228      * The arguments give the indices of the effected range and
229      * are in terms of the model <b>before</b> the change.
230      * For example, if you have a 5-row model and delete 3 items from the end
231      * of the model the indices are 2, 4.
232      * <p>
233      * You normally do not call this method. This method is public
234      * to allow view classes to call it.
235      *
236      * @param firstRow the first row
237      * @param endRow the last row
238      * @throws IndexOutOfBoundsException if either argument is outside
239      * the range of the model before the change, or
240      * <code>firstRow</code> &gt; <code>endRow</code>
241      */

242     public abstract void rowsDeleted(int firstRow, int endRow);
243
244     /**
245      * Invoked when rows have been changed in the underlying model
246      * between the specified range (inclusive).
247      * <p>
248      * You normally do not call this method. This method is public
249      * to allow view classes to call it.
250      *
251      * @param firstRow the first row, in terms of the underlying model
252      * @param endRow the last row, in terms of the underlying model
253      * @throws IndexOutOfBoundsException if either argument is outside
254      * the range of the underlying model, or
255      * <code>firstRow</code> &gt; <code>endRow</code>
256      */

257     public abstract void rowsUpdated(int firstRow, int endRow);
258
259     /**
260      * Invoked when the column in the rows have been updated in
261      * the underlying model between the specified range.
262      * <p>
263      * You normally do not call this method. This method is public
264      * to allow view classes to call it.
265      *
266      * @param firstRow the first row, in terms of the underlying model
267      * @param endRow the last row, in terms of the underlying model
268      * @param column the column that has changed, in terms of the underlying
269      * model
270      * @throws IndexOutOfBoundsException if either argument is outside
271      * the range of the underlying model after the change,
272      * <code>firstRow</code> &gt; <code>endRow</code>, or
273      * <code>column</code> is outside the range of the underlying
274      * model
275      */

276     public abstract void rowsUpdated(int firstRow, int endRow, int column);
277
278     /**
279      * Adds a <code>RowSorterListener</code> to receive notification
280      * about this <code>RowSorter</code>. If the same
281      * listener is added more than once it will receive multiple
282      * notifications. If <code>l</code> is <code>null</code> nothing
283      * is done.
284      *
285      * @param l the <code>RowSorterListener</code>
286      */

287     public void addRowSorterListener(RowSorterListener l) {
288     listenerList.add(RowSorterListener.class, l);
289     }
290
291     /**
292      * Removes a <code>RowSorterListener</code>. If
293      * <code>l</code> is <code>null</code> nothing is done.
294      *
295      * @param l the <code>RowSorterListener</code>
296      */

297     public void removeRowSorterListener(RowSorterListener l) {
298     listenerList.remove(RowSorterListener.class, l);
299     }
300
301     /**
302      * Notifies listener that the sort order has changed.
303      */

304     protected void fireSortOrderChanged() {
305         fireRowSorterChanged(new RowSorterEvent(this));
306     }
307
308     /**
309      * Notifies listener that the mapping has changed.
310      *
311      * @param lastRowIndexToModel the mapping from model indices to
312      * view indices prior to the sort, may be <code>null</code>
313      */

314     protected void fireRowSorterChanged(int[] lastRowIndexToModel) {
315         fireRowSorterChanged(new RowSorterEvent(this,
316                 RowSorterEvent.Type.SORTED, lastRowIndexToModel));
317     }
318
319     void fireRowSorterChanged(RowSorterEvent event) {
320         Object JavaDoc[] listeners = listenerList.getListenerList();
321         for (int i = listeners.length - 2; i >= 0; i -= 2) {
322             if (listeners[i] == RowSorterListener.class) {
323                 ((RowSorterListener)listeners[i + 1]).
324                         sorterChanged(event);
325             }
326         }
327     }
328
329     /**
330      * SortKey describes the sort order for a particular column. The
331      * column index is in terms of the underlying model, which may differ
332      * from that of the view.
333      *
334      * @since 1.6
335      */

336     public static class SortKey {
337         private int column;
338         private SortOrder JavaDoc sortOrder;
339
340         /**
341          * Creates a <code>SortKey</code> for the specified column with
342          * the specified sort order.
343          *
344          * @param column index of the column, in terms of the model
345          * @param sortOrder the sorter order
346          * @throws IllegalArgumentException if <code>sortOrder</code> is
347          * <code>null</code>
348          */

349         public SortKey(int column, SortOrder JavaDoc sortOrder) {
350             if (sortOrder == null) {
351                 throw new IllegalArgumentException JavaDoc(
352                         "sort order must be non-null");
353             }
354             this.column = column;
355             this.sortOrder = sortOrder;
356         }
357
358         /**
359          * Returns the index of the column.
360          *
361          * @return index of column
362          */

363         public final int getColumn() {
364             return column;
365         }
366
367         /**
368          * Returns the sort order of the column.
369          *
370          * @return the sort order of the column
371          */

372         public final SortOrder JavaDoc getSortOrder() {
373             return sortOrder;
374         }
375
376         /**
377          * Returns the hash code for this <code>SortKey</code>.
378          *
379          * @return hash code
380          */

381         public int hashCode() {
382             int result = 17;
383             result = 37 * result + column;
384             result = 37 * result + sortOrder.hashCode();
385             return result;
386         }
387
388         /**
389          * Returns true if this object equals the specified object.
390          * If the specified object is a <code>SortKey</code> and
391          * references the same column and sort order, the two objects
392          * are equal.
393          *
394          * @param o the object to compare to
395          * @return true if <code>o</code> is equal to this <code>SortKey</code>
396          */

397         public boolean equals(Object JavaDoc o) {
398             if (o == this) {
399                 return true;
400             }
401             if (o instanceof SortKey) {
402                 return (((SortKey)o).column == column &&
403                         ((SortKey)o).sortOrder == sortOrder);
404             }
405             return false;
406         }
407     }
408 }
409
Popular Tags