List models

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

List models

Schwab,Wilhelm K
Hello all,

I am working on some code that's been in use for a while, so some of the
design reflects things I didn't know about MVP (or in some cases works
around quirks of same that have long since been fixed).  In short, some
of it is pretty ugly.

There are several places in which it would be nice to be able to attach
  multiple list models to one collection, with each of them displaying
only items that meet a particular filter condition.  While we're at it,
it would be nice to be able to optionally sort the displayed items w/o
affecting the underlying collection.  As it is, I do a lot of selecting
and populating followed by integrating the results of changes into the
source collection(s).

Any thoughts on a better way?  Better still, am I missing something that
would let me do this kind of thing with current list models?  There is a
FilteredListModel in the archives, but it appears to do (pretty much)
what I do now, only with some formalization.

One challenge would be to make sense of #add:afterIndex:.  It might need
to translate the index to the unfiltered collection and make the
addition there, and then trigger events only if the element meets the
receiver's filter condition.  It probably gets worse than that.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: List models, I second

Günther Schmidt
Bill Schwab schrieb:

> Hello all,
>
> I am working on some code that's been in use for a while, so some of the
> design reflects things I didn't know about MVP (or in some cases works
> around quirks of same that have long since been fixed).  In short, some
> of it is pretty ugly.
>
> There are several places in which it would be nice to be able to attach
>  multiple list models to one collection, with each of them displaying
> only items that meet a particular filter condition.  While we're at it,
> it would be nice to be able to optionally sort the displayed items w/o
> affecting the underlying collection.

I second that. Even to a newbie such as me this doesn't seem right,
manipulating the model for the sake of presentation.

Guenther

Would it work if ListModel would pass a copy of the List?
When asked for ListModel>>list

  As it is, I do a lot of selecting

> and populating followed by integrating the results of changes into the
> source collection(s).
>
> Any thoughts on a better way?  Better still, am I missing something that
> would let me do this kind of thing with current list models?  There is a
> FilteredListModel in the archives, but it appears to do (pretty much)
> what I do now, only with some formalization.
>
> One challenge would be to make sense of #add:afterIndex:.  It might need
> to translate the index to the unfiltered collection and make the
> addition there, and then trigger events only if the element meets the
> receiver's filter condition.  It probably gets worse than that.
>
> Have a good one,
>
> Bill
>


Reply | Threaded
Open this post in threaded view
|

Re: List models, I second

Schwab,Wilhelm K
Günther,

> I second that. Even to a newbie such as me this doesn't seem right,
> manipulating the model for the sake of presentation.

It might be ideal under some circumstances.  It depends on the
performance implications of avoiding such changes to the model, and
whether or not manipulating the model is a problem.


> Would it work if ListModel would pass a copy of the List?
> When asked for ListModel>>list

Maybe we should write some tests and see =:0

A start at it might be as below.  Note that it will not even get past
creating the list models, but it's a (very small) start.  I suspect that
we would do well to create a new type of list model rather than change
the existing one.  If the result is fast and reliable, then OA can
change ListModel, or not, at their discretion.

Have a good one,

Bill


testList

                | smalltalkers r others |

        smalltalkers := OrderedCollection new
                add:'Goldberg';
                add:'Robson';
                add:'Raab';
                add:'Kay';
                add:'Ingalls';
                yourself. "Pun intended"

        r := ListModel on:smalltalkers filter:[ :each | each beginsWith:'R' ].
        others := ListModel on:smalltalkers filter:[ :each | ( each
beginsWith:'R' ) not. ].

        self
                should:[ r add:'McGlashan'. ]
                trigger:#itemAdded:atIndex:
                against:others.

        self
                should:[ others add:'Bower'. ]
                trigger:#itemAdded:atIndex:
                against:others.

        #( 'McGlashan' 'Bower' ) do:[ :each |
                self should:[
                        others includes:each.
                ].
                self should:[
                        smalltalkers include:each.
                ].
                self shouldnt:[
                        r includes:each.
                ].
        ].



--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: List models

Chris Uppal-3
In reply to this post by Schwab,Wilhelm K
Bill Schwab wrote:

> There are several places in which it would be nice to be able to attach
>   multiple list models to one collection, with each of them displaying
> only items that meet a particular filter condition.  While we're at it,
> it would be nice to be able to optionally sort the displayed items w/o
> affecting the underlying collection.  As it is, I do a lot of selecting
> and populating followed by integrating the results of changes into the
> source collection(s).
>
> Any thoughts on a better way?

I'd say that if the underlying list does not change, then the easiest thing is
just to use a shallow copy for the derived lists.  (Or take a copy via #select:
if you want to apply a non-trivial filter).

If, on the other hand, the underling list does change, and you want the changes
to be reflected in the derived lists, then you either have to create a new kind
of list, a new kind of ListModel, or hand-code it all in each application.  Up
until today ;-) I have been doing the latter, and -- like you -- have become
tired of it.

Here's a quick sketch of the design.  Basically it's a generalisation of Dmitry
Zamotkin's FiltereredListModel, along the lines I had suggested way back in the
thread where he posted that code.

A DerivedListModel takes another ListModel as its subject, and hooks up with
that list model's change notifications.  It builds a derived OrderedCollection
by applying its #filterBlock and #sortBlock to the underlying data, so changing
the sort order of a derived list does not affect the base list.  Changes to the
underlying list cause changes to the derived list, which in turn causes further
change notifications.  Wherever feasible, changes applied to the derived lists'
contents are passed through to the underlying list.

The idea is that the real "model" code can use an ordinary ListModel (which is
never used in an MVP tiad), and then the UI can attach one or more
DerivedListModel's to it for displaying sorted and/or filtered representations
of the same data.  The real model code will change the ListModel as it likes,
and the changes will be reflected through to the UI, but changes to the
sorting/filtering in the UI are invisible to the real model.

Some problems:

As you say,  applying #add:afterIndex: to a derived list is problematical.
What I chose was to:
    a) forbid that operation if the derived list is sorted (just as a ListModel
        forbids it).
    b) add the item at the proposed spot in the derived list.
    c) just #add: the item to the underlying list (which, after all, might be
        sorted itself).
Similarly for #at:put:, i.e. try to respect the index in the derived list,
but just #remove: the old element from the base list and #add: the new one.

Handling item changed notification is trickier since the derived list doesn't
know what element has just vanished from the base list.  After messing about
fruitlessly for a while I gave up and just rebuild the entire derived list when
that happens.  There doesn't seem to be any cheaper solution, and at least it's
simple...

A nuisance is that ListPresenter likes to think that it can re-order the list
by using #list: on its model, which (for compatibility with /loads/ of code) I
interpret as setting a new underlying list.  It seemed that the best bet was to
create a trivial new DerivedListPresenter class that doesn't try to implement
its own sorting, but delegates all sorting and filtering to its model (a
DerivedListModel).

I made it a subclass of ListModel, but in the end I've overridden at least half
of the ListModel implementation.  Maybe it would be better (or less fragile) as
a standalone class.

Anyway, it'll end up on my website in due course (once it's had a bit longer to
dry, and assuming no horrors emerge), but if anyone'd like a beta copy, then
please say so or drop me a line.

    -- chris