TableView filtering and sorting (was Re: FilteredList/SortedList)
alspaughb at gmail.com
Thu Jan 17 12:09:08 PST 2013
As a latecomer to this discussion and a Glazed Lists user, I really
appreciate Richard Bair's summary. This is getting to be a long thread,
and I'm still working through it.
My initial reaction is that the underlying problem is that adding
sorting capability to TableView overloads it with too many concerns and
violates the single responsibility principle. Now you are having to
deal with the resulting complications and pathologies. What's next?
Building database persistence into TableView?
Werner Lehmann writes: "Generally speaking, it would be nice to be able
to set the sorting arrows on columns manually, without getting automatic
+1 All we really need to be able to do is to set the arrows manually,
and register for a callback when the user clicks in the column headers.
As developers, we should be able to decide how we want to handle that
callback. If we decide to sort the list, the TableView will see that
the list has changed and redraw itself accordingly.
Perhaps you could move the sorting functionality you have now into a
default handler that responds to mouse clicks in the header by changing
the arrows and sorting the list. But that default can be replaced by
the developer. Then there would no longer be a need to make a
distinction inside TableView between view and model indexes.
From: Richard Bair <richard.bair at oracle.com>
To: Martin Sladecek <martin.sladecek at oracle.com>
Cc: openjfx-dev at openjdk.java.net <openjfx-dev at openjdk.java.net>
Subject: Re: TableView filtering and sorting (was Re:
Date: Tue, 15 Jan 2013 10:18:10 -0800
>> I also thing we didn't explore details on Richard's solution much. I have some questions about how the implementation would look like:
Let me start by describing some of what we were thinking way back when we decided to sort the items list directly and not maintain a mapping in the control itself. There are a number of issues involved here.
1) In Swing, GlazedLists was quite popular and was based on the idea of decorating (or wrapping) lists within lists.
2) In Swing, TableModel etc. contained both view & model data (which sometimes led to oddities such as column information in both the TableModel and the TableColumnModel which would conflict at times)
3) In Swing, retrofitting with built in sorting / filtering as problematic due to the number of "index" APIs that had to be either view or model based
4) The popular thing in 2005 was to say that Swing should have just used beans & collections as its model, and a number of projects had APIs to do this by providing custom table models, list models, etc.
5) Sometimes you want a sort or filter to happen clear on the back-end (in the database for example) rather than on the control
Our thinking was that by separating the sorting / filtering out into the ObservableList, we provide a much nicer solution to each of these design points.
1) GlazedLists was popular in Swing, so adopting a similar API design would be popular in FX. Right? :-)
2) By not having TableModel we don't have some view state in the model.
3) All indexes have intuitive meaning -- they map exactly to the indexes in the items list
4) By just having any old ObservableList as the data items, people are free to give us anything they want (even things that are not naturally a list but implement the ObservableList interface. For example, a RowSet or some other JDBC class could be wrapped by something implementing ObservableList). The design scales from the simplest samples to the most complex. And we didn't have to invent a new interface to achieve it.
5) Because we sort the supplied ObservableList directly, and because you can create an ObservableList implementation that wraps, say, a ResultSet or RowSet, you could get notification of a sort and perform it directly on the backend database. In this case some dev-level coordination will probably be needed (specify both the RowSetObservableList on the TableView and the comparators on the TableView columns such that when a sort happens you can determine which comparators are involved and construct the appropriate SQL query). This would require some additional API beyond just ObservableList (such as the FilteredList and SortedList we had almost shipped previously), such that the TableView can pass the comparators / predicates along.
The sticking point seemed to be around how to handle add / remove on a FilteredList and SortedList. Specifically, the following are not always true:
assert item == filteredList.get(10);
int size = filteredList.size();
assert size + 1 == filteredList.size();
assert item == sortedList.get(10);
And other such related tests. IMO this doesn't matter unless you are using a FilteredList as a general purpose list and passing it to general purpose APIs and expecting it to behave in a standard way. But if there is one thing that is true about the Java collection APIs, it is that they are tailored to be practical rather than theoretical or elegant. And I think having a FilteredList or SortedList that is true to the spirit but not the letter of the List API is very practical, though maybe not as a general purpose construct. Maybe it is only really applicable to the UI world. Of course, we could just throw UnsupportedOperationException on add / remove, and instead have alternative methods that need to be called on these classes, and special case the FXCollections.sort so that it calls the right methods instead of add / remove, and that would seem to solve the issue?
More information about the openjfx-dev