/*
* 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
* {@link javax.swing.table.TableRowSorter 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.
* RowSorter
should not update its mapping
* until one of these methods is invoked.
* 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
* If this results in changing the sort order and sorting, the
* appropriate
* 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.
*/
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.
*
* @param firstRow the first row
* @param endRow the last row
* @throws IndexOutOfBoundsException if either argument is invalid, or
*
* 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.
*
* @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
*
* 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
*
* 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,
* 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
.
*
* @param RowSorter
.
*/
public RowSorter() {
}
/**
* 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.
* RowSorterListener
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.
*
* @param index the row index in terms of the underlying view
* @return row index in terms of the view
* @throws IndexOutOfBoundsException if index
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.
*
* @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 index
is outside
* the range of the model
*/
public abstract int convertRowIndexToView(int index);
/**
* Sets the current sort keys.
*
* @param keys the new SortKeys
; null
* 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 {@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.
*
* @return number of rows in the view
* @see #getModelRowCount
*/
public abstract int getViewRowCount();
/**
* 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.
* firstRow
> endRow
*/
public abstract void rowsInserted(int firstRow, int endRow);
/**
* Invoked when rows have been deleted from the underlying model
* in the specified range (inclusive).
* firstRow
> endRow
*/
public abstract void rowsDeleted(int firstRow, int endRow);
/**
* Invoked when rows have been changed in the underlying model
* between the specified range (inclusive).
* firstRow
> endRow
*/
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.
* firstRow
> endRow
, or
* column
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.
*
* @param l the RowSorterListener
*/
public void addRowSorterListener(RowSorterListener l) {
listenerList.add(RowSorterListener.class, l);
}
/**
* Removes a RowSorterListener
. If
* l
is null
nothing is done.
*
* @param l the RowSorterListener
*/
public void removeRowSorterListener(RowSorterListener l) {
listenerList.remove(RowSorterListener.class, l);
}
/**
* Notifies listener that the sort order has changed.
*/
protected void fireSortOrderChanged() {
fireRowSorterChanged(new RowSorterEvent(this));
}
/**
* Notifies listener that the mapping has changed.
*
* @param lastRowIndexToModel the mapping from model indices to
* view indices prior to the sort, may be null
*/
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
*/
public static class SortKey {
private int column;
private SortOrder sortOrder;
/**
* Creates a SortKey
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 sortOrder
is
* null
*/
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.
*
* @return index of column
*/
public final int getColumn() {
return 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
.
*
* @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.
*
* @param o the object to compare to
* @return true if o
is equal to this SortKey
*/
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;
}
}
}