2362N/A * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 2362N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 2362N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2362N/A * or visit www.oracle.com if you need additional information or have any 0N/A * An implementation of <code>RowSorter</code> that provides sorting and 0N/A * filtering around a grid-based data model. 0N/A * Beyond creating and installing a <code>RowSorter</code>, you very rarely 0N/A * need to interact with one directly. Refer to 0N/A * {@link javax.swing.table.TableRowSorter TableRowSorter} for a concrete 0N/A * implementation of <code>RowSorter</code> for <code>JTable</code>. 0N/A * Sorting is done based on the current <code>SortKey</code>s, in order. 0N/A * If two objects are equal (the <code>Comparator</code> for the 0N/A * column returns 0) the next <code>SortKey</code> is used. If no 0N/A * <code>SortKey</code>s remain or the order is <code>UNSORTED</code>, then 0N/A * the order of the rows in the model is used. 0N/A * Sorting of each column is done by way of a <code>Comparator</code> 0N/A * that you can specify using the <code>setComparator</code> method. 0N/A * If a <code>Comparator</code> has not been specified, the 0N/A * <code>Comparator</code> returned by 0N/A * <code>Collator.getInstance()</code> is used on the results of 0N/A * calling <code>toString</code> on the underlying objects. The 0N/A * <code>Comparator</code> is never passed <code>null</code>. A 0N/A * <code>null</code> value is treated as occuring before a 0N/A * non-<code>null</code> value, and two <code>null</code> values are * If you specify a <code>Comparator</code> that casts its argument to * a type other than that provided by the model, a * <code>ClassCastException</code> will be thrown when the data is sorted. * In addition to sorting, <code>DefaultRowSorter</code> provides the * ability to filter rows. Filtering is done by way of a * <code>RowFilter</code> that is specified using the * <code>setRowFilter</code> method. If no filter has been specified all * By default, rows are in unsorted order (the same as the model) and * every column is sortable. The default <code>Comparator</code>s are * documented in the subclasses (for example, {@link * javax.swing.table.TableRowSorter TableRowSorter}). * If the underlying model structure changes (the * <code>modelStructureChanged</code> method is invoked) the following * are reset to their default values: <code>Comparator</code>s by * column, current sort order, and whether each column is sortable. To * find the default <code>Comparator</code>s, see the concrete * implementation (for example, {@link * javax.swing.table.TableRowSorter TableRowSorter}). The default * sort order is unsorted (the same as the model), and columns are * If the underlying model structure changes (the * <code>modelStructureChanged</code> method is invoked) the following * are reset to their default values: <code>Comparator</code>s by column, * current sort order and whether a column is sortable. * <code>DefaultRowSorter</code> is an abstract class. Concrete * subclasses must provide access to the underlying data by invoking * {@code setModelWrapper}. The {@code setModelWrapper} method * <b>must</b> be invoked soon after the constructor is * called, ideally from within the subclass's constructor. * Undefined behavior will result if you use a {@code * DefaultRowSorter} without specifying a {@code ModelWrapper}. * <code>DefaultRowSorter</code> has two formal type parameters. The * first type parameter corresponds to the class of the model, for example * <code>DefaultTableModel</code>. The second type parameter * corresponds to the class of the identifier passed to the * <code>RowFilter</code>. Refer to <code>TableRowSorter</code> and * <code>RowFilter</code> for more details on the type parameters. * @param <M> the type of the model * @param <I> the type of the identifier passed to the <code>RowFilter</code> * @see javax.swing.table.TableRowSorter * @see javax.swing.table.DefaultTableModel * @see java.text.Collator * Whether or not we resort on TableModelEvent.UPDATEs. * View (JTable) -> model. * Comparators specified by column. * Whether or not the specified column is sortable, by column. * Cached SortKeys for the current sort. * Cached comparators for the current sort * Developer supplied Filter. * Value passed to the filter. The same instance is passed to the * filter for different rows. * Whether or not to use getStringValueAt. This is indexed by column. * Indicates the contents are sorted. This is used if * getSortsOnUpdates is false and an update event is received. * Maximum number of sort keys. * Size of the model. This is used to enforce error checking within * the table changed notification methods (such as rowsInserted). * Creates an empty <code>DefaultRowSorter</code>. * Sets the model wrapper providing the data that is being sorted and * @param modelWrapper the model wrapper responsible for providing the * data that gets sorted and filtered * @throws IllegalArgumentException if {@code modelWrapper} is "modelWrapper most be non-null");
// If last is null, we're in the constructor. If we're in // the constructor we don't want to call to overridable methods. * Returns the model wrapper providing the data that is being sorted and * @return the model wrapper responsible for providing the data that * gets sorted and filtered * Returns the underlying model. * @return the underlying model * Sets whether or not the specified column is sortable. The specified * value is only checked when <code>toggleSortOrder</code> is invoked. * It is still possible to sort on a column that has been marked as * unsortable by directly setting the sort keys. The default is * @param column the column to enable or disable sorting on, in terms * of the underlying model * @param sortable whether or not the specified column is sortable * @throws IndexOutOfBoundsException if <code>column</code> is outside * Returns true if the specified column is sortable; otherwise, false. * @param column the column to check sorting for, in terms of the * @return true if the column is sortable * @throws IndexOutOfBoundsException if column is outside * the range of the underlying model * Sets the sort keys. This creates a copy of the supplied * {@code List}; subsequent changes to the supplied * {@code List} do not effect this {@code DefaultRowSorter}. * If the sort keys have changed this triggers a sort. * @param sortKeys the new <code>SortKeys</code>; <code>null</code> * is a shorthand for specifying an empty list, * indicating that the view should be unsorted * @throws IllegalArgumentException if any of the values in * <code>sortKeys</code> are null or have a column index outside // Currently unsorted, use sort so that internal fields * Returns the current sort keys. This returns an unmodifiable * {@code non-null 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 * Sets the maximum number of sort keys. The number of sort keys * determines how equal values are resolved when sorting. For * example, assume a table row sorter is created and * <code>setMaxSortKeys(2)</code> is invoked on it. The user * clicks the header for column 1, causing the table rows to be * sorted based on the items in column 1. Next, the user clicks * the header for column 2, causing the table to be sorted based * on the items in column 2; if any items in column 2 are equal, * then those particular rows are ordered based on the items in * column 1. In this case, we say that the rows are primarily * sorted on column 2, and secondarily on column 1. If the user * then clicks the header for column 3, then the items are * primarily sorted on column 3 and secondarily sorted on column * 2. Because the maximum number of sort keys has been set to 2 * with <code>setMaxSortKeys</code>, column 1 no longer has an * The maximum number of sort keys is enforced by * <code>toggleSortOrder</code>. You can specify more sort * keys by invoking <code>setSortKeys</code> directly and they will * all be honored. However if <code>toggleSortOrder</code> is subsequently * invoked the maximum number of sort keys will be enforced. * The default value is 3. * @param max the maximum number of sort keys * @throws IllegalArgumentException if <code>max</code> < 1 * Returns the maximum number of sort keys. * @return the maximum number of sort keys * If true, specifies that a sort should happen when the underlying * model is updated (<code>rowsUpdated</code> is invoked). For * example, if this is true and the user edits an entry the * location of that item in the view may change. The default is * @param sortsOnUpdates whether or not to sort on update events * Returns true if a sort should happen when the underlying * model is updated; otherwise, returns false. * @return whether or not to sort when the model is updated * Sets the filter that determines which rows, if any, should be * hidden from the view. The filter is applied before sorting. A value * of <code>null</code> indicates all values from the model should be * <code>RowFilter</code>'s <code>include</code> method is passed an * <code>Entry</code> that wraps the underlying model. The number * of columns in the <code>Entry</code> corresponds to the * number of columns in the <code>ModelWrapper</code>. The identifier * comes from the <code>ModelWrapper</code> as well. * This method triggers a sort. * @param filter the filter used to determine what entries should be * Returns the filter that determines which rows, if any, should * Reverses 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 * @param column index of the column to make the primary sorted column, * in terms of the underlying model * @throws IndexOutOfBoundsException {@inheritDoc} * @see #setSortable(int,boolean) * @see #setMaxSortKeys(int) // It's the primary sorting key, toggle it // It's not the first, but was sorted on, remove old // entry, insert as first with ascending. * @throws IndexOutOfBoundsException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} * Sorts the existing filtered data. This should only be used if * the filter hasn't changed. // Update the modelToView array * Sorts and filters the rows in the view based on the sort keys * of the columns currently being sorted and the filter, if any, * associated with this sorter. An empty <code>sortKeys</code> list * indicates that the view should unsorted, the same as the model. // No need to do anything. // There is filter, reset mappings // Update the modelToView array * Updates the useToString mapping before a sort. * Resets the viewToModel and modelToView mappings based on * Makes sure the modelToView array is of size rowCount. * Resets the viewToModel array to be of size rowCount. * Caches the sort keys before a sort. for (
int i =
0; i <
keySize; i++) {
* Returns whether or not to convert the value to a string before * doing comparisons when sorting. If true * <code>ModelWrapper.getStringValueAt</code> will be used, otherwise * <code>ModelWrapper.getValueAt</code> will be used. It is up to * subclasses, such as <code>TableRowSorter</code>, to honor this value * in their <code>ModelWrapper</code> implementation. * @param column the index of the column to test, in terms of the * @throws IndexOutOfBoundsException if <code>column</code> is not valid * Refreshes the modelToView mapping from that of viewToModel. * If <code>unsetFirst</code> is true, all indices in modelToView are * Sets the <code>Comparator</code> to use when sorting the specified * column. This does not trigger a sort. If you want to sort after * setting the comparator you need to explicitly invoke <code>sort</code>. * @param column the index of the column the <code>Comparator</code> is * to be used for, in terms of the underlying model * @param comparator the <code>Comparator</code> to use * @throws IndexOutOfBoundsException if <code>column</code> is outside * the range of the underlying model * Returns the <code>Comparator</code> for the specified * column. This will return <code>null</code> if a <code>Comparator</code> * has not been specified for the column. * @param column the column to fetch the <code>Comparator</code> for, in * terms of the underlying model * @return the <code>Comparator</code> for the specified column * @throws IndexOutOfBoundsException if column is outside * the range of the underlying model // Returns the Comparator to use during sorting. Where as // getComparator() may return null, this will never return null. // This should be ok as useToString(column) should have returned // When filtering this may differ from getModelWrapper().getRowCount() // Keys are already empty, to force a resort we have to * @throws IndexOutOfBoundsException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} * Returns true if the specified row should be included. // null filter, always include the row. // v1 != null && v2 != null // Treat nulls as < then non-null // If we get here, they're equal. Fallback to model order. * Insets new set of entries. * @param toAdd the Rows to add, sorted * @param current the array to insert the items into for (
int i =
0; i <
max; i++) {
* Returns true if we should try and optimize the processing of the * <code>TableModelEvent</code>. If this returns false, assume the * event was dealt with and no further processing needs to happen. // Not transformed, nothing to do. // We either weren't sorted, or to much changed, sort it all // Build the list of Rows to add into added // Adjust the model index of rows after the effected region // Insert newly added rows into viewToModel // Figure out how many visible rows are going to be effected. // Update the model index of rows after the effected region // Then patch up the viewToModel array // Update the modelToView mapping // Remove the effected rows // Build the intermediary array: the array of // viewToModel without the effected rows. // Build the new viewToModel // Remove the effected rows, adding them to updated and setting // modelToView to -2 for any rows that were not filtered out // This row was filtered out // This row was visible, make sure it should still be // Build the intermediary array: the array of // viewToModel without the updated rows. // Recreate viewToModel, if necessary // Rebuild the new viewToModel array // And finally fire a sort event. "column beyond range of TableModel");
* <code>DefaultRowSorter.ModelWrapper</code> is responsible for providing * the data that gets sorted by <code>DefaultRowSorter</code>. You * normally do not interact directly with <code>ModelWrapper</code>. * Subclasses of <code>DefaultRowSorter</code> provide an * implementation of <code>ModelWrapper</code> wrapping another model. * <code>TableRowSorter</code> provides a <code>ModelWrapper</code> that * wraps a <code>TableModel</code>. * <code>ModelWrapper</code> makes a distinction between values as * <code>Object</code>s and <code>String</code>s. This allows * implementations to provide a custom string * converter to be used instead of invoking <code>toString</code> on the * @param <M> the type of the underlying model * @param <I> the identifier supplied to the filter * Creates a new <code>ModelWrapper</code>. * Returns the underlying model that this <code>Model</code> is * @return the underlying model * Returns the number of columns in the model. * @return the number of columns in the model * Returns the number of rows in the model. * @return the number of rows in the model * Returns the value at the specified index. * @param row the row index * @param column the column index * @return the value at the specified index * @throws IndexOutOfBoundsException if the indices are outside * Returns the value as a <code>String</code> at the specified * index. This implementation uses <code>toString</code> on * the result from <code>getValueAt</code> (making sure * to return an empty string for null values). Subclasses that * override this method should never return null. * @param row the row index * @param column the column index * @return the value at the specified index as a <code>String</code> * @throws IndexOutOfBoundsException if the indices are outside * Returns the identifier for the specified row. The return value * of this is used as the identifier for the * <code>RowFilter.Entry</code> that is passed to the * <code>RowFilter</code>. * @param row the row to return the identifier for, in terms of * @see RowFilter.Entry#getIdentifier * RowFilter.Entry implementation that delegates to the ModelWrapper. * getFilterEntry(int) creates the single instance of this that is * passed to the Filter. Only call getFilterEntry(int) to get * The index into the model, set in getFilterEntry * Row is used to handle the actual sorting by way of Comparable. It * will use the sortKeys to do the actual comparison. // NOTE: this class is static so that it can be placed in an array