< prev index next >

src/java.desktop/share/classes/javax/swing/DefaultRowSorter.java

Print this page

        

*** 31,111 **** import java.util.Comparator; import java.util.List; import javax.swing.SortOrder; /** ! * An implementation of <code>RowSorter</code> that provides sorting and * filtering around a grid-based data model. ! * 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> ! * Sorting is done based on the current <code>SortKey</code>s, in order. ! * If two objects are equal (the <code>Comparator</code> for the ! * column returns 0) the next <code>SortKey</code> is used. If no ! * <code>SortKey</code>s remain or the order is <code>UNSORTED</code>, then * the order of the rows in the model is used. * <p> ! * Sorting of each column is done by way of a <code>Comparator</code> ! * that you can specify using the <code>setComparator</code> method. ! * If a <code>Comparator</code> has not been specified, the ! * <code>Comparator</code> returned by ! * <code>Collator.getInstance()</code> is used on the results of ! * calling <code>toString</code> on the underlying objects. The ! * <code>Comparator</code> is never passed <code>null</code>. A ! * <code>null</code> value is treated as occurring before a ! * non-<code>null</code> value, and two <code>null</code> values are * considered equal. * <p> ! * 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. * <p> ! * 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 * rows are included. * <p> * 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}). * <p> * 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 * sortable by default. * <p> * 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. * <p> ! * <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}. * <p> ! * <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 * @since 1.6 */ --- 31,111 ---- import java.util.Comparator; import java.util.List; import javax.swing.SortOrder; /** ! * An implementation of {@code RowSorter} that provides sorting and * filtering around a grid-based data model. ! * Beyond creating and installing a {@code RowSorter}, you very rarely * need to interact with one directly. Refer to * {@link javax.swing.table.TableRowSorter TableRowSorter} for a concrete ! * implementation of {@code RowSorter} for {@code JTable}. * <p> ! * Sorting is done based on the current {@code SortKey}s, in order. ! * If two objects are equal (the {@code Comparator} for the ! * column returns 0) the next {@code SortKey} is used. If no ! * {@code SortKey}s remain or the order is {@code UNSORTED}, then * the order of the rows in the model is used. * <p> ! * Sorting of each column is done by way of a {@code Comparator} ! * that you can specify using the {@code setComparator} method. ! * If a {@code Comparator} has not been specified, the ! * {@code Comparator} returned by ! * {@code Collator.getInstance()} is used on the results of ! * calling {@code toString} on the underlying objects. The ! * {@code Comparator} is never passed {@code null}. A ! * {@code null} value is treated as occurring before a ! * non-{@code null} value, and two {@code null} values are * considered equal. * <p> ! * If you specify a {@code Comparator} that casts its argument to * a type other than that provided by the model, a ! * {@code ClassCastException} will be thrown when the data is sorted. * <p> ! * In addition to sorting, {@code DefaultRowSorter} provides the * ability to filter rows. Filtering is done by way of a ! * {@code RowFilter} that is specified using the ! * {@code setRowFilter} method. If no filter has been specified all * rows are included. * <p> * By default, rows are in unsorted order (the same as the model) and ! * every column is sortable. The default {@code Comparator}s are * documented in the subclasses (for example, {@link * javax.swing.table.TableRowSorter TableRowSorter}). * <p> * If the underlying model structure changes (the ! * {@code modelStructureChanged} method is invoked) the following ! * are reset to their default values: {@code Comparator}s by * column, current sort order, and whether each column is sortable. To ! * find the default {@code Comparator}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 * sortable by default. * <p> * If the underlying model structure changes (the ! * {@code modelStructureChanged} method is invoked) the following ! * are reset to their default values: {@code Comparator}s by column, * current sort order and whether a column is sortable. * <p> ! * {@code DefaultRowSorter} 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}. * <p> ! * {@code DefaultRowSorter} has two formal type parameters. The * first type parameter corresponds to the class of the model, for example ! * {@code DefaultTableModel}. The second type parameter * corresponds to the class of the identifier passed to the ! * {@code RowFilter}. Refer to {@code TableRowSorter} and ! * {@code RowFilter} 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} * @see javax.swing.table.TableRowSorter * @see javax.swing.table.DefaultTableModel * @see java.text.Collator * @since 1.6 */
*** 188,198 **** */ private int modelRowCount; /** ! * Creates an empty <code>DefaultRowSorter</code>. */ public DefaultRowSorter() { sortKeys = Collections.emptyList(); maxSortKeys = 3; } --- 188,198 ---- */ private int modelRowCount; /** ! * Creates an empty {@code DefaultRowSorter}. */ public DefaultRowSorter() { sortKeys = Collections.emptyList(); maxSortKeys = 3; }
*** 242,260 **** return getModelWrapper().getModel(); } /** * 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 * true. * * @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 * the range of the model * @see #toggleSortOrder * @see #setSortKeys */ public void setSortable(int column, boolean sortable) { --- 242,260 ---- return getModelWrapper().getModel(); } /** * Sets whether or not the specified column is sortable. The specified ! * value is only checked when {@code toggleSortOrder} 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 * true. * * @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} is outside * the range of the model * @see #toggleSortOrder * @see #setSortKeys */ public void setSortable(int column, boolean sortable) {
*** 286,300 **** * 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 * the range of the model */ public void setSortKeys(List<? extends SortKey> sortKeys) { List<SortKey> old = this.sortKeys; if (sortKeys != null && sortKeys.size() > 0) { --- 286,300 ---- * 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 null} * 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} are null or have a column index outside * the range of the model */ public void setSortKeys(List<? extends SortKey> sortKeys) { List<SortKey> old = this.sortKeys; if (sortKeys != null && sortKeys.size() > 0) {
*** 337,369 **** /** * 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 * effect on the order. * <p> * 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> &lt; 1 */ public void setMaxSortKeys(int max) { if (max < 1) { throw new IllegalArgumentException("Invalid max"); } --- 337,369 ---- /** * 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)} 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}, column 1 no longer has an * effect on the order. * <p> * The maximum number of sort keys is enforced by ! * {@code toggleSortOrder}. You can specify more sort ! * keys by invoking {@code setSortKeys} directly and they will ! * all be honored. However if {@code toggleSortOrder} 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 < 1} */ public void setMaxSortKeys(int max) { if (max < 1) { throw new IllegalArgumentException("Invalid max"); }
*** 379,389 **** return maxSortKeys; } /** * 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 * false. * * @param sortsOnUpdates whether or not to sort on update events --- 379,389 ---- return maxSortKeys; } /** * If true, specifies that a sort should happen when the underlying ! * model is updated ({@code rowsUpdated} 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 * false. * * @param sortsOnUpdates whether or not to sort on update events
*** 403,420 **** } /** * 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 * included. * <p> ! * <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. * <p> * This method triggers a sort. * * @param filter the filter used to determine what entries should be * included --- 403,420 ---- } /** * 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} indicates all values from the model should be * included. * <p> ! * {@code RowFilter}'s {@code include} method is passed an ! * {@code Entry} that wraps the underlying model. The number ! * of columns in the {@code Entry} corresponds to the ! * number of columns in the {@code ModelWrapper}. The identifier ! * comes from the {@code ModelWrapper} as well. * <p> * This method triggers a sort. * * @param filter the filter used to determine what entries should be * included
*** 559,569 **** } /** * 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. * * @see #setRowFilter * @see #setSortKeys */ --- 559,569 ---- } /** * 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} list * indicates that the view should unsorted, the same as the model. * * @see #setRowFilter * @see #setSortKeys */
*** 703,730 **** } /** * 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 * underlying model * @return true if values are to be converted to strings before doing * comparisons when sorting ! * @throws IndexOutOfBoundsException if <code>column</code> is not valid */ protected boolean useToString(int column) { return (getComparator(column) == null); } /** * Refreshes the modelToView mapping from that of viewToModel. ! * If <code>unsetFirst</code> is true, all indices in modelToView are * first set to -1. */ private void setModelToViewFromViewToModel(boolean unsetFirst) { int i; if (unsetFirst) { --- 703,730 ---- } /** * Returns whether or not to convert the value to a string before * doing comparisons when sorting. If true ! * {@code ModelWrapper.getStringValueAt} will be used, otherwise ! * {@code ModelWrapper.getValueAt} will be used. It is up to ! * subclasses, such as {@code TableRowSorter}, to honor this value ! * in their {@code ModelWrapper} implementation. * * @param column the index of the column to test, in terms of the * underlying model * @return true if values are to be converted to strings before doing * comparisons when sorting ! * @throws IndexOutOfBoundsException if {@code column} is not valid */ protected boolean useToString(int column) { return (getComparator(column) == null); } /** * Refreshes the modelToView mapping from that of viewToModel. ! * If {@code unsetFirst} is true, all indices in modelToView are * first set to -1. */ private void setModelToViewFromViewToModel(boolean unsetFirst) { int i; if (unsetFirst) {
*** 747,764 **** } return new int[0]; } /** ! * 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 */ public void setComparator(int column, Comparator<?> comparator) { checkColumn(column); if (comparators == null) { --- 747,764 ---- } return new int[0]; } /** ! * Sets the {@code Comparator} 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}. * ! * @param column the index of the column the {@code Comparator} is * to be used for, in terms of the underlying model ! * @param comparator the {@code Comparator} to use ! * @throws IndexOutOfBoundsException if {@code column} is outside * the range of the underlying model */ public void setComparator(int column, Comparator<?> comparator) { checkColumn(column); if (comparators == null) {
*** 766,782 **** } comparators[column] = comparator; } /** ! * 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 */ public Comparator<?> getComparator(int column) { checkColumn(column); --- 766,782 ---- } comparators[column] = comparator; } /** ! * Returns the {@code Comparator} for the specified ! * column. This will return {@code null} if a {@code Comparator} * has not been specified for the column. * ! * @param column the column to fetch the {@code Comparator} for, in * terms of the underlying model ! * @return the {@code Comparator} for the specified column * @throws IndexOutOfBoundsException if column is outside * the range of the underlying model */ public Comparator<?> getComparator(int column) { checkColumn(column);
*** 1014,1024 **** current.length - last); } /** * 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. */ private boolean shouldOptimizeChange(int firstRow, int lastRow) { if (!isTransformed()) { // Not transformed, nothing to do. --- 1014,1024 ---- current.length - last); } /** * Returns true if we should try and optimize the processing of the ! * {@code TableModelEvent}. If this returns false, assume the * event was dealt with and no further processing needs to happen. */ private boolean shouldOptimizeChange(int firstRow, int lastRow) { if (!isTransformed()) { // Not transformed, nothing to do.
*** 1225,1264 **** } } /** ! * <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. * For example, ! * <code>TableRowSorter</code> provides a <code>ModelWrapper</code> that ! * wraps a <code>TableModel</code>. * <p> ! * <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 * object. * * @param <M> the type of the underlying model * @param <I> the identifier supplied to the filter * @since 1.6 * @see RowFilter * @see RowFilter.Entry */ protected abstract static class ModelWrapper<M,I> { /** ! * Creates a new <code>ModelWrapper</code>. */ protected ModelWrapper() { } /** ! * Returns the underlying model that this <code>Model</code> is * wrapping. * * @return the underlying model */ public abstract M getModel(); --- 1225,1264 ---- } } /** ! * {@code DefaultRowSorter.ModelWrapper} is responsible for providing ! * the data that gets sorted by {@code DefaultRowSorter}. You ! * normally do not interact directly with {@code ModelWrapper}. ! * Subclasses of {@code DefaultRowSorter} provide an ! * implementation of {@code ModelWrapper} wrapping another model. * For example, ! * {@code TableRowSorter} provides a {@code ModelWrapper} that ! * wraps a {@code TableModel}. * <p> ! * {@code ModelWrapper} makes a distinction between values as ! * {@code Object}s and {@code String}s. This allows * implementations to provide a custom string ! * converter to be used instead of invoking {@code toString} on the * object. * * @param <M> the type of the underlying model * @param <I> the identifier supplied to the filter * @since 1.6 * @see RowFilter * @see RowFilter.Entry */ protected abstract static class ModelWrapper<M,I> { /** ! * Creates a new {@code ModelWrapper}. */ protected ModelWrapper() { } /** ! * Returns the underlying model that this {@code Model} is * wrapping. * * @return the underlying model */ public abstract M getModel();
*** 1287,1305 **** * the range of the model */ public abstract Object getValueAt(int row, int column); /** ! * 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 * the range of the model */ public String getStringValueAt(int row, int column) { Object o = getValueAt(row, column); --- 1287,1305 ---- * the range of the model */ public abstract Object getValueAt(int row, int column); /** ! * Returns the value as a {@code String} at the specified ! * index. This implementation uses {@code toString} on ! * the result from {@code getValueAt} (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} * @throws IndexOutOfBoundsException if the indices are outside * the range of the model */ public String getStringValueAt(int row, int column) { Object o = getValueAt(row, column);
*** 1314,1325 **** } /** * 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 * the underlying model * @return the identifier * @see RowFilter.Entry#getIdentifier --- 1314,1325 ---- } /** * Returns the identifier for the specified row. The return value * of this is used as the identifier for the ! * {@code RowFilter.Entry} that is passed to the ! * {@code RowFilter}. * * @param row the row to return the identifier for, in terms of * the underlying model * @return the identifier * @see RowFilter.Entry#getIdentifier
< prev index next >