/*
* Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.SortOrder;
import javax.swing.event.*;
import java.util.*;
RowSorter
provides the basis for sorting and filtering.
Beyond creating and installing a RowSorter
, you very rarely need to interact with one directly. Refer to TableRowSorter
for a concrete implementation of RowSorter
for JTable
.
RowSorter
's primary role is to provide a mapping between
two coordinate systems: that of the view (for example a
JTable
) and that of the underlying data source, typically a
model.
The view invokes the following methods on the RowSorter
:
toggleSortOrder
— The view invokes this when the
appropriate user gesture has occurred to trigger a sort. For example,
the user clicked a column header in a table.
- One of the model change methods — The view invokes a model
change method when the underlying model
has changed. There may be order dependencies in how the events are
delivered, so a
RowSorter
should not update its mapping
until one of these methods is invoked.
Because the view makes extensive use of the
convertRowIndexToModel
,
convertRowIndexToView
and getViewRowCount
methods,
these methods need to be fast.
RowSorter
provides notification of changes by way of
RowSorterListener
. Two types of notification are sent:
RowSorterEvent.Type.SORT_ORDER_CHANGED
— notifies
listeners that the sort order has changed. This is typically followed
by a notification that the sort has changed.
RowSorterEvent.Type.SORTED
— notifies listeners that
the mapping maintained by the RowSorter
has changed in
some way.
RowSorter
implementations typically don't have a one-to-one
mapping with the underlying model, but they can.
For example, if a database does the sorting,
toggleSortOrder
might call through to the database
(on a background thread), and override the mapping methods to return the
argument that is passed in.
Concrete implementations of RowSorter
need to reference a model such as TableModel
or
ListModel
. The view classes, such as
JTable
and JList
, will also have a
reference to the model. To avoid ordering dependencies,
RowSorter
implementations should not install a
listener on the model. Instead the view class will call into the
RowSorter
when the model changes. For
example, if a row is updated in a TableModel
JTable
invokes rowsUpdated
.
When the model changes, the view may call into any of the following methods:
modelStructureChanged
, allRowsChanged
,
rowsInserted
, rowsDeleted
and
rowsUpdated
.
Type parameters: - <M> – the type of the underlying model
See Also: Since: 1.6
/**
* <code>RowSorter</code> provides the basis for sorting and filtering.
* Beyond creating and installing a <code>RowSorter</code>, you very rarely
* need to interact with one directly. Refer to
* {@link javax.swing.table.TableRowSorter TableRowSorter} for a concrete
* implementation of <code>RowSorter</code> for <code>JTable</code>.
* <p>
* <code>RowSorter</code>'s primary role is to provide a mapping between
* two coordinate systems: that of the view (for example a
* <code>JTable</code>) and that of the underlying data source, typically a
* model.
* <p>
* The view invokes the following methods on the <code>RowSorter</code>:
* <ul>
* <li><code>toggleSortOrder</code> — The view invokes this when the
* appropriate user gesture has occurred to trigger a sort. For example,
* the user clicked a column header in a table.
* <li>One of the model change methods — The view invokes a model
* change method when the underlying model
* has changed. There may be order dependencies in how the events are
* delivered, so a <code>RowSorter</code> should not update its mapping
* until one of these methods is invoked.
* </ul>
* Because the view makes extensive use of the
* <code>convertRowIndexToModel</code>,
* <code>convertRowIndexToView</code> and <code>getViewRowCount</code> methods,
* these methods need to be fast.
* <p>
* <code>RowSorter</code> provides notification of changes by way of
* <code>RowSorterListener</code>. Two types of notification are sent:
* <ul>
* <li><code>RowSorterEvent.Type.SORT_ORDER_CHANGED</code> — notifies
* listeners that the sort order has changed. This is typically followed
* by a notification that the sort has changed.
* <li><code>RowSorterEvent.Type.SORTED</code> — notifies listeners that
* the mapping maintained by the <code>RowSorter</code> has changed in
* some way.
* </ul>
* <code>RowSorter</code> implementations typically don't have a one-to-one
* mapping with the underlying model, but they can.
* For example, if a database does the sorting,
* <code>toggleSortOrder</code> might call through to the database
* (on a background thread), and override the mapping methods to return the
* argument that is passed in.
* <p>
* Concrete implementations of <code>RowSorter</code>
* need to reference a model such as <code>TableModel</code> or
* <code>ListModel</code>. The view classes, such as
* <code>JTable</code> and <code>JList</code>, will also have a
* reference to the model. To avoid ordering dependencies,
* <code>RowSorter</code> implementations should not install a
* listener on the model. Instead the view class will call into the
* <code>RowSorter</code> when the model changes. For
* example, if a row is updated in a <code>TableModel</code>
* <code>JTable</code> invokes <code>rowsUpdated</code>.
* When the model changes, the view may call into any of the following methods:
* <code>modelStructureChanged</code>, <code>allRowsChanged</code>,
* <code>rowsInserted</code>, <code>rowsDeleted</code> and
* <code>rowsUpdated</code>.
*
* @param <M> the type of the underlying model
* @see javax.swing.table.TableRowSorter
* @since 1.6
*/
public abstract class RowSorter<M> {
private EventListenerList listenerList = new EventListenerList();
Creates a RowSorter
.
/**
* Creates a <code>RowSorter</code>.
*/
public RowSorter() {
}
Returns the underlying model.
Returns: the underlying model
/**
* Returns the underlying model.
*
* @return the underlying model
*/
public abstract M getModel();
Reverses the sort order of the specified column. It is up to
subclasses to provide the exact behavior when invoked. Typically
this will reverse the sort order from ascending to descending (or
descending to ascending) if the specified column is already the
primary sorted column; otherwise, makes the specified column
the primary sorted column, with an ascending sort order. If
the specified column is not sortable, this method has no
effect.
If this results in changing the sort order and sorting, the
appropriate RowSorterListener
notification will be
sent.
Params: - column – the column to toggle the sort ordering of, in
terms of the underlying model
Throws: - IndexOutOfBoundsException – if column is outside the range of
the underlying model
/**
* Reverses the sort order of the specified column. It is up to
* subclasses to provide the exact behavior when invoked. Typically
* this will reverse the sort order from ascending to descending (or
* descending to ascending) if the specified column is already the
* primary sorted column; otherwise, makes the specified column
* the primary sorted column, with an ascending sort order. If
* the specified column is not sortable, this method has no
* effect.
* <p>
* If this results in changing the sort order and sorting, the
* appropriate <code>RowSorterListener</code> notification will be
* sent.
*
* @param column the column to toggle the sort ordering of, in
* terms of the underlying model
* @throws IndexOutOfBoundsException if column is outside the range of
* the underlying model
*/
public abstract void toggleSortOrder(int column);
Returns the location of index
in terms of the
underlying model. That is, for the row index
in
the coordinates of the view this returns the row index in terms
of the underlying model.
Params: - index – the row index in terms of the underlying view
Throws: - IndexOutOfBoundsException – if
index
is outside the
range of the view
Returns: row index in terms of the view
/**
* Returns the location of <code>index</code> in terms of the
* underlying model. That is, for the row <code>index</code> in
* the coordinates of the view this returns the row index in terms
* of the underlying model.
*
* @param index the row index in terms of the underlying view
* @return row index in terms of the view
* @throws IndexOutOfBoundsException if <code>index</code> is outside the
* range of the view
*/
public abstract int convertRowIndexToModel(int index);
Returns the location of index
in terms of the
view. That is, for the row index
in the
coordinates of the underlying model this returns the row index
in terms of the view.
Params: - index – the row index in terms of the underlying model
Throws: - IndexOutOfBoundsException – if
index
is outside
the range of the model
Returns: row index in terms of the view, or -1 if index has been
filtered out of the view
/**
* Returns the location of <code>index</code> in terms of the
* view. That is, for the row <code>index</code> in the
* coordinates of the underlying model this returns the row index
* in terms of the view.
*
* @param index the row index in terms of the underlying model
* @return row index in terms of the view, or -1 if index has been
* filtered out of the view
* @throws IndexOutOfBoundsException if <code>index</code> is outside
* the range of the model
*/
public abstract int convertRowIndexToView(int index);
Sets the current sort keys.
Params: - keys – the new
SortKeys
; null
is a shorthand for specifying an empty list,
indicating that the view should be unsorted
/**
* Sets the current sort keys.
*
* @param keys the new <code>SortKeys</code>; <code>null</code>
* is a shorthand for specifying an empty list,
* indicating that the view should be unsorted
*/
public abstract void setSortKeys(List<? extends SortKey> keys);
Returns the current sort keys. This must return a
non-null List
and may return an unmodifiable List
. If you need to change the sort keys, make a copy of the returned List
, mutate the copy and invoke setSortKeys
with the new list. Returns: the current sort order
/**
* Returns the current sort keys. This must return a {@code
* non-null List} and may return an unmodifiable {@code List}. If
* you need to change the sort keys, make a copy of the returned
* {@code List}, mutate the copy and invoke {@code setSortKeys}
* with the new list.
*
* @return the current sort order
*/
public abstract List<? extends SortKey> getSortKeys();
Returns the number of rows in the view. If the contents have
been filtered this might differ from the row count of the
underlying model.
See Also: Returns: number of rows in the view
/**
* Returns the number of rows in the view. If the contents have
* been filtered this might differ from the row count of the
* underlying model.
*
* @return number of rows in the view
* @see #getModelRowCount
*/
public abstract int getViewRowCount();
Returns the number of rows in the underlying model.
See Also: Returns: number of rows in the underlying model
/**
* Returns the number of rows in the underlying model.
*
* @return number of rows in the underlying model
* @see #getViewRowCount
*/
public abstract int getModelRowCount();
Invoked when the underlying model structure has completely
changed. For example, if the number of columns in a
TableModel
changed, this method would be invoked.
You normally do not call this method. This method is public
to allow view classes to call it.
/**
* Invoked when the underlying model structure has completely
* changed. For example, if the number of columns in a
* <code>TableModel</code> changed, this method would be invoked.
* <p>
* You normally do not call this method. This method is public
* to allow view classes to call it.
*/
public abstract void modelStructureChanged();
Invoked when the contents of the underlying model have
completely changed. The structure of the table is the same,
only the contents have changed. This is typically sent when it
is too expensive to characterize the change in terms of the
other methods.
You normally do not call this method. This method is public
to allow view classes to call it.
/**
* Invoked when the contents of the underlying model have
* completely changed. The structure of the table is the same,
* only the contents have changed. This is typically sent when it
* is too expensive to characterize the change in terms of the
* other methods.
* <p>
* You normally do not call this method. This method is public
* to allow view classes to call it.
*/
public abstract void allRowsChanged();
Invoked when rows have been inserted into the underlying model
in the specified range (inclusive).
The arguments give the indices of the effected range.
The first argument is in terms of the model before the change, and
must be less than or equal to the size of the model before the change.
The second argument is in terms of the model after the change and must
be less than the size of the model after the change. For example,
if you have a 5-row model and add 3 items to the end of the model
the indices are 5, 7.
You normally do not call this method. This method is public
to allow view classes to call it.
Params: - firstRow – the first row
- endRow – the last row
Throws: - IndexOutOfBoundsException – if either argument is invalid, or
firstRow
> endRow
/**
* Invoked when rows have been inserted into the underlying model
* in the specified range (inclusive).
* <p>
* The arguments give the indices of the effected range.
* The first argument is in terms of the model before the change, and
* must be less than or equal to the size of the model before the change.
* The second argument is in terms of the model after the change and must
* be less than the size of the model after the change. For example,
* if you have a 5-row model and add 3 items to the end of the model
* the indices are 5, 7.
* <p>
* You normally do not call this method. This method is public
* to allow view classes to call it.
*
* @param firstRow the first row
* @param endRow the last row
* @throws IndexOutOfBoundsException if either argument is invalid, or
* <code>firstRow</code> > <code>endRow</code>
*/
public abstract void rowsInserted(int firstRow, int endRow);
Invoked when rows have been deleted from the underlying model
in the specified range (inclusive).
The arguments give the indices of the effected range and
are in terms of the model before the change.
For example, if you have a 5-row model and delete 3 items from the end
of the model the indices are 2, 4.
You normally do not call this method. This method is public
to allow view classes to call it.
Params: - firstRow – the first row
- endRow – the last row
Throws: - IndexOutOfBoundsException – if either argument is outside
the range of the model before the change, or
firstRow
> endRow
/**
* Invoked when rows have been deleted from the underlying model
* in the specified range (inclusive).
* <p>
* The arguments give the indices of the effected range and
* are in terms of the model <b>before</b> the change.
* For example, if you have a 5-row model and delete 3 items from the end
* of the model the indices are 2, 4.
* <p>
* You normally do not call this method. This method is public
* to allow view classes to call it.
*
* @param firstRow the first row
* @param endRow the last row
* @throws IndexOutOfBoundsException if either argument is outside
* the range of the model before the change, or
* <code>firstRow</code> > <code>endRow</code>
*/
public abstract void rowsDeleted(int firstRow, int endRow);
Invoked when rows have been changed in the underlying model
between the specified range (inclusive).
You normally do not call this method. This method is public
to allow view classes to call it.
Params: - firstRow – the first row, in terms of the underlying model
- endRow – the last row, in terms of the underlying model
Throws: - IndexOutOfBoundsException – if either argument is outside
the range of the underlying model, or
firstRow
> endRow
/**
* Invoked when rows have been changed in the underlying model
* between the specified range (inclusive).
* <p>
* You normally do not call this method. This method is public
* to allow view classes to call it.
*
* @param firstRow the first row, in terms of the underlying model
* @param endRow the last row, in terms of the underlying model
* @throws IndexOutOfBoundsException if either argument is outside
* the range of the underlying model, or
* <code>firstRow</code> > <code>endRow</code>
*/
public abstract void rowsUpdated(int firstRow, int endRow);
Invoked when the column in the rows have been updated in
the underlying model between the specified range.
You normally do not call this method. This method is public
to allow view classes to call it.
Params: - firstRow – the first row, in terms of the underlying model
- endRow – the last row, in terms of the underlying model
- column – the column that has changed, in terms of the underlying
model
Throws: - IndexOutOfBoundsException – if either argument is outside
the range of the underlying model after the change,
firstRow
> endRow
, or
column
is outside the range of the underlying
model
/**
* Invoked when the column in the rows have been updated in
* the underlying model between the specified range.
* <p>
* You normally do not call this method. This method is public
* to allow view classes to call it.
*
* @param firstRow the first row, in terms of the underlying model
* @param endRow the last row, in terms of the underlying model
* @param column the column that has changed, in terms of the underlying
* model
* @throws IndexOutOfBoundsException if either argument is outside
* the range of the underlying model after the change,
* <code>firstRow</code> > <code>endRow</code>, or
* <code>column</code> is outside the range of the underlying
* model
*/
public abstract void rowsUpdated(int firstRow, int endRow, int column);
Adds a RowSorterListener
to receive notification
about this RowSorter
. If the same
listener is added more than once it will receive multiple
notifications. If l
is null
nothing
is done.
Params: - l – the
RowSorterListener
/**
* Adds a <code>RowSorterListener</code> to receive notification
* about this <code>RowSorter</code>. If the same
* listener is added more than once it will receive multiple
* notifications. If <code>l</code> is <code>null</code> nothing
* is done.
*
* @param l the <code>RowSorterListener</code>
*/
public void addRowSorterListener(RowSorterListener l) {
listenerList.add(RowSorterListener.class, l);
}
Removes a RowSorterListener
. If
l
is null
nothing is done.
Params: - l – the
RowSorterListener
/**
* Removes a <code>RowSorterListener</code>. If
* <code>l</code> is <code>null</code> nothing is done.
*
* @param l the <code>RowSorterListener</code>
*/
public void removeRowSorterListener(RowSorterListener l) {
listenerList.remove(RowSorterListener.class, l);
}
Notifies listener that the sort order has changed.
/**
* Notifies listener that the sort order has changed.
*/
protected void fireSortOrderChanged() {
fireRowSorterChanged(new RowSorterEvent(this));
}
Notifies listener that the mapping has changed.
Params: - lastRowIndexToModel – the mapping from model indices to
view indices prior to the sort, may be
null
/**
* Notifies listener that the mapping has changed.
*
* @param lastRowIndexToModel the mapping from model indices to
* view indices prior to the sort, may be <code>null</code>
*/
protected void fireRowSorterChanged(int[] lastRowIndexToModel) {
fireRowSorterChanged(new RowSorterEvent(this,
RowSorterEvent.Type.SORTED, lastRowIndexToModel));
}
void fireRowSorterChanged(RowSorterEvent event) {
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == RowSorterListener.class) {
((RowSorterListener)listeners[i + 1]).
sorterChanged(event);
}
}
}
SortKey describes the sort order for a particular column. The
column index is in terms of the underlying model, which may differ
from that of the view.
Since: 1.6
/**
* SortKey describes the sort order for a particular column. The
* column index is in terms of the underlying model, which may differ
* from that of the view.
*
* @since 1.6
*/
public static class SortKey {
private int column;
private SortOrder sortOrder;
Creates a SortKey
for the specified column with
the specified sort order.
Params: - column – index of the column, in terms of the model
- sortOrder – the sorter order
Throws: - IllegalArgumentException – if
sortOrder
is
null
/**
* Creates a <code>SortKey</code> for the specified column with
* the specified sort order.
*
* @param column index of the column, in terms of the model
* @param sortOrder the sorter order
* @throws IllegalArgumentException if <code>sortOrder</code> is
* <code>null</code>
*/
public SortKey(int column, SortOrder sortOrder) {
if (sortOrder == null) {
throw new IllegalArgumentException(
"sort order must be non-null");
}
this.column = column;
this.sortOrder = sortOrder;
}
Returns the index of the column.
Returns: index of column
/**
* Returns the index of the column.
*
* @return index of column
*/
public final int getColumn() {
return column;
}
Returns the sort order of the column.
Returns: the sort order of the column
/**
* Returns the sort order of the column.
*
* @return the sort order of the column
*/
public final SortOrder getSortOrder() {
return sortOrder;
}
Returns the hash code for this SortKey
.
Returns: hash code
/**
* Returns the hash code for this <code>SortKey</code>.
*
* @return hash code
*/
public int hashCode() {
int result = 17;
result = 37 * result + column;
result = 37 * result + sortOrder.hashCode();
return result;
}
Returns true if this object equals the specified object.
If the specified object is a SortKey
and
references the same column and sort order, the two objects
are equal.
Params: - o – the object to compare to
Returns: true if o
is equal to this SortKey
/**
* Returns true if this object equals the specified object.
* If the specified object is a <code>SortKey</code> and
* references the same column and sort order, the two objects
* are equal.
*
* @param o the object to compare to
* @return true if <code>o</code> is equal to this <code>SortKey</code>
*/
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof SortKey) {
return (((SortKey)o).column == column &&
((SortKey)o).sortOrder == sortOrder);
}
return false;
}
}
}