TableView filtering and sorting (was Re: FilteredList/SortedList)
martin.sladecek at oracle.com
Tue Jan 15 02:13:36 PST 2013
OK, seems like we all dug our trenches and this is not going to move
Means it's time for some summary. :-)
As I see it, we have 2 very similar solutions (let's call them W(rapper)
and M(odel)-V(iew)) with the following aspects:
* Both have 2 different "modes", with mutable/immutable model. Mutable
model is used by default and will be always used when executing an old
code. Immutable model is triggered by using a wrapper (W) or using
setModel() method on the control (M-V).
* In both cases, using immutable model require extra work and extra
caution in order to have the indexes right.
* M-V require additional methods for all affected controls, while W
needs a new class or a defender method on ObservableList.
* M-V handles sort internally in the control, while with W, an external
object is modified by the control.
I also thing we didn't explore details on Richard's solution much. I
have some questions about how the implementation would look like:
* The WrapperList will be something tightly associated with our controls
or some general-purpose wrapper? In case of the latter, what will be
it's functionality then? A special wrapper that can be sorted by
FXCollections.sort() while leaving the wrapped list untouched? Or maybe
it will be a special class that also allows direct sort calls?
(Note that it must be something like FXCollections.sort() as there is no
sorting method on List and Collections.sort() uses clear() + add()).
* How will the developer know that the WrapperList is the list to be used?
* What about TableView's encapsulation? What if something else tries to
use the same WrapperList that is used by the TableView?
On 01/15/2013 04:11 AM, Richard Bair wrote:
> On Jan 14, 2013, at 5:34 AM, Martin Sladecek <martin.sladecek at oracle.com> wrote:
>> On 01/10/2013 06:00 PM, Richard Bair wrote:
>>>> This doesn't have to break. All existing APIs are View-based. The current API for setting the items in the table is assumed to be setting the View, since when sorting it is updated in place.
>>>> There currently isn't any API for setting a model independent of the view, so one could be added. As long as the list added via the new method is not modified in place and the existing APIs set and return the items in "view" order.. all is well.
>>>> We need about four new APIs.
>>>> void setModel(ObservableList)
>>>> ObservableList getModel()
>>>> int getModelIndex(int viewIndex)
>>>> int getViewIndex(int modelIndex)
>>>> Sorting happens internally on the "Items" list, not the "Model" list.
>>>> If you call setModel(), a view list ("Items") is created for you and anything you may have set it to previously is toast.
>>>> If you call setItems(), indicating you wish to use the old API, the model could be forced to null, or a copy of the view list could be made in it's place. But you have two APIs that are overlapping slightly. That's just what you have to live with.
>>>> Any existing APIs continue to work based on view coordinates.
>>> So, the obvious issues:
>>> - As you mentioned the APIs overlap slightly. Or even if they don't the names are ambiguous so there is some sadness that would just have to be lived with
>>> - Because "items" is mutable, we actually have all the same problems Martin is trying to avoid. For example, if the list has been sorted, and you insert an item at a specific location in the items list, then what happens? Once the TableView supports UI for filtering, and you insert and item into items, then what happens?
>> The items would be mutable only when set directly using the setItems() methods. It would be user's responsibility to handle that correctly, if he provided a mutable list as "items".
>> Otherwise, the items would be created immutable for the provided model.
> That would break current users who can:
>> It's the same with your approach. We have either mutable list as items (set directly) or an immutable one (wrapper). There will be some ambiguity in the API and different approach will have to be used when model is set directly, or in your case, when a wrapper is used.
>> E.g. if we want to scroll to a specific element (which is, as you called it, a model based method).
>> When view == model, which in both cases means setItems was called with our list, then you can use scrollTo directly with the index from our list.
> Really I want a mutable ObservableList for filtering. That was the original intent :-(. Or do you mean we have to deal with unmodifiable lists in either case?
>> In case we do not wish TableView to modify our model, we need to treat "model-based" API differently. In case of what Scott proposed, it would be like this (say we have some the index stored in listIndex property):
>> ...in case of your API:
>> WrapperList wrapper = new WrapperList(list);
>> I'm afraid we have no other option if we do not wish to deprecate the items property.
> Right, in my case where there is only "items", the items are always view based and if you want to map you use an API on the list vs on the control. But none of the mapping concepts are on any control, just relegated to the list.
More information about the openjfx-dev