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 Availability Release.
We've gotten some external feedback on swing's sorting/filtering API that should be incorporated before beta.
Comments
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<Object,Object>() {
* public boolean include(Entry<? extends Object, ? extends Object> entry) {
* for (int i = entry.getValueCount() - 1; i >= 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<PersonModel,Integer> ageFilter = new RowFilter<PersonModel,Integer>() {
* public boolean include(Entry<? extends PersonModel, ? extends Integer> entry) {
* PersonModel personModel = entry.getModel();
* Person person = personModel.getPerson(entry.getIdentifier());
* if (person.getAge() > 20) {
* // Returning true indicates this row should be shown.
* return true;
* }
* // Age is <= 20, don't show it.
* return false;
* }
* };
* PersonModel model = createPersonModel();
* TableRowSorter<PersonModel> sorter = new TableRowSorter<PersonModel>(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 < 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();