Skip to main content

RowSorter and related classes

18 replies [Last post]
forax
Offline
Joined: 2004-10-07
Points: 0

First a want thank SUN folks to adding sorting and filtering capability to JTable.

I suppose that the reason why RowSorter is included in javax.swing and not javax.swing.table, is that RowSorter
could be used not only on a JTable but on
JList and JTree too, that's great.

I have some remarks about the design of RowSorter and the
related classes.
Let me fisrt write what i think about the current design :
In order to implement sorting and filtering JTree, JList or JTree,
you need an adapter that convert rows and columns indexes,
this adpater need to be specific to the model.

So RowSorter provide support for converting events and
subtypes of RowSorter provide the adapter
(TableRowSorter provide an adpater on TableModel, etc.)

1) I don't understand why there is two classes here
(RowSorter and DefaultRowSorter). One is sufficient.
Furthermore DefaultRowSorter is badly named because
it's an abstract class.
My advice, merge RowSorter and DefaultSorter in
one abstract class, that could be named
AbstractRowSorter or RowSorter.

2) Because RowSorter is generic and TableRowSorter
specific to TableModel, it's interresting to
parametrized RowSorter with the model type
(RowSorter) because it'a avoid lot of cast
(see belong)
In this case TableRowSorter extends
RowSorter.

3) DefaultRowSorter.Model is badly name because it
could lead to confusion between the model
(TableModel) and the adapter
(DefaultRowSorter.Model).
See methods getModel() and getTableModel() in
TableRowSorter.
Rename it to RowSorter.Adapter
in order to avoid confusion.

Like RowSorter, RowSorter.Adapter needs to
be parametrized by the type of the model. It's great
because getModel() could be typed
like this : M getModel().

4) Like RowSorter, RowFilter is generic for tree, list
and table so it have to be parametrized by M.
I really don't agree with the design of the
include method and more particularly the presence of
the RowFilter.Entry class.
Basically to filter we need to know the adapter
(RowSorter.Adapter) and the current row.
So i propose to change the signature of
method include() to
boolean include(RowSorter.Adapter adapter,int row).
It's avoid creation of Entry object and
ugly boxing in getIdentifier().

5) about TableStringConverter; i not really understand
why string convertion need to be specific to a table.
Rename it to StringConverter, parametrized it by M and
move it into javax.swing package.

public interface StringConverter {
String toString(M model, int row, int column);
}

6) In general i prefer using interface than
abstract class, abstract class is a bit more efficient
but a really much less flexible.
So RowFilter, StringConverter, RowSorterAdpater
are interfaces for me.

7) In JList, JTtree and JTable, get/setRowSorter() need
to be parametrized with the good model,
i.e. respectively RowSorter,
RowSorter and RowSorter.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
zixle
Offline
Joined: 2004-07-22
Points: 0

My first cut was a bit too restrictive. It would have to be:
public abstract boolean include(Entry entry);

With the setter/getter in TableRowSorter:

public void setRowFilter(RowFilter filter) {

-Scott

zixle
Offline
Joined: 2004-07-22
Points: 0

> I am still trying to work out a name for
> DefaultRowSorter.Model. I
> agree with you it needs to change before FCS.

And the winner is ModelWrapper.

-Scott

zixle
Offline
Joined: 2004-07-22
Points: 0

Hi Jeanette,

> Hmm, then I overlooked it ;) How would I do that? I mean without
> setting a new filter - ideally I would like to have that handled
> automatically for me: some listener getting notified that a view
> column was removed and all sorters/filters that depend on that
> column discarded without a necessity to interfere.

On the way home for work I was thinking this one through and had another thought. I'm not sure that visually adding/removing a column should in anyway change the filters. Consider the case where the developer has widgets outside the scope of the table controlling the filter. For example, I choose to see all email messages that have a status of important. Even if the status column isn't visible I expect the filter to still apply.

Alternatively if you change the structure of the TableModel the filters are chucked.

-Scott

kleopatra
Offline
Joined: 2003-06-11
Points: 0

Hi Scott,

>
> On the way home for work I was thinking this one
> through and had another thought. I'm not sure that
> visually adding/removing a column should in anyway
> change the filters. Consider the case where the
> developer has widgets outside the scope of the table
> controlling the filter. For example, I choose to see
> all email messages that have a status of important.
> Even if the status column isn't visible I expect the
> e filter to still apply.

SwingX added the concept of "hidden view columns" to allow a more fine-grained control than in core swing: in your example the status column may not be visible but still contained in the view (as a unchecked menu in the controlButton). By default, all view columns (hidden and visible) are accessible to sorting/filtering while non-view columns are not. This default can be changed easily.

There had been some discussions in the swingx forum about the requirements (and an issue #63-swingx), f.i.

http://www.javadesktop.org/forums/thread.jspa?messageID=38276

Jeanette

zixle
Offline
Joined: 2004-07-22
Points: 0

Hi Jeanette,

> > On the way home for work I was thinking this one
> > through and had another thought. I'm not sure that
> > visually adding/removing a column should in anyway
> > change the filters. Consider the case where the
> > developer has widgets outside the scope of the table
> > controlling the filter. For example, I choose to see
> > all email messages that have a status of important.
> > Even if the status column isn't visible I expect the
> > e filter to still apply.
>
> SwingX added the concept of "hidden view columns" to allow a more
> fine-grained control than in core swing: in your example the status
> column may not be visible but still contained in the view (as a
> unchecked menu in the controlButton). By default, all view columns
> (hidden and visible) are accessible to sorting/filtering while
> non-view columns are not. This default can be changed easily.

There are two options:

. You want to filter all columns in the model.
. You only want to filter columns that are displayed.

The first is what is supported out the box. The latter could be
supported by wrapping the original TableModel in a TableModel that
only provides a subset of the columns. There are use cases where both
make sense.

In some cases you want 2, for example typing in a string, in other
cases you want 1.

Do you think TableRowSorter really need support the later out of the box?

-Scott

zixle
Offline
Joined: 2004-07-22
Points: 0

Remi,

I am still trying to work out a name for DefaultRowSorter.Model. I
agree with you it needs to change before FCS.

I'm still for RowFilter and RowFilter.Entry as the allow for filtering
regardless of the view class. Some generification could help though.
For example, I could generify DefaultRowSorter on the model,
RowFilter.Entry on the model and identifier and RowFilter on the model
and identifier. That is:

public abstract class DefaultRowSorter extends RowSorter {

M = class of the model, eg TableModel

public static abstract class Entry {

M = class of model
I = identifier type, for tables/lists this'll be Integer.

public abstract class RowFilter {

M = class of model
I = identifier type, for tables/lists this'll be Integer.

setRowFilter on TableRowSorter would become:
public void setRowFilter(RowFilter filter) {

This would make the example in RowFilter:

RowFilter ageFilter = new RowFilter() {
public boolean include(Entry 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;
}
};

I suspect it would also be possible to generify on the value type, so
that instead of:

public static abstract class Entry {
public abstract Object getValue(int index);

you have:

public static abstract class Entry {
public V getValue(int);

This isn't useful for tables as you typically have heterogeneous data,
but for lists/tables/comboboxs this could be useful.

Thoughts?

-Scott

zixle
Offline
Joined: 2004-07-22
Points: 0

In my RowFilter example Identifier should be Integer. Sorry for any confusion.

-Scott

christian_schli...
Offline
Joined: 2005-05-21
Points: 0

For the impatient:

my TrueFilter project (http://truefilter.dev.java.net) provides a small package to do filtering of JLists. It decorates a ListModel and is completely dynamic, i.e. you can change the source list model, the filter and the elements in the source list model at any time. For some source list models it even allows to update the filtered list model which automatically updates the source list model as well (pass through).

Just my two cents...

With best regards,
Christian

christian_schli...
Offline
Joined: 2005-05-21
Points: 0

Hi,

forgot to mention that if you want to see the filter in action please visit http://truemirror.schlichtherle.de/en/ and start the TrueMirror application. The synchronization dialog provides more than twenty filters to filter the synchronization operations and allows even editing the operations which requires the "pass-through" feature of the filter.

Regards,
Christian

kleopatra
Offline
Joined: 2003-06-11
Points: 0

Old thread - but I wanted to keep Mustang sorter/filter related comments in one place. Here are a couple of my raw thoughts/questions, in no particular order (my primary interest currently is to understand the api, so please be lenient if I'm too far off the track :-)

* RowSorter API incomplete?

What's missing, IMO, are a full set of methods to access the allowed range for model/view row and model column coordinates. Without those, clients have no way to safely respect the preconditions of f.i. convertRowIndexToView(modelRow) and toggleSortColumn(modelColumn).

* RowSorter API doing too much?

Basically it's covering two areas of functionality

a) The major part is about allowing access to mapped indices between model <--> column and notification if those mappings are changed. Additionally there are updating methods to call if the model side of the mapping has changed so the object can update itself.

b) The minor part is about sorting which is one possible reason that might cause non-identity mappings.

Another possible reason for non-identity mappings is filtering which is handled in the DefaultRowSorter. This feels somehow "asymetrical" ... my gut (fed with maybe too much exposure to JDNC :-) would divide responsibilities into a mapping class (taking "a" above) with hooks to plug-in any functions that are the reason for the mapping (like sorting and/or filtering)

This would allow fine-grained control about updating mappings on a conceptual level: while both filtering and sorting need to be updated if the model changed (that's what DefaultRowSorter does do) - the filter mapping can be re-used if only the sortOrder/SortKeys/Comparator changed (that's what DefaultRowSorter doesn't do, but concededly could be implemented here easily enough)
not quite sure but shouldn't the sort be updated on setting the comparator?

* RowSorter ("mapping part") update notification methods too coarse?

The rowsInserted/-etc all take an interval of indices. While this is how f.i. Table/ListModel events notify there might be clients interested in a more general, "muliple-interval" notification, like a list of changed rows. Would be nice to have it here.

One use case would be to make it possible to chain mappers - a filter mapper can keep track of filter changes in terms of rows inserted/removed to the "view" which could be adapted to be the "model" of a sorter (yeah, the idea is stolen from the FilterPipeline of swingx decorators )

Another notification I miss is one about column removals (possibly for symetry reasons for additions as well, but can't think of a use case here). As the client might be interested to allow only a subset of the model to be included into the filtering/sorting, it would be nice to have a way to remove any filters/sorters on a column that's removed dynamically - structure changed is very coarse grained, the resulting sort() might or might not be necessary.

To make full use of finer-grained column changed notification the RowFilter would need a means to detect which columns it checks for including.

* JTable API

there are probably plans to add cover methods to access the filter/sorter objects? For clients interacting with the JTable these methods would be responsible for column coordinate transformation.

* J

are there plans to support list, tree, combo, (what else?) sorting in Mustang out-of-the-box? And/or are there any examples showing the usage of the sorter/filter api (the swingset doesn't yet seem to be updated)

Have a nice working day (mine is nearly over, I'm hungry :)
Jeanette

zixle
Offline
Joined: 2004-07-22
Points: 0

Hi Jeanette,

> Old thread - but I wanted to keep Mustang sorter/filter related
> comments in one place. Here are a couple of my raw
> thoughts/questions, in no particular order (my primary interest
> currently is to understand the api, so please be lenient if I'm too
> far off the track :)

Definitely, and I apologize for not responding immediately. It's easy
to forget to check the forums for responses. I've requested email
gateways, hopefully they'll get set up.

>
> * RowSorter API incomplete?
>
> What's missing, IMO, are a full set of methods to access the allowed
> range for model/view row and model column coordinates. Without
> those, clients have no way to safely respect the preconditions of
> f.i. convertRowIndexToView(modelRow) and
> toggleSortColumn(modelColumn).

In which place are you referring to?
RowSorter has the method getViewRowCount which returns the number of
rows visible. JTable's getRowCount will return the same thing.

> * RowSorter API doing too much?
>
> Basically it's covering two areas of functionality
>
> a) The major part is about allowing access to mapped indices between
> model <--> column and notification if those mappings are
> changed. Additionally there are updating methods to call if the
> model side of the mapping has changed so the object can update
> itself.
>
> b) The minor part is about sorting which is one possible reason that
> might cause non-identity mappings.
>
> Another possible reason for non-identity mappings is filtering which
> is handled in the DefaultRowSorter. This feels somehow "asymetrical"
> ... my gut (fed with maybe too much exposure to JDNC :) would divide
> responsibilities into a mapping class (taking "a" above) with hooks
> to plug-in any functions that are the reason for the mapping (like
> sorting and/or filtering)

In doing the mustang sorting/filtering API I thought long and hard on
this issue, as well as talking to various folks. One of the common
ways to tackle sorting/filtering is to create a generic model
adapter. If you want sorting, that becomes a model. If you want
filtering you create a specific model for that. If you want both
sorting and filtering you create two different models one wrapping the
other. This approach has been proven to work. I strayed away from it
for two reasons:

. It comes at the cost of complexity and cost. In particular when a
TableModel event is received it has to be mutated at each wrapped
model passing a new event up the chain. Many implementations of
sorting simply create a new TableModelEvent at each level saying
everything has changed. If you do not allow nesting you can
optimize this scenario much better.
. Most developers only want sorting and/or filtering, so that wrapping
models is just a means to an end and isn't really all that interesting
in and of itself.

> This would allow fine-grained control about updating mappings on a
> conceptual level: while both filtering and sorting need to be
> updated if the model changed (that's what DefaultRowSorter does do)
> - the filter mapping can be re-used if only the
> sortOrder/SortKeys/Comparator changed (that's what DefaultRowSorter
> doesn't do, but concededly could be implemented here easily enough)
> not quite sure but shouldn't the sort be
> updated on setting the comparator?

As you say, this is really just an optimization that could readily be
implemented.

> * RowSorter ("mapping part") update notification methods too coarse?
>
> The rowsInserted/-etc all take an interval of indices. While this is
> how f.i. Table/ListModel events notify there might be clients
> interested in a more general, "muliple-interval" notification, like
> a list of changed rows. Would be nice to have it here.

I was hestitant to add this as JTable does not yet support this. If
we were to add a new event type to TableModelEvent, then it would make
sense to add it to RowSorter too.

> One use case would be to make it possible to chain mappers - a
> filter mapper can keep track of filter changes in terms of rows
> inserted/removed to the "view" which could be adapted to be the
> "model" of a sorter (yeah, the idea is stolen from the
> FilterPipeline of swingx decorators ;)

I don't quite understand this point. You could always create one off
Filters if that is what you are after, and you can wrap many filters
inside of and/or type Filters.

> Another notification I miss is one about column removals (possibly
> for symetry reasons for additions as well, but can't think of a use
> case here). As the client might be interested to allow only a subset
> of the model to be included into the filtering/sorting, it would be
> nice to have a way to remove any filters/sorters on a column that's
> removed dynamically - structure changed is very coarse grained, the
> resulting sort() might or might not be necessary.

I was hestitant to optimize this because one can't know what a filter
(or event Comparator for that matter) is doing. By that I mean it's
entirely possible to write a Sorter or Comparator that looks at
objects that aren't visible.

> To make full use of finer-grained column changed notification the
> RowFilter would need a means to detect which columns it checks for
> including.

RowFilter allows you to specify which columns it is applied to.
You could remove Filters as you remove Columns.

> * JTable API
>
> there are probably plans to add cover methods to access the
> filter/sorter objects?

JTable got the following new methods:

set/getUpdateSelectionOnSort
set/getRowSorter
convertRowIndexToView
convertRowIndexToModel
sorterChanged

> For clients interacting with the JTable these
> methods would be responsible for column coordinate transformation.
>
> * J
>
> are there plans to support list, tree, combo, (what else?) sorting
> in Mustang out-of-the-box? And/or are there any examples showing the
> usage of the sorter/filter api (the swingset doesn't yet seem to be
> updated)

There isn't any time left for 1.6:( I hope to add support to list and
tree in 1.7. As you know, it'll be extremely tricky to add this to
list/tree.

> Have a nice working day (mine is nearly over, I'm hungry :)

;)
Thanks for the feedback!

-Scott

kleopatra
Offline
Joined: 2003-06-11
Points: 0

Hi Scott,

>
> Definitely, and I apologize for not responding
> immediately.

no problem.

> >
> > * RowSorter API incomplete?
> >
> > What's missing, IMO, are a full set of methods to
> access the allowed
> > range for model/view row and model column
> coordinates. Without
> > those, clients have no way to safely respect the
> preconditions of
> > f.i. convertRowIndexToView(modelRow) and
> > toggleSortColumn(modelColumn).
>
> In which place are you referring to?
> RowSorter has the method getViewRowCount which
> returns the number of
> rows visible. JTable's getRowCount will return the
> same thing.
>

in the methods I mentioned above: f.i. convertRowIndexToView(modelIndex) has the precondition of modelIndex < ??.getModelRowCount(). The RowSorter doesn't provide a means to get at that. So client code cannot savely use the RowSorter as such - they need access to information outside of the scope of class. Personally I prefer classes to be self-contained and complete (I might look up the correct OO terminology - but I'm too lazy right now )

> If
> you want both
> sorting and filtering you create two different models
> one wrapping the
> other. This approach has been proven to work.

exactly - that's what I tried to explain later on as chaining ;-)

> strayed away from it
> for two reasons:
>
> . It comes at the cost of complexity and cost. In
> particular when a
> TableModel event is received it has to be mutated
> ed at each wrapped
> model passing a new event up the chain. Many
> ny implementations of
> sorting simply create a new TableModelEvent at each
> ch level saying
> everything has changed.

citing the most primitive approach

> If you do not allow
> ow nesting you can
> optimize this scenario much better.

Hmm ... not convinced about the "optimize ... much better" - will come back to it later on.

> . Most developers only want sorting and/or filtering,
> so that wrapping
> models is just a means to an end and isn't really
> ly all that interesting
> in and of itself.
>

agreed: clients (most notably the view) are mostly interested in the overall mapping of the input (== model coordinates) to/from output (== view coordinates).

> > This would allow fine-grained control about
> updating mappings on a
> > conceptual level: while both filtering and sorting
> need to be
> > updated if the model changed (that's what
> DefaultRowSorter does do)
> > - the filter mapping can be re-used if only the
> > sortOrder/SortKeys/Comparator changed (that's what
> DefaultRowSorter
> > doesn't do, but concededly could be implemented
> here easily enough)
> As you say, this is really just an optimization that
> could readily be
> implemented.

maybe .. my gut tends to tell me that this optimization should be abstracted a bit further - DefaultRowSorter already is fat.

Repeating my question (just want to understand if that's be design or an oversight)

> > not quite sure but shouldn't
> the sort be
> > updated on setting the comparator? > aside>
>

>
> > * RowSorter ("mapping part") update notification
> methods too coarse?
> >
> > The rowsInserted/-etc all take an interval of
> indices. While this is
> > how f.i. Table/ListModel events notify there might
> be clients
> > interested in a more general, "muliple-interval"
> notification, like
> > a list of changed rows. Would be nice to have it
> here.
>
> I was hestitant to add this as JTable does not yet
> support this. If
> we were to add a new event type to TableModelEvent,
> then it would make
> sense to add it to RowSorter too.
>

Hmm ... it's obviously true that core TableModelEvent doesn't support multiple-interval notification, but real-world extensions do IMO it makes perfect sense to add it to the RowSorter now.

[ snipped bad description ]
>
> I don't quite understand this point.

what I meant is more or less the wrapping you describe above.

>
> > Another notification I miss is one about column
> removals [...]

> I was hestitant to optimize this because one can't
> know what a filter
> (or event Comparator for that matter) is doing. By
> that I mean it's
> entirely possible to write a Sorter or Comparator
> that looks at
> objects that aren't visible.

Beside that being a usability nightmare - there's something in between: SwingX has the concept of "view columns" - that's the subset of model columns controlled by the columnModel. These columns can be either visible or hidden. To limit filtering/Sorting to the subset of "view columns" is a reasonable default behaviour. This way we can have different sets of view columns viewed in different tables but backed by the same tableModel. I'm not sure how to realize such a scenario here?

>
> > To make full use of finer-grained column changed
> notification the
> > RowFilter would need a means to detect which
> columns it checks for
> > including.
>
> RowFilter allows you to specify which columns it is
> applied to.
> You could remove Filters as you remove Columns.
>

Hmm, then I overlooked it ;-) How would I do that? I mean without setting a new filter - ideally I would like to have that handled automatically for me: some listener getting notified that a view column was removed and all sorters/filters that depend on that column discarded without a necessity to interfere.

There are other bits I'm a unsure how to solve (didn't try too hard, so my apologies if it turns out to be trivial ;-)

- how to set the sort order into "neutral" position? I only see setSortKeys(null), but should doing a "reset sort order of this column" user interaction really have such a big side-effect (removing all)?

- let's say I want the model appear in the view in a pre-ordered state and allow header clicks to do the usual sort-this-column. Now resetting the interactively triggered sorting should revert to the pre-sorted state.

> > * JTable API
> >
> > there are probably plans to add cover methods to
> access the
> > filter/sorter objects?
>
> JTable got the following new methods:
>
> set/getUpdateSelectionOnSort
> set/getRowSorter
> convertRowIndexToView
> convertRowIndexToModel
> sorterChanged

yeah, I've seen those - but what I meant are methods in the good-old-table-tradition that allow to interact (more or less) exclusively with the table instead of having to know about such intricacies as models:

table.toggleSortOrder(int column)
table.resetSorter(?int column)
table.setRowFilter(...)
table.setColumnComparator(int column)

The coordinates will be view coordinates and the table will do the-right-thing. An indication that those are needed (IMO) is that the TableHeader has to do a columnIndex conversion ... shouldn't be necessary, the header lives entirely in "view".

> > are there plans to support list, tree, combo, (what
> else?) sorting
> > in Mustang out-of-the-box? And/or are there any
> examples showing the
> > usage of the sorter/filter api (the swingset
> doesn't yet seem to be
> > updated)
>
> There isn't any time left for 1.6:( I hope to add
> support to list and
> tree in 1.7. As you know, it'll be extremely tricky
> to add this to
> list/tree.
>

got me Fortunately I have the SwingLabs freedom which is a bit more than you have in core - so the list is no problem at all (with the ever so slightly dirty glitch to internally wrap the model). What I'm worried about is the tree - are there any code examples around for decorating a treeModel?

Thanks for listening!
Jeanette

zixle
Offline
Joined: 2004-07-22
Points: 0

Hi Jeanette,

> > > * RowSorter API incomplete?
> > >
> > > What's missing, IMO, are a full set of methods to
> > access the allowed
> > > range for model/view row and model column
> > coordinates. Without
> > > those, clients have no way to safely respect the
> > preconditions of
> > > f.i. convertRowIndexToView(modelRow) and
> > > toggleSortColumn(modelColumn).
> >
> > In which place are you referring to?
> > RowSorter has the method getViewRowCount which
> > returns the number of
> > rows visible. JTable's getRowCount will return the
> > same thing.
> >
>
> in the methods I mentioned above:
> f.i. convertRowIndexToView(modelIndex) has the precondition of
> modelIndex < ??.getModelRowCount(). The RowSorter doesn't provide a
> means to get at that. So client code cannot savely use the RowSorter
> as such - they need access to information outside of the scope of
> class. Personally I prefer classes to be self-contained and complete
> (I might look up the correct OO terminology - but I'm too lazy right
> now ;)

Ah, ok, now I see your point.
I didn't add this as I assumed folks would have the model at hand so
that it isn't all that interesting. None-the-less it would be trivial
to add a getModelRowCount. I had no need for it in implementing all
the sorting, so I assumed others wouldn't need it either. Do you
really see the need for it?

> > If
> > you want both
> > sorting and filtering you create two different models
> > one wrapping the
> > other. This approach has been proven to work.
>
> exactly - that's what I tried to explain later on as chaining ;)
>
> > strayed away from it
> > for two reasons:
> >
> > . It comes at the cost of complexity and cost. In
> > particular when a
> > TableModel event is received it has to be mutated
> > ed at each wrapped
> > model passing a new event up the chain. Many
> > ny implementations of
> > sorting simply create a new TableModelEvent at each
> > ch level saying
> > everything has changed.
>
> citing the most primitive approach

Yes. I'm assuming you haven't created a new set of event types
allowing for different types of notification than is currently
possible with JTable.

> > If you do not allow
> > ow nesting you can
> > optimize this scenario much better.
>
> Hmm ... not convinced about the "optimize ... much better" - will come back to it later on.
>
> > . Most developers only want sorting and/or filtering,
> > so that wrapping
> > models is just a means to an end and isn't really
> > ly all that interesting
> > in and of itself.
> >
>
> agreed: clients (most notably the view) are mostly interested in the
> overall mapping of the input (== model coordinates) to/from output
> (== view coordinates).
>
> > > This would allow fine-grained control about
> > updating mappings on a
> > > conceptual level: while both filtering and sorting
> > need to be
> > > updated if the model changed (that's what
> > DefaultRowSorter does do)
> > > - the filter mapping can be re-used if only the
> > > sortOrder/SortKeys/Comparator changed (that's what
> > DefaultRowSorter
> > > doesn't do, but concededly could be implemented
> > here easily enough)
> > As you say, this is really just an optimization that
> > could readily be
> > implemented.
>
> maybe .. my gut tends to tell me that this optimization should be
> abstracted a bit further - DefaultRowSorter already is fat.

Stepping back for a minute I designed this around the use case that a
filter should be a simple conditional. Should this object be included
or not? For example, show me all mail messages today, or show me
all cars within a radius of 50 miles. I believe this is the common
case for filtering. I did not design around filters being stateful
objects that may, at times, change their constraints. To allow
filters to be stateful requires notification from the filters and a
more complicated dependancy chain. I do not believe stateful filters
are the common case, and did not want to complicate the API to
accomodate for that.

Similarly I did not envision sorting as a multi-step process. Just a
single sorter that can sort multiple constraints if it need be.

If you buy these arguments then hopefully you understand why I took
the API the way I did.

I also don't think DefaultRowSorter is all that fat. It does what it
does and has a handful of optimizations that add to the heft. If I
removed the optimizations for the common cases it would certainly be a
bit thinner;)

> Repeating my question (just want to understand if that's be design
> or an oversight)

If I still haven't answered your question, please let me know.
Hopefully I'm not rambling.

> > > not quite sure but shouldn't
> > the sort be
> > > updated on setting the comparator? > > aside>

Good question. I can't think of a good reason as to why I didn't do
this:( I'll add to my list of things for 1.6.

> > > * RowSorter ("mapping part") update notification
> > methods too coarse?
> > >
> > > The rowsInserted/-etc all take an interval of
> > indices. While this is
> > > how f.i. Table/ListModel events notify there might
> > be clients
> > > interested in a more general, "muliple-interval"
> > notification, like
> > > a list of changed rows. Would be nice to have it
> > here.
> >
> > I was hestitant to add this as JTable does not yet
> > support this. If
> > we were to add a new event type to TableModelEvent,
> > then it would make
> > sense to add it to RowSorter too.
> >
>
> Hmm ... it's obviously true that core TableModelEvent doesn't
> support multiple-interval notification, but real-world extensions do
> IMO it makes perfect sense to add it to the RowSorter now.

I know we've had this argument on the JDNC forums. Do you have a
specific use case that would help drive home why it's important to
have multiple-interval notification?

> [ snipped bad description ]
> >
> > I don't quite understand this point.
>
> what I meant is more or less the wrapping you describe above.

So again, if I'm not answering your question, just tell me;)

> > > Another notification I miss is one about column
> > removals [...]
>
> > I was hestitant to optimize this because one can't
> > know what a filter
> > (or event Comparator for that matter) is doing. By
> > that I mean it's
> > entirely possible to write a Sorter or Comparator
> > that looks at
> > objects that aren't visible.
>
> Beside that being a usability nightmare - there's something in
> between: SwingX has the concept of "view columns" - that's the
> subset of model columns controlled by the columnModel. These columns
> can be either visible or hidden. To limit filtering/Sorting to the
> subset of "view columns" is a reasonable default behaviour. This way
> we can have different sets of view columns viewed in different
> tables but backed by the same tableModel. I'm not sure how to
> realize such a scenario here?

Yes, this currently isn't supported out of the box. I suppose
DefaultRowSorter or TableRowSorter could offer the ability to restrict
the columns that are filtered on. Perhaps a method like:

setFilterColumns(int[] columns);

where columns is an array in terms of the underlying model.

Is that what you are after?

> > > To make full use of finer-grained column changed
> > notification the
> > > RowFilter would need a means to detect which
> > columns it checks for
> > > including.
> >
> > RowFilter allows you to specify which columns it is
> > applied to.
> > You could remove Filters as you remove Columns.
> >
>
> Hmm, then I overlooked it ;) How would I do that? I mean without
> setting a new filter - ideally I would like to have that handled
> automatically for me: some listener getting notified that a view
> column was removed and all sorters/filters that depend on that
> column discarded without a necessity to interfere.

Unfortunately you would have to reapply the necessary filters/sort
keys. Again, I've done this to keep RowFilter as simple a class as
possible. If you added API to detect what columns the RowFilter
applied to you could accomplish something like you're after.

> There are other bits I'm a unsure how to solve (didn't try too hard,
> so my apologies if it turns out to be trivial ;)
>
> - how to set the sort order into "neutral" position? I only see
> setSortKeys(null), but should doing a "reset sort order of this
> column" user interaction really have such a big side-effect
> (removing all)?

I don't understand. If you want to remove the sort keys,
setSortKeys(null) is the way to go. It won't trigger a resort if
already unsorted. But perhaps I'm missing your question?

> - let's say I want the model appear in the view in a pre-ordered
> state and allow header clicks to do the usual sort-this-column. Now
> resetting the interactively triggered sorting should revert to the
> pre-sorted state.

I'm not sure I understand your question, so if I answer the wrong
thing try again;) Internally Swing will only ever call
toggleSortOrder, so if at some point you want to reset things you
could could call setSortKeys with whatever array you wanted.

> > > * JTable API
> > >
> > > there are probably plans to add cover methods to
> > access the
> > > filter/sorter objects?
> >
> > JTable got the following new methods:
> >
> > set/getUpdateSelectionOnSort
> > set/getRowSorter
> > convertRowIndexToView
> > convertRowIndexToModel
> > sorterChanged
>
> yeah, I've seen those - but what I meant are methods in the
> good-old-table-tradition that allow to interact (more or less)
> exclusively with the table instead of having to know about such
> intricacies as models:
>
> table.toggleSortOrder(int column)
> table.resetSorter(?int column)
> table.setRowFilter(...)
> table.setColumnComparator(int column)

There are no plans for this. I think all this API should remain in
the sorter.

> The coordinates will be view coordinates and the table will do
> the-right-thing. An indication that those are needed (IMO) is that
> the TableHeader has to do a columnIndex conversion ... shouldn't be
> necessary, the header lives entirely in "view".
>
> > > are there plans to support list, tree, combo, (what
> > else?) sorting
> > > in Mustang out-of-the-box? And/or are there any
> > examples showing the
> > > usage of the sorter/filter api (the swingset
> > doesn't yet seem to be
> > > updated)
> >
> > There isn't any time left for 1.6:( I hope to add
> > support to list and
> > tree in 1.7. As you know, it'll be extremely tricky
> > to add this to
> > list/tree.
> >
>
> got me Fortunately I have the SwingLabs freedom which is a bit
> more than you have in core - so the list is no problem at all (with
> the ever so slightly dirty glitch to internally wrap the
> model). What I'm worried about is the tree - are there any code
> examples around for decorating a treeModel?

If you wrap the model it's certainly easier. But I don't want to see
us do that for 1.7. I don't have any handy examples of wrapping a
TreeModel, but it shouldn't be that hard, although I know you'll run
into problems with sorting. The behavior for saying all descendants
of a node have changed will cause a behavior you won't like:(

-Scott

kleopatra
Offline
Joined: 2003-06-11
Points: 0

Hi Scott

>
> Ah, ok, now I see your point.
> I didn't add this as I assumed folks would have the
> model at hand so
> that it isn't all that interesting. None-the-less it
> would be trivial
> to add a getModelRowCount.

trivial if you are in a position to change the api

I had no need for it in
> implementing all
> the sorting, so I assumed others wouldn't need it
> either. Do you
> really see the need for it?
>

yes, I think so - there may be clients of the sorter without access to the model. Or the other way round - if all clients need access to a "model" than it should be part of the RowSorter instead of a concrete implementations. Personally I would add only the methods which allow an safe access to all precondition-containing methods.

An example for a client only interested in the _mapping_ (and totally uninterested in the actual values) is a selection/rowsizing handler, keeping track of selection/rowsizes in model coordinates and updating the related view classes. SwingX has both extracted for reuse across list-like views.

> Stepping back for a minute I designed this around the
> use case that a
> filter should be a simple conditional. Should this
> object be included
> or not? For example, show me all mail messages
> today, or show me
> all cars within a radius of 50 miles. I believe this
> is the common
> case for filtering. I did not design around filters
> being stateful
> objects that may, at times, change their constraints.
> To allow
> filters to be stateful requires notification from the
> filters and a
> more complicated dependancy chain. I do not believe
> stateful filters
> are the common case, and did not want to complicate
> the API to
> accomodate for that.
>
> Similarly I did not envision sorting as a multi-step
> process. Just a
> single sorter that can sort multiple constraints if
> it need be.
>
> If you buy these arguments then hopefully you
> understand why I took
> the API the way I did.

Don't get me wrong - those are perfectly valid design decisions! And I like many aspects of them - only I want to keep a bit more flexibility for now.

>
> I also don't think DefaultRowSorter is all that fat.
> It does what it
> does and has a handful of optimizations that add to
> the heft. If I
> removed the optimizations for the common cases it
> would certainly be a
> bit thinner;)
>

okay, it's not fat in the sense of obese, more in the sense of muscular .

>
> I know we've had this argument on the JDNC forums.
> Do you have a
> specific use case that would help drive home why it's
> important to
> have multiple-interval notification?
>

Nothing specific at the moment - will browse my attic (storage if old-known but never really solved problems) to see if I can find one.

> Unfortunately you would have to reapply the necessary
> filters/sort
> keys. Again, I've done this to keep RowFilter as
> simple a class as
> possible. If you added API to detect what columns
> the RowFilter
> applied to you could accomplish something like you're
> after.
>

again, that would be an api change - not open to everybody ;-)

> >
> > - how to set the sort order into "neutral"
> position? I only see
> > setSortKeys(null), but should doing a "reset sort
> order of this
> > column" user interaction really have such a big
> side-effect
> > (removing all)?
>
> I don't understand. If you want to remove the sort
> keys,
> setSortKeys(null) is the way to go. It won't trigger
> a resort if
> already unsorted. But perhaps I'm missing your
> question?
>

only because I did't explain it well enough (wouldn't understand it myself ;-). And thinking about it, I'm not entirely sure of what the usability requirements are. But, I'll try again:

- fact is that the sorter allows multi-column sorting (?). The latest toggleSortOrder adds a sortKey to the list (if the column doesn't already has one) thus enabling n-ary sorts.
-


- a user gesture to add a sort column might f.i. be a ctr-click on the header. An implementation might set the maxSortKeys to 1 on click without ctrl modifier and increase the maxSortKeys with every ctrl-click if the clicked column had not been sorted before, toggle sort order of that column if it had been sorted - and remove an already sorted column from the sortkeys on ctrl-shift click, f.i. Hmm... looks like much work for the implemetnation. Need to think a bit more about it, most probably overlooked something important.

> > - let's say I want the model appear in the view in
> a pre-ordered
> > state and allow header clicks to do the usual
> sort-this-column. Now
> > resetting the interactively triggered sorting
> should revert to the
> > pre-sorted state.
>
> I'm not sure I understand your question, so if I
> answer the wrong
> thing try again;) Internally Swing will only ever
> call
> toggleSortOrder, so if at some point you want to
> reset things you
> could could call setSortKeys with whatever array you
> wanted.
>

hmm ... I'm not quite sure where I would do that (spoiled by SwingX which distinguishes "interactively" triggered sorts from programmatically set sorts - currently at the cost of not supporting interactive multiple column sorts)

> > yeah, I've seen those - but what I meant are
> methods in the
> > good-old-table-tradition that allow to interact
> (more or less)
> > exclusively with the table instead of having to
> know about such
> > intricacies as models:
> >
> > table.toggleSortOrder(int column)
> > table.resetSorter(?int column)
> > table.setRowFilter(...)
> > table.setColumnComparator(int column)
>
> There are no plans for this. I think all this API
> should remain in
> the sorter.
>

Would care to elaborate a bit on the why? On first look such a decision seems to break JTable's overall design consistency - which is to allow clients to interact exclusively with the table and exclusively in view coordinates.

>
> > got me Fortunately I have the SwingLabs freedom
> which is a bit
> > more than you have in core - so the list is no
> problem at all (with
> > the ever so slightly dirty glitch to internally
> wrap the
> > model). What I'm worried about is the tree - are
> there any code
> > examples around for decorating a treeModel?
>
> If you wrap the model it's certainly easier. But I
> don't want to see
> us do that for 1.7.

It's a hack while waiting for the 1.7 views to add data access in view coordinates ;-)

> I don't have any handy examples
> of wrapping a
> TreeModel, but it shouldn't be that hard, although I
> know you'll run
> into problems with sorting. The behavior for saying
> all descendants
> of a node have changed will cause a behavior you
> won't like:(

that's what I feared ...

Thanks for your time and patience!
Jeanette

zixle
Offline
Joined: 2004-07-22
Points: 0

Hi Jeanette,

> > Ah, ok, now I see your point.
> > I didn't add this as I assumed folks would have the
> > model at hand so
> > that it isn't all that interesting. None-the-less it
> > would be trivial
> > to add a getModelRowCount.
>
> trivial if you are in a position to change the api
>
> I had no need for it in
> > implementing all
> > the sorting, so I assumed others wouldn't need it
> > either. Do you
> > really see the need for it?
> >
>
> yes, I think so - there may be clients of the sorter without access
> to the model. Or the other way round - if all clients need access to
> a "model" than it should be part of the RowSorter instead of a
> concrete implementations. Personally I would add only the methods
> which allow an safe access to all precondition-containing methods.
>
> An example for a client only interested in the _mapping_ (and
> totally uninterested in the actual values) is a selection/rowsizing
> handler, keeping track of selection/rowsizes in model coordinates
> and updating the related view classes. SwingX has both extracted for
> reuse across list-like views.

I'll add it to my list of things to add;)

> > Stepping back for a minute I designed this around the
> > use case that a
> > filter should be a simple conditional. Should this
> > object be included
> > or not? For example, show me all mail messages
> > today, or show me
> > all cars within a radius of 50 miles. I believe this
> > is the common
> > case for filtering. I did not design around filters
> > being stateful
> > objects that may, at times, change their constraints.
> > To allow
> > filters to be stateful requires notification from the
> > filters and a
> > more complicated dependancy chain. I do not believe
> > stateful filters
> > are the common case, and did not want to complicate
> > the API to
> > accomodate for that.
> >
> > Similarly I did not envision sorting as a multi-step
> > process. Just a
> > single sorter that can sort multiple constraints if
> > it need be.
> >
> > If you buy these arguments then hopefully you
> > understand why I took
> > the API the way I did.
>
> Don't get me wrong - those are perfectly valid design decisions! And
> I like many aspects of them - only I want to keep a bit more
> flexibility for now.

If I'm to read between the lines it would seem you don't agree with my
assumptions. Is that correct? If so, what are the important use
cases you're designing around?

> > I also don't think DefaultRowSorter is all that fat.
> > It does what it
> > does and has a handful of optimizations that add to
> > the heft. If I
> > removed the optimizations for the common cases it
> > would certainly be a
> > bit thinner;)
> >
>
> okay, it's not fat in the sense of obese, more in the sense of muscular .

LOL!

> > I know we've had this argument on the JDNC forums.
> > Do you have a
> > specific use case that would help drive home why it's
> > important to
> > have multiple-interval notification?
> >
>
> Nothing specific at the moment - will browse my attic (storage if
> old-known but never really solved problems) to see if I can find
> one.

That would be extremely helpful. I just can't see adding the
functionality without a real need.

> > Unfortunately you would have to reapply the necessary
> > filters/sort
> > keys. Again, I've done this to keep RowFilter as
> > simple a class as
> > possible. If you added API to detect what columns
> > the RowFilter
> > applied to you could accomplish something like you're
> > after.
> >
>
> again, that would be an api change - not open to everybody ;)

If you want to hide/show columns, and only allow filters to be active
on the visible columns then presumably you are in a position to know
what the set of filters are and so you should be able to reconstruct
them. For example, you could associate a RowFilter with each
TableColumn.

> > > - how to set the sort order into "neutral"
> > position? I only see
> > > setSortKeys(null), but should doing a "reset sort
> > order of this
> > > column" user interaction really have such a big
> > side-effect
> > > (removing all)?
> >
> > I don't understand. If you want to remove the sort
> > keys,
> > setSortKeys(null) is the way to go. It won't trigger
> > a resort if
> > already unsorted. But perhaps I'm missing your
> > question?
> >
>
> only because I did't explain it well enough (wouldn't understand it
> myself ;). And thinking about it, I'm not entirely sure of what the
> usability requirements are. But, I'll try again:
>
> - fact is that the sorter allows multi-column sorting (?). The
> latest toggleSortOrder adds a sortKey to the list (if the column
> doesn't already has one) thus enabling n-ary sorts.
> -

While I would like the UI to visually show it, keeping the last sort
key is expected behavior. For example, if you first click on the
First Name column then the Last Name Column, any identical Last Names
will be sorted by first name. Seems nice.

> - a user gesture to add a sort column might f.i. be a ctr-click on
> the header. An implementation might set the maxSortKeys to 1 on
> click without ctrl modifier and increase the maxSortKeys with every
> ctrl-click if the clicked column had not been sorted before, toggle
> sort order of that column if it had been sorted - and remove an
> already sorted column from the sortkeys on ctrl-shift click,
> f.i. Hmm... looks like much work for the implemetnation. Need to
> think a bit more about it, most probably overlooked something
> important.

I'm not sure that end users would realize that subteltly. In fact I
suspect end users won't notice the n osrt subteltly either:(

> > > - let's say I want the model appear in the view in
> > a pre-ordered
> > > state and allow header clicks to do the usual
> > sort-this-column. Now
> > > resetting the interactively triggered sorting
> > should revert to the
> > > pre-sorted state.
> >
> > I'm not sure I understand your question, so if I
> > answer the wrong
> > thing try again;) Internally Swing will only ever
> > call
> > toggleSortOrder, so if at some point you want to
> > reset things you
> > could could call setSortKeys with whatever array you
> > wanted.
> >
>
> hmm ... I'm not quite sure where I would do that (spoiled by SwingX
> which distinguishes "interactively" triggered sorts from
> programmatically set sorts - currently at the cost of not supporting
> interactive multiple column sorts)

I don't quite follow your comment.

> > > yeah, I've seen those - but what I meant are
> > methods in the
> > > good-old-table-tradition that allow to interact
> > (more or less)
> > > exclusively with the table instead of having to
> > know about such
> > > intricacies as models:
> > >
> > > table.toggleSortOrder(int column)
> > > table.resetSorter(?int column)
> > > table.setRowFilter(...)
> > > table.setColumnComparator(int column)
> >
> > There are no plans for this. I think all this API
> > should remain in
> > the sorter.
> >
>
> Would care to elaborate a bit on the why? On first look such a
> decision seems to break JTable's overall design consistency - which
> is to allow clients to interact exclusively with the table and
> exclusively in view coordinates.

Two reasons:

. I hadn't considered it;)
. They are only meaningful if you have installed a sorter. API of
that sort is always a pain.

So, I don't know that we've gotten anywhere. Do you have a list of
things you want to see changed?

Thanks,

-Scott

zixle
Offline
Joined: 2004-07-22
Points: 0

forax,

Thanks for the comments! I've been meaning to blog about the new sorting/filtering API, but have been swamped with JavaOne. Anyway, I wanted to respond to various comments you've raised. There have been long running threads on the JDNC and swing forums relating to this API. They are: http://www.javadesktop.org/forums/thread.jspa?forumID=2&threadID=11551&m... and http://www.javadesktop.org/forums/thread.jspa?threadID=10944&start=0&tst... .

For those wondering about the API look at: http://www.java.net/download/jdk6/docs/api/javax/swing/table/TableRowSor... you can branch out to almost all related API from there.

> 1) I don't understand why there is two classes here
> (RowSorter and DefaultRowSorter). One is sufficient.
> Furthermore DefaultRowSorter is badly named because
> it's an abstract class.
> My advice, merge RowSorter and DefaultSorter in
> one abstract class, that could be named
> AbstractRowSorter or RowSorter.

Numerous folks requested the ability to do sorting at the database level. Having RowSorter effectively empty allows for this.

> 2) Because RowSorter is generic and TableRowSorter
> specific to TableModel, it's interresting to
> parametrized RowSorter with the model type
> (RowSorter;) because it'a avoid lot of cast
> (see belong)
> In this case TableRowSorter extends
> RowSorter.

Yes, it should be possible to parameterize the return type, but it turns out it isn't really needed. If you look at the code for TableRowSorter you'll see that it doesn't directly need this.

> 3) DefaultRowSorter.Model is badly name because it
> could lead to confusion between the model
> (TableModel) and the adapter
> (DefaultRowSorter.Model).
> See methods getModel() and getTableModel() in
> TableRowSorter.
> Rename it to RowSorter.Adapter
> in order to avoid confusion.

We are rapidly running out of non-overloaded names in the JDK. From one perspective RowSorter has a model, that is called Model. It could be named RowModel, but as you'll almost always be referencing it by way of RowSorter.XXX that seemed a bit excessive.

When I think of the name Adapter I think of a listener subclass, eg MouseAdapter, KeyAdapter ...

> Like RowSorter, RowSorter.Adapter needs to
> be parametrized by the type of the model. It's great
> because getModel() could be typed
> like this : M getModel().

The concrete implementations will have their own reference to the model, so that I don't see this as saving all that much. Take a look at the source of TableRowSorter there are no casts.

> 4) Like RowSorter, RowFilter is generic for tree, list
> and table so it have to be parametrized by M.
> I really don't agree with the design of the
> include method and more particularly the presence of
> the RowFilter.Entry class.
> Basically to filter we need to know the adapter
> (RowSorter.Adapter) and the current row.
> So i propose to change the signature of
> method include() to
> boolean include(RowSorter.Adapter adapter,int row).
> It's avoid creation of Entry object and
> ugly boxing in getIdentifier().

All a Filter should care about is the available column counts and entries in the columns to filter by. I don't see why it needs to be tied to RowSorter.

I initially had int getIdentifier();, but I was worried that for trees we may want getIdentifier to be a TreePath. If I go with row that precludes something more meaningful later on.

> 5) about TableStringConverter; i not really understand
> why string convertion need to be specific to a table.
> Rename it to StringConverter, parametrized it by M and
> move it into javax.swing package.

TableStringConverter is initially only used by TableSorter, but at a later date JTable should take one to aid in converting strings for rendering.

> public interface StringConverter {
> String toString(M model, int row, int column);
> }
>
> 6) In general i prefer using interface than
> abstract class, abstract class is a bit more efficient
> but a really much less flexible.
> So RowFilter, StringConverter, RowSorterAdpater
> are interfaces for me.

We have a lot more flexibility in evolving abstract classes than we do in evolving interfaces. By that I mean you can add to an abstract class, for an interface you can only create a new one (as in LayoutManager2). For this reason Swing has gone with abstract classes where others may have gone with interfaces.

> 7) In JList, JTtree and JTable, get/setRowSorter() need
> to be parametrized with the good model,
> i.e. respectively RowSorter,
> RowSorter and RowSorter

I'm not really seeing the necessity of parameterizing this yet. Of course I may be missing something;)

Thanks again for the feedback.

-Scott

forax
Offline
Joined: 2004-10-07
Points: 0

...
> Numerous folks requested the ability to do sorting at
> the database level. Having RowSorter effectively
> empty allows for this.

ok

>
> > 2) Because RowSorter is generic and TableRowSorter
> > specific to TableModel, it's interresting to
> > parametrized RowSorter with the model type
> > (RowSorter;) because it'a avoid lot of cast
> > (see belong)
> > In this case TableRowSorter extends
> > RowSorter.
>
> Yes, it should be possible to parameterize the return
> type, but it turns out it isn't really needed. If
> you look at the code for TableRowSorter you'll see
> that it doesn't directly need this.

ok, TableRowSorter doesn't directly need this
in its implementation.

I think it's a good idea to generify RowFilter
basically because users have to write some filter
and generify RowFilter permit to write filters
without any cast (see below for an example).

If RowFilter is generified, RowSorter need to be
generified too because it returns a RowFilter.
If RowSorter if generified
DefaultRowSorter, DefaultRowSorter.Model and
TableRowSorter need to be generified too.

>
> > 3) DefaultRowSorter.Model is badly name because it
> > could lead to confusion between the model
> > (TableModel) and the adapter
> > (DefaultRowSorter.Model).
> > See methods getModel() and getTableModel() in
> > TableRowSorter.
> > Rename it to RowSorter.Adapter
> > in order to avoid confusion.
>
> We are rapidly running out of non-overloaded names in
> the JDK.

yes, in the whole JDK, but DefaultRowSorter.Model.getModel()
and DefaultRowSorter.getModel() return two different
kinds of model. It's not very easy to understand that
the first time that you read the API.

> From one perspective RowSorter has a model,
> that is called Model. It could be named RowModel,
> but as you'll almost always be referencing it by way
> of RowSorter.XXX that seemed a bit excessive.
>
> When I think of the name Adapter I think of a
> listener subclass, eg MouseAdapter, KeyAdapter ...

yes, when i've proposed Adapter, it was the name of the
design pattern (Gof) not the Adapter use in AWT.
So Adapter is not a good name, Model neither,
why not GridWrapper or something like this.

...

> All a Filter should care about is the available
> column counts and entries in the columns to filter
> by. I don't see why it needs to be tied to
> RowSorter.

yes, forget what i said about that.
RowFilter is the same kind of interface that
a renderer. Why not choose the same way to write it.
Provide to the user the model and the row et let him
call getElementAt() to find the corresponding data.

I have rewrite your second example with this idea
and the code seems more simpler to me.

public class PersonnModel extends AbstractTableModel {
public Personn getElementAt(int row,int column) {
...
}
}
...
RowFilter ageFilter = new RowFilter() {
public boolean include(TableModel model,int row) {
Person person =model.getElementAt(row,0);
return person.getAge() > 20;
}
};

>
> I initially had int getIdentifier();, but I was
> worried that for trees we may want getIdentifier to
> be a TreePath. If I go with row that precludes
> something more meaningful later on.

Perhaps the Entry needs to be different for each
Component Model. Else i don't see how you can send
a TreePath to the filter because only JTree
(in fact TreeUI) knows such information,
not TreeModel and RowSorter only relies on models.

Let the user makes the wire seems more easy to me :
final JTree tree=...
RowFilter filter = new RowFilter() {
public boolean include(TreeModel model,int row) {
TreePath path=tree.getPathForRow(row);
...
}
};

>
> > 5) about TableStringConverter; i not really
> understand
> > why string convertion need to be specific to a
> table.
> > Rename it to StringConverter, parametrized it by M
> and
> > move it into javax.swing package.
>
> TableStringConverter is initially only used by
> TableSorter, but at a later date JTable should take
> one to aid in converting strings for rendering.

yes but why JList or JTree could not be interrested
by the same convertion.

>
> > public interface StringConverter {
> > String toString(M model, int row, int column);
> > }
> >
> > 6) In general i prefer using interface than
> > abstract class, abstract class is a bit more
> efficient
> > but a really much less flexible.
> > So RowFilter, StringConverter, RowSorterAdpater
> > are interfaces for me.
>
> We have a lot more flexibility in evolving abstract
> classes than we do in evolving interfaces. By that I
> mean you can add to an abstract class, for an
> interface you can only create a new one (as in
> LayoutManager2).
> For this reason Swing has gone with
> abstract classes where others may have gone with
> interfaces.

ok

...
>
> Thanks again for the feedback.
>
> -Scott

Thanks too

Rémi

zixle
Offline
Joined: 2004-07-22
Points: 0

Hi Remi,

I must apologize for the delay in responding. Your post came right at
the time of JavaOne and I had three presentations to do:( Sorry about
that. I can't say as I'm less busy now, but hopefully I can be a bit
more repsonsive.

> > > 2) Because RowSorter is generic and TableRowSorter
> > > specific to TableModel, it's interresting to
> > > parametrized RowSorter with the model type
> > > (RowSorter;) because it'a avoid lot of cast
> > > (see belong)
> > > In this case TableRowSorter extends
> > > RowSorter.
> >
> > Yes, it should be possible to parameterize the return
> > type, but it turns out it isn't really needed. If
> > you look at the code for TableRowSorter you'll see
> > that it doesn't directly need this.
>
> ok, TableRowSorter doesn't directly need this
> in its implementation.
>
> I think it's a good idea to generify RowFilter
> basically because users have to write some filter
> and generify RowFilter permit to write filters
> without any cast (see below for an example).
>
> If RowFilter is generified, RowSorter need to be
> generified too because it returns a RowFilter.
> If RowSorter if generified
> DefaultRowSorter, DefaultRowSorter.Model and
> TableRowSorter need to be generified too.

I agree that some sort of generification could be helpful. I'm not
entirely sure I completely understand what you are suggesting though.
If you could supply a set of diffs that would clarify what you are
after.

> > > 3) DefaultRowSorter.Model is badly name because it
> > > could lead to confusion between the model
> > > (TableModel) and the adapter
> > > (DefaultRowSorter.Model).
> > > See methods getModel() and getTableModel() in
> > > TableRowSorter.
> > > Rename it to RowSorter.Adapter
> > > in order to avoid confusion.
> >
> > We are rapidly running out of non-overloaded names in
> > the JDK.
>
> yes, in the whole JDK, but DefaultRowSorter.Model.getModel()
> and DefaultRowSorter.getModel() return two different
> kinds of model. It's not very easy to understand that
> the first time that you read the API.

Yes, this is too.
I like using the name Model, but as you say it is a bit overloaded.
I'll have to think on this.

> > From one perspective RowSorter has a model,
> > that is called Model. It could be named RowModel,
> > but as you'll almost always be referencing it by way
> > of RowSorter.XXX that seemed a bit excessive.
> >
> > When I think of the name Adapter I think of a
> > listener subclass, eg MouseAdapter, KeyAdapter ...
>
> yes, when i've proposed Adapter, it was the name of the
> design pattern (Gof) not the Adapter use in AWT.
> So Adapter is not a good name, Model neither,
> why not GridWrapper or something like this.

Even though overloaded I like ModelAdapter a bit better. I'll run the
name by the doc folks and see if they have another idea.

> > All a Filter should care about is the available
> > column counts and entries in the columns to filter
> > by. I don't see why it needs to be tied to
> > RowSorter.
>
> yes, forget what i said about that.
> RowFilter is the same kind of interface that
> a renderer. Why not choose the same way to write it.
> Provide to the user the model and the row et let him
> call getElementAt() to find the corresponding data.

In hind sight having a distince interface per class is problematic.
It means one has to create specific renderers for tree/list/table when
they should really be the same. I wanted to avoid that with filters
and sorting.

> I have rewrite your second example with this idea
> and the code seems more simpler to me.
>
> public class PersonnModel extends AbstractTableModel {
> public Personn getElementAt(int row,int column) {
> ...
> }
> }
> ...
> RowFilter ageFilter = new RowFilter() {
> public boolean include(TableModel model,int row) {
> Person person =model.getElementAt(row,0);
> return person.getAge() > 20;
> }
> };

It's slightly simpler, but if we go this route you lose the ability to
have the common filters I've created. You would need one per source.

> > I initially had int getIdentifier();, but I was
> > worried that for trees we may want getIdentifier to
> > be a TreePath. If I go with row that precludes
> > something more meaningful later on.
>
> Perhaps the Entry needs to be different for each
> Component Model. Else i don't see how you can send
> a TreePath to the filter because only JTree
> (in fact TreeUI) knows such information,
> not TreeModel and RowSorter only relies on models.

When we add sorting/filtering to tree/list we'll need to change them
to centralize all access to the model so that the access first goes
through the RowSorter. Yes, no simple task. When we do this we'll
then be able to have a DefaultRowSorter subclass for Tree and one for
List. The tree implementation or RowSorter (extending
DefaultRowSorter) could use TreePaths as the identifier. I say could
as I haven't done the work and we'll have to see what makes the most
sense.

> Let the user makes the wire seems more easy to me :
> final JTree tree=...
> RowFilter filter = new RowFilter() {
> public boolean include(TreeModel model,int row) {
> TreePath path=tree.getPathForRow(row);
> ...
> }
> };

A filter for the tree wouldn't be able to call back into the tree as
the indices wouldn't make sense. If we went this route it would have
to be something like:

include(TreeModel,Object parent, int childIndex);

or something.

But again, I really want Filters to be sharable among
tree/list/table.

> > > 5) about TableStringConverter; i not really
> > understand
> > > why string convertion need to be specific to a
> > table.
> > > Rename it to StringConverter, parametrized it by M
> > and
> > > move it into javax.swing package.
> >
> > TableStringConverter is initially only used by
> > TableSorter, but at a later date JTable should take
> > one to aid in converting strings for rendering.
>
> yes but why JList or JTree could not be interrested
> by the same convertion.

List/Tree will be interested in this as well, but the parameters will
need to be different. My last set of comments advocated sharing the
same filter among tree/list/table. Why not the same for String
conversion? String conversion is a developer supplied operation,
which is specific to the model and so it seemed acceptable to have an
interface for each model type.

-Scott