Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » JFace » Issues with ObservableListTreeContentProvider
Issues with ObservableListTreeContentProvider [message #910791] Mon, 10 September 2012 11:56 Go to next message
Dirk Fauth is currently offline Dirk Fauth
Messages: 1289
Registered: July 2012
Senior Member
Hi,

I'm trying to create a composite with a TreeViewer on the left showing available items, a TreeViewer on the right showing the selected items and buttons to add/remove items from one TreeViewer to the other. Some kind of generic chooser composite.

I want to use databinding as it already worked great with simple TableViewers. But there are several issues I can't help myself. And I tried a lot with several workarounds.

I'm using ObservableListTreeContentProvider as described by Tom Schindl here: http://tomsondev.bestsolution.at/2009/06/08/galileo-emf-databinding-%E2%80%93-part-3/

But in fact I don't use EMF.

My IObservableFactory looks like this:
public IObservable createObservable(Object target) {
	if (target instanceof IObservableList) {
		return (IObservable)target;
	}
	else if (target instanceof Family) {
		return PojoProperties.list(Family.class, "members", FamilyMember.class).observe(target);
	}
	else if (target instanceof FamilyMember) {
		return PojoProperties.list(FamilyMember.class, "food", Food.class).observe(target);
	}
	return null;
}


hashCode() and equals() are implemented in the model, taking unique attributes into account, not the parent-child-relationship.

Some things I noticed:
- Adding items to the underlying list and calling refresh() on the TreeViewer causes an AssertionFailedException as described here http://www.eclipse.org/forums/index.php/t/367951/ -> calling refresh(Object element) doesn't cause this
- It seems to be not possible to get the IObservableCollection created by the IObservableFactory for the children lists. So it seems to be not possible to update the children directly via IObservableCollection as I'm not able to get the reference to the created one.

The second point is really frustrating, but maybe I'm simply doing things wrong.

What I've found out is:
- ObservableCollectionTreeContentProvider defines a protected TreeNode that holds the reference to the IObservableCollection of children.
- An IObservablesListener is added to the IObservableCollection which reacts on adding/removing items from the list.
- The ListChangeListener implemented in private static inner class ObservableListTreeContentProvider.Impl seems to refresh the cached values
- This ListChangeListener never seems to be called (at least in my scenarios)

I created a workaround by updating my model manually (as I don't get the IObservableCollection itself) and then update the TreeViewer. But this is not the wanted solution as I want to use databinding. And even this brings up a strange issue.
When I have a tree with 3 levels, removing and re-adding a third-level-item (which will re-create the first two levels as it should be for this kind of chooser composite), only the first two levels are shown correctly in TreeViewer. And this is because of the cached values that are not updated.

I'm really stuck here and not sure if this is a bug or if I'm doing something really wrong. If there is someone out there willing to help, I would send the current version of the composite and the example by mail. In fact I'm also thinking about contributing to Nebula when it is finished.

Any help will be appreciated.

Greez,
Dirk
Re: Issues with ObservableListTreeContentProvider [message #910819 is a reply to message #910791] Mon, 10 September 2012 12:41 Go to previous messageGo to next message
Marco Maccaferri is currently offline Marco Maccaferri
Messages: 132
Registered: July 2009
Senior Member
On 10/09/2012 13:56 Dirk Fauth ha scritto:

> Some things I noticed: - Adding items to the underlying list and
> calling refresh() on the TreeViewer causes an
> AssertionFailedException as described here
> http://www.eclipse.org/forums/index.php/t/367951/ -> calling
> refresh(Object element) doesn't cause this

I had this problem once, the cause, if I remember correctly, was the
observable factory, the createObservable should return an object that
can be safely disposed at any time, in other words always return a new
object from that method (specifically, the first instanceof). You can
use Observables.unmodifiableObservableList for that.

> - It seems to be not
> possible to get the IObservableCollection created by the
> IObservableFactory for the children lists. So it seems to be not
> possible to update the children directly via IObservableCollection as
> I'm not able to get the reference to the created one.

That's right because your model should provide the necessary methods and
implementations to notify listeners of changes. I see you are using
PojoProperties.list, as far as I can tell it doesn't notify changes to
the underlying list, use a WritebleList instead so you can add items to
the model and fire notifications to the listeners.

> I created a workaround by updating my model manually (as I don't get
> the IObservableCollection itself) and then update the TreeViewer. But
> this is not the wanted solution as I want to use databinding.

Well, that is how it should work. You should never update the viewer
directly, your model should notify its listeners about changes. You can
use databinding in the model without problems.

> And
> even this brings up a strange issue. When I have a tree with 3
> levels, removing and re-adding a third-level-item (which will
> re-create the first two levels as it should be for this kind of
> chooser composite), only the first two levels are shown correctly in
> TreeViewer. And this is because of the cached values that are not
> updated.

I'm not sure to understand but looks to be an effect of the previous
issues. It may also have something to do with the hashCode and equals,
it is better to not override these methods since the viewer relies on
them to identify the viewer elements and if they change (due to some
property that is used to calculate the hash) the viewer may get confused
and produce unpredictable results.


Hope this helps.

Regards,
Marco.
Re: Issues with ObservableListTreeContentProvider [message #910882 is a reply to message #910819] Mon, 10 September 2012 15:00 Go to previous messageGo to next message
Dirk Fauth is currently offline Dirk Fauth
Messages: 1289
Registered: July 2012
Senior Member
Hi,

thanks for your hints. They helped me to get it for some parts. Although I'm not 100% with you. Smile

You are completely right on saying the issue is related to the observable factory. I used the same factory instance for two viewers. This caused the strange behaviour I described last. And by using different instances for the two viewers, hashCode() and equals() work fine. And they are supposed to. Of course the unique identifiers in the model are not allowed to be modified. Wink

Always returning new instances and/or Observables.unmodifiableObservableList breaks everything. How to add/remove from unmodifiable lists? I solved this by remembering my instances within an abstract factory, checking the disposal state before accessing. This way it works fine now. (Despite some smaller parts that are related to older code that needs to be thrown away now)

Thanks again,
Dirk


Marco Maccaferri wrote on Mon, 10 September 2012 14:41
On 10/09/2012 13:56 Dirk Fauth ha scritto:

> Some things I noticed: - Adding items to the underlying list and
> calling refresh() on the TreeViewer causes an
> AssertionFailedException as described here
> http://www.eclipse.org/forums/index.php/t/367951/ -> calling
> refresh(Object element) doesn't cause this

I had this problem once, the cause, if I remember correctly, was the
observable factory, the createObservable should return an object that
can be safely disposed at any time, in other words always return a new
object from that method (specifically, the first instanceof). You can
use Observables.unmodifiableObservableList for that.


> - It seems to be not
> possible to get the IObservableCollection created by the
> IObservableFactory for the children lists. So it seems to be not
> possible to update the children directly via IObservableCollection as
> I'm not able to get the reference to the created one.

That's right because your model should provide the necessary methods and
implementations to notify listeners of changes. I see you are using
PojoProperties.list, as far as I can tell it doesn't notify changes to
the underlying list, use a WritebleList instead so you can add items to
the model and fire notifications to the listeners.

> I created a workaround by updating my model manually (as I don't get
> the IObservableCollection itself) and then update the TreeViewer. But
> this is not the wanted solution as I want to use databinding.

Well, that is how it should work. You should never update the viewer
directly, your model should notify its listeners about changes. You can
use databinding in the model without problems.

> And
> even this brings up a strange issue. When I have a tree with 3
> levels, removing and re-adding a third-level-item (which will
> re-create the first two levels as it should be for this kind of
> chooser composite), only the first two levels are shown correctly in
> TreeViewer. And this is because of the cached values that are not
> updated.

I'm not sure to understand but looks to be an effect of the previous
issues. It may also have something to do with the hashCode and equals,
it is better to not override these methods since the viewer relies on
them to identify the viewer elements and if they change (due to some
property that is used to calculate the hash) the viewer may get confused
and produce unpredictable results.


Hope this helps.

Regards,
Marco.

Re: Issues with ObservableListTreeContentProvider [message #910915 is a reply to message #910882] Mon, 10 September 2012 16:05 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas Schindl
Messages: 5330
Registered: July 2009
Senior Member
I have to admit that I didn't read through the whole thread. If the
following is completely off-topic then just ignore it.

Well ont of the underlying real problem with using plain Java is that
java.util.List does not notify about changes hence addition/removal can
not be tracked automatically by Eclipse-Databinding.

Once javafx is completely merged into JDK/JRE (maybe already with u10)
there are List implementations in Java (in the javafx-namespace) who
notify about changes.

Tom

Am 10.09.12 17:00, schrieb Dirk Fauth:
> Hi,
>
> thanks for your hints. They helped me to get it for some parts. Although
> I'm not 100% with you. :)
>
> You are completely right on saying the issue is related to the
> observable factory. I used the same factory instance for two viewers.
> This caused the strange behaviour I described last. And by using
> different instances for the two viewers, hashCode() and equals() work
> fine. And they are supposed to. Of course the unique identifiers in the
> model are not allowed to be modified. ;)
>
> Always returning new instances and/or
> Observables.unmodifiableObservableList breaks everything. How to
> add/remove from unmodifiable lists? I solved this by remembering my
> instances within an abstract factory, checking the disposal state before
> accessing. This way it works fine now. (Despite some smaller parts that
> are related to older code that needs to be thrown away now)
>
> Thanks again,
> Dirk
>
>
> Marco Maccaferri wrote on Mon, 10 September 2012 14:41
>> On 10/09/2012 13:56 Dirk Fauth ha scritto:
>>
>> > Some things I noticed: - Adding items to the underlying list and
>> > calling refresh() on the TreeViewer causes an
>> > AssertionFailedException as described here
>> > http://www.eclipse.org/forums/index.php/t/367951/ -> calling
>> > refresh(Object element) doesn't cause this
>>
>> I had this problem once, the cause, if I remember correctly, was the
>> observable factory, the createObservable should return an object that
>> can be safely disposed at any time, in other words always return a new
>> object from that method (specifically, the first instanceof). You can
>> use Observables.unmodifiableObservableList for that.
>>
>>
>> > - It seems to be not
>> > possible to get the IObservableCollection created by the
>> > IObservableFactory for the children lists. So it seems to be not
>> > possible to update the children directly via IObservableCollection as
>> > I'm not able to get the reference to the created one.
>>
>> That's right because your model should provide the necessary methods
>> and implementations to notify listeners of changes. I see you are
>> using PojoProperties.list, as far as I can tell it doesn't notify
>> changes to the underlying list, use a WritebleList instead so you can
>> add items to the model and fire notifications to the listeners.
>>
>> > I created a workaround by updating my model manually (as I don't get
>> > the IObservableCollection itself) and then update the TreeViewer. But
>> > this is not the wanted solution as I want to use databinding.
>>
>> Well, that is how it should work. You should never update the viewer
>> directly, your model should notify its listeners about changes. You
>> can use databinding in the model without problems.
>>
>> > And
>> > even this brings up a strange issue. When I have a tree with 3
>> > levels, removing and re-adding a third-level-item (which will
>> > re-create the first two levels as it should be for this kind of
>> > chooser composite), only the first two levels are shown correctly in
>> > TreeViewer. And this is because of the cached values that are not
>> > updated.
>>
>> I'm not sure to understand but looks to be an effect of the previous
>> issues. It may also have something to do with the hashCode and equals,
>> it is better to not override these methods since the viewer relies on
>> them to identify the viewer elements and if they change (due to some
>> property that is used to calculate the hash) the viewer may get
>> confused and produce unpredictable results.
>>
>>
>> Hope this helps.
>>
>> Regards,
>> Marco.
>
>
Re: Issues with ObservableListTreeContentProvider [message #911264 is a reply to message #910882] Tue, 11 September 2012 09:05 Go to previous messageGo to next message
Marco Maccaferri is currently offline Marco Maccaferri
Messages: 132
Registered: July 2009
Senior Member
On 10/09/2012 17:00 Dirk Fauth ha scritto:

> Always returning new instances and/or
> Observables.unmodifiableObservableList breaks everything. How to
> add/remove from unmodifiable lists? I solved this by remembering my
> instances within an abstract factory, checking the disposal state
> before accessing. This way it works fine now. (Despite some smaller
> parts that are related to older code that needs to be thrown away
> now)

You don't have to add/remove things from unmodifiable lists, and you
don't need to remember the observables created from the factory. Just
replace your List on the model with WritableList, then the factory can
safely return unmodifiable instances of that list, and the model
notifies changes through its writable list.

The only drawback is that you loose generics. Easy workaround is to add
helper methods to the model and never use the list directly.

Regards,
Marco.
Re: Issues with ObservableListTreeContentProvider [message #911694 is a reply to message #911264] Wed, 12 September 2012 06:28 Go to previous message
Dirk Fauth is currently offline Dirk Fauth
Messages: 1289
Registered: July 2012
Senior Member
Well the lists are coming out of a project that has no dependency to JFace and it shouldn't have them. So my thoughts were that using the IObservableFactory, those lists are wrapped into WritableLists in the background, so I don't have to modify my model to use WritableLists. And with my knowing about patterns, this should be the intention of the IObservableFactory as the adapter pattern is realized with it. Please correct me if I'm seeing things wrong.
Previous Topic:TreeViewer refresh() collapse problem-- SWT
Next Topic:Checkbox in a TreeViewer column - How?
Goto Forum:
  


Current Time: Sat Sep 20 12:22:09 GMT 2014

Powered by FUDForum. Page generated in 0.01952 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software