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] |
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 > |
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] |
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 |
Free forum by Nabble | Edit this page |