TableView filtering and sorting (was Re: FilteredList/SortedList)

Richard Bair richard.bair at oracle.com
Tue Jan 15 10:18:10 PST 2013


>> 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:

filteredList.add(10, item);
assert item == filteredList.get(10);

int size = filteredList.size();
filteredList.add(item);
assert size + 1 == filteredList.size();

sortedList.add(10, item);
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?

Richard


More information about the openjfx-dev mailing list