Smart ListModel Updating.

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

Smart ListModel Updating.

Howard Oh
Traditional way to update a ListPresenter in a Shell is to wire events
to know when the modification of items has occuurred. Then find out
indices of items has changed, and send updateAtIndex: to ListModel or
ListPresenter as many times as the items that changed.

I suggest following patchings on ListModel can do all the updating
works seemlessly.

ListModel>>setList: collection searchPolicy: policy
        "Private - Initialize the receiver's identity instance variables.
Answer the receiver."

        list := collection.
        searchPolicy := policy.
        "PATCHING begins"
        list do: [:each| each when: #valueChanged send: #updateItem: to: self
with: each ].
        "PATCHING ends"



ListModel>>list: aSequenceableCollection
        "Set the list of the receiver, i.e. the collection that it represents"

        list == aSequenceableCollection ifFalse: [
                list := aSequenceableCollection.
                "HwaJongOh begins"
                list do: [:each| each when: #valueChanged send: #updateItem: to: self
with: each ].
                "HwaJongOh ends"
                self trigger: #listChanged ]




ListModel>>updateItem: objectInThisList

        self updateAtIndex: (self indexOf: objectInThisList)






After these patches, you can trigger #valueChanged in your model and
watch the smart updating happens in your ListPresenter.

MyObject>>setter: anObject

    field1 := anObject.
    self trigger: #valueChanged



Even simpler example will be,

array := Array with: 1 asValue.
ListPresenter showOn: (ListModel on: array).
array first value: 4

Have a good one


Reply | Threaded
Open this post in threaded view
|

Re: Smart ListModel Updating.

Howard Oh
I missed to post 1 more patching...

addAnsweringIndex: newObject
        "Append newObject as the last element of the receiver.
        Answer the index at which the object was added."

        | index |
        index := self list addAnsweringIndex: newObject.
        self trigger: #item:addedAtIndex: with: newObject with: index.
        "PATCHING begins"
        newObject when: #valueChanged send: #updateItem: to: self with:
newObject.
        "PATCHING ends"
        ^index


Reply | Threaded
Open this post in threaded view
|

Re: Smart ListModel Updating.

Howard Oh
In reply to this post by Howard Oh
I'm experiencing some side effects of the patching.

Process Viewer holds "dead" threads not allowing GC. This problem goes
away by closing the view and reopen it.

There may be more unfound side effects.


Reply | Threaded
Open this post in threaded view
|

Re: Smart ListModel Updating.

Esteban A. Maringolo-3
Howard Oh escribió:
> I'm experiencing some side effects of the patching.
>
> Process Viewer holds "dead" threads not allowing GC. This problem goes
> away by closing the view and reopen it.
>
> There may be more unfound side effects.
>

What if the object changes once removed from the listmodel?, I've
not seen that the listmodel is removed from the event-receivers of
the object in the collection.

Saludos.

--
Esteban.


Reply | Threaded
Open this post in threaded view
|

Re: Smart ListModel Updating.

Chris Uppal-3
In reply to this post by Howard Oh
Howard,

> ListModel>>setList: collection searchPolicy: policy
> "Private - Initialize the receiver's identity instance variables.
> Answer the receiver."
>
> list := collection.
> searchPolicy := policy.
> "PATCHING begins"
> list do: [:each| each when: #valueChanged send: #updateItem: to: self
> with: each ].
> "PATCHING ends"

I think this is a good idea but it would work better as a custom sub-class of
ListModel than as a change to the existing ListModel.  The main reason is that
many (most!) objects don't generate change events themselves, so an application
which used them could not rely on the ListModel seeing the changes
automatically.

Some other thoughts:

You'd also have to override quite a number of other methods, such as #at:put:
#addAnsweringIndex: #removeAtIndex: and so on.

As Esteban mentioned, you'd also want to remove the event triggers when objects
were taken out of the list.

STB would take a bit of thought.  If the ListModel were saved in STB format,
should it re-establish the events when it is re-created ?  I /think/ the answer
is yes, but I'm not sure.  The same question applies to #deepCopy.

    -- chris


Reply | Threaded
Open this post in threaded view
|

Re: Smart ListModel Updating.

Udo Schneider
Chris Uppal wrote:
  > Some other thoughts:
Just to add a thought from my side.

If you create a Subclass of ListModel I would also recommend to make the
triggerSelector pluggable. I have many models which do trigger change
events without using #valueChanged. Especially for complex models which
are more than simple values #valueChanged doesn't seem right.

CU,

Udo


Reply | Threaded
Open this post in threaded view
|

Re: Smart ListModel Updating.

Howard Oh
In reply to this post by Esteban A. Maringolo-3
Yes, indeed.

I've also patching some event unwiring at the removeing methods.

SmartListModel>>removeAll

        "Empty the receiver of all contents."
        self list do: [:each| each removeEventsTriggeredFor: self].
        ^super removeAll"self list: self list copyEmpty"


removeAtIndex: anInteger
        "Remove, and answer, the element of the receiver at the specified
        <integer> index, by shuffling elements which succeed it down one slot.
        Raise an BoundsError if there is no element with that index."

        | elem |
        elem := self list removeAtIndex: anInteger.
        elem removeEventsTriggeredFor: self.
        self trigger: #itemRemovedAtIndex: with: anInteger.
        ^elem

As Process Monitor showing strange behavior, I've decided to subclass
ListModel and move all the method patchings to it. Its name is
SmartListModel.  After this Process Monitor worked correctly.


Have a Good One