JDK-6316493 : Incoporate feedback on filtering/sorting API
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2005-08-26
  • Updated: 2017-05-16
  • Resolved: 2005-09-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availabitlity Release.

To download the current JDK release, click here.
6 b53Fixed
We've gotten some external feedback on swing's sorting/filtering API that should be incorporated before beta.

EVALUATION Here's the list of changes: javax.swing.RowFilter: Two new type parameters will be added: * @param <M> the type of the model; for example <code>PersonModel</code> * @param <I> the type of the identifier; when using * <code>TableRowSorter</code> this will be <code>Integer</code> public abstract class RowFilter<M,I>; They are used in the include method: public abstract boolean include(Entry<? extends M, ? extends I> entry); RowFilter's examples in the javadoc will be updated appropriately: * <pre> * RowFilter startsWithAFilter = new RowFilter&lt;Object,Object&gt;() { * public boolean include(Entry&lt;? extends Object, ? extends Object&gt; entry) { * for (int i = entry.getValueCount() - 1; i &gt;= 0; i--) { * if (entry.getStringValue(i).startsWith("a")) { * // The value starts with "a", include it * return true; * } * } * // None of the columns start with "a"; return false so that this * // entry is not shown * return false; * } * }; * </pre> * <code>RowFilter</code> has two formal type parameters that allow * you to create a <code>RowFilter</code> for a specific model. For * example, the following assumes a specific model that is wrapping * objects of type <code>Person</code>. Only <code>Person</code>s * with an age over 20 will be shown: * <pre> * RowFilter&lt;PersonModel,Integer&gt; ageFilter = new RowFilter&lt;PersonModel,Integer&gt;() { * public boolean include(Entry&lt;? extends PersonModel, ? extends Integer&gt; entry) { * PersonModel personModel = entry.getModel(); * Person person = personModel.getPerson(entry.getIdentifier()); * if (person.getAge() &gt; 20) { * // Returning true indicates this row should be shown. * return true; * } * // Age is &lt;= 20, don't show it. * return false; * } * }; * PersonModel model = createPersonModel(); * TableRowSorter&lt;PersonModel&gt; sorter = new TableRowSorter&lt;PersonModel&gt;(model); * sorter.setRowFilter(ageFilter); * </pre> RowFilter's factory methods have been updated as well: public static RowFilter<Object,Object> regexFilter(String regex, int... indices); public static RowFilter<Object,Object> dateFilter(ComparisonType type, Date date, int... indices); public static RowFilter<Object,Object> numberFilter(ComparisonType type, Number number, int... indices); public static <M,I> RowFilter<M,I> orFilter( List<RowFilter<M, I>> filters); public static <M,I> RowFilter<M,I> andFilter( List<RowFilter<M, I>> filters); public static <M,I> RowFilter<M,I> notFilter(RowFilter<M,I> filter); Of note is the orFilter/andFilter methods. These previously took varags. Because of restrictions on arrays and generics they now take Lists. This resulted in orFilter/andFilter now throwing an NPE if passed a null List: * @throws NullPointerException if <code>filters</code> is null Additionally regexFilter will be changed from using java.util.regex.Matcher.matches to java.util.regex.Matcher.find. The new javadoc will be: /** * Returns a <code>RowFilter</code> that uses a regular * expression to determine which entries to include. Only entries * with at least one matching value are included. For * example, the following creates a <code>RowFilter</code> that * includes entries with at least one value starting with * "a": * <pre> * RowFilter.regexFilter("^a"); * </pre> * <p> * The returned filter uses {@link java.util.regex.Matcher#find} * to test for inclusion. To test for exact matches use ^ and $ * to match the beginning and end of the string respectively. For * example, "^foo$" includes only whose string is exactly "foo" * and not, for example, "food". See {@link * java.util.regex.Pattern} for a complete description of the * supported regular-expression constructs. * * @param regex the regular expression to filter on * @param indices the indices of the values to check. If not supplied all * values are evaluated * @return a <code>RowFilter</code> implementing the specified criteria * @throws NullPointerException if <code>regex</code> is * <code>null</code> * @throws IllegalArgumentException if any of the columns * contains a value &lt; 0 * @throws PatternSyntaxException if <code>regex</code> is * not a valid regular expression. * @see java.util.regex.Pattern */ public static RowFilter<Object,Object> regexFilter(String regex, int... indices) { return new RegexFilter(Pattern.compile(regex), indices); } RowFilter's static inner class Entry will also get two type parameters: * @param <M> the type of the model; for example <code>PersonModel</code> * @param <I> the type of the identifier; when using * <code>TableRowSorter</code> this will be <code>Integer</code> public static abstract class Entry<M, I> {} The type parameters are used in the following methods: public abstract M getModel(); public abstract I getIdentifier(); javax.swing.RowSorter will get one type parameter: * @param <M> the type of the underlying model public abstract class RowSorter<M> { The new method getModel will use the type parameter: /** * Returns the underlying model. * * @return the underlying model */ public abstract M getModel(); RowSorter will also get the following new method: /** * Returns the number of rows in the underlying model. * * @return number of rows in the underlying model * @see #getViewRowCount */ public abstract int getModelRowCount(); RowSorter's inner class SortKey will get two new methods: /** * Returns the hash code for this <code>SortKey</code>. * * @return hash code */ public int hashCode(); /** * 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); And SortKey's getColumn and getSortOrder methods will be made final: public final int getColumn(); public final SortOrder getSortOrder(); javax.swing.DefaultRowSorter will also get two type parameters: * @param <M> the type of the model * @param <I> the type of the object passed to the <code>RowFilter</code> public abstract class DefaultRowSorter<M, I> extends RowSorter<M> { getModel will be renamed to getModelWrapper: protected abstract ModelWrapper<M,I> getModelWrapper(); set/getRowFilter will be updated based on the new type parameters: public void setRowFilter(RowFilter<? super M,? super I> filter); public RowFilter<? super M,? super I> getRowFilter(); The new method getModelRowCount will be overriden from the superclass: /** * {@inheritDoc} */ public int getModelRowCount(); javax.swing.DefaultRowSorter's static inner class Model will be renamed to ModelWrapper and get two type parameters: * @param <M> the type of the underlying model * @param <I> the identifier supplied to the filter protected abstract static class ModelWrapper<M,I>; The pararamter is returned from the getModel and the new getIdentifier method: public abstract M getModel(); /** * 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 */ public abstract I getIdentifier(int row); javax.swing.table.TableRowSorter: TableRowSorter will get one formal type parameter: * @param <M> the type of the model, which must be an implementation of * <code>TableModel</code> public class TableRowSorter<M extends TableModel> extends DefaultRowSorter<M, Integer>; The following methods will make use of it: public TableRowSorter(M model); /** * Sets the <code>TableModel</code> to use as the underlying model * for this <code>TableRowSorter</code>. A value of <code>null</code> * can be used to set an empty model. * * @param model the underlying model to use, or <code>null</code> */ public void setModel(M model) { /** * {@inheritDoc} */ public M getModel(); setModel/getModel were previously named set/getTableModel. They have been renamed to coincide with the getModel method of RowSorter. And what was getModel is now called getModelWrapper: /** * Returns an implementation of <code>DefaultRowSorter.ModelWrapper</code> * wrapping the provided <code>TableModel</code>. * * @return a <code>DefaultRowSorter.ModelWrapper</code> implementation * wrapping the provided <code>TableModel</code> */ protected ModelWrapper<M,Integer> getModelWrapper(); javax.swing.JTable has been changed to take a specific type of RowSorter: public void setRowSorter(RowSorter<? extends TableModel> sorter); public RowSorter<? extends TableModel> getRowSorter();