Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » JFace » ObservableCollectionTreeContentProvider duplicate TreeNode creation
ObservableCollectionTreeContentProvider duplicate TreeNode creation [message #20562] Mon, 13 July 2009 19:59 Go to next message
Will Horn is currently offline Will HornFriend
Messages: 265
Registered: July 2009
Senior Member
ObservableCollectionTreeContentProvider has logic to prevent creating a
duplicate TreeNode. However, this relies on the hash code of the input,
which in a list's case is dependent on the list contents.

The test case below will cause 2 TreeNodes to be created (one during
setInput and one during the manual getElements call). On shell close, the
content provider will throw
"org.eclipse.core.runtime.AssertionFailedException: assertion failed: Getter
called on disposed observable
org.eclipse.core.databinding.observable.list.WritableList@148cc8c" when
disposing the second TreeNode.

At least in my case, the error happens because I call "getElements" on the
content provider directly. If this is not allowed, it needs to be
documented. Otherwise, maybe an IdentityHashMap should be used.

Thanks,
Will

final Display d = new Display();
Realm.runWithDefault(SWTObservables.getRealm(d), new Runnable() {
public void run() {
Shell s = new Shell(d);
TreeViewer v = new TreeViewer(s);
ObservableListTreeContentProvider cp = new
ObservableListTreeContentProvider(
new IObservableFactory() {
@Override
public IObservable createObservable(Object target) {
if (target instanceof IObservableList) {
return (IObservableList) target;
}
return null;
}
}, new TreeStructureAdvisor() {
});
v.setContentProvider(cp);
WritableList input = WritableList.withElementType(String.class);
v.setInput(input);
input.add("ABC");
cp.getElements(input);
s.close();
}
});
Re: ObservableCollectionTreeContentProvider duplicate TreeNode creation [message #20573 is a reply to message #20562] Mon, 13 July 2009 20:09 Go to previous messageGo to next message
Matthew Hall is currently offline Matthew HallFriend
Messages: 368
Registered: July 2009
Senior Member
Will Horn wrote:
> If this is not allowed, it needs to be
> documented. Otherwise, maybe an IdentityHashMap should be used.

You need to set an IElementComparer on the viewer before binding it.
Your ObservableListTreeContentProvider will honor that element comparer.
My code usually looks like this:

TreeViewer viewer = ...
viewer.setComparer(new IElementComparer() {
public void equals(Object a, Object b) {
return a==b;
}
public void hashCode(Object a) {
return System.identityHashCode(a);
}
} );
viewer.setUseHashLookup(true);

// bind viewer now.

--Matthew
Re: ObservableCollectionTreeContentProvider duplicate TreeNode creation [message #20590 is a reply to message #20573] Mon, 13 July 2009 21:31 Go to previous messageGo to next message
Will Horn is currently offline Will HornFriend
Messages: 265
Registered: July 2009
Senior Member
"Matthew Hall" <matthall@woodcraftmill.com> wrote in message
news:h3g4af$j32$1@build.eclipse.org...
> You need to set an IElementComparer on the viewer before binding it. Your
> ObservableListTreeContentProvider will honor that element comparer.
Okay, thanks for the tip. Is that documented anywhere?

In my recent investigation/usage of ObservableListTreeContentProvider, I
have come across some other caveats which I have not seen documented:

1) Constructor must be called on the realm of the current display (maybe
this goes without saying, but wouldn't hurt to document since most of the
databinding code is very good about documenting such restrictions).
2) If the input is an IObservableList and you use it as the "children" of
itself, it will be disposed with the viewer or on input change. For example,
if you use an IObservableFactory like I did in my test case:

new IObservableFactory() {
@Override
public IObservable createObservable(Object target) {
if (target instanceof IObservableList) {
return (IObservableList) target;
}
return null;
}
}

Is there a best practice or workaround for this one?
Re: ObservableCollectionTreeContentProvider duplicate TreeNode creation [message #20599 is a reply to message #20590] Mon, 13 July 2009 21:40 Go to previous messageGo to next message
Matthew Hall is currently offline Matthew HallFriend
Messages: 368
Registered: July 2009
Senior Member
Will Horn wrote:
> "Matthew Hall" <matthall@woodcraftmill.com> wrote in message
> news:h3g4af$j32$1@build.eclipse.org...
>> You need to set an IElementComparer on the viewer before binding it.
>> Your ObservableListTreeContentProvider will honor that element comparer.
> Okay, thanks for the tip. Is that documented anywhere?

I think this is documented in StructuredViewer.

> In my recent investigation/usage of ObservableListTreeContentProvider, I
> have come across some other caveats which I have not seen documented:
>
> 1) Constructor must be called on the realm of the current display (maybe
> this goes without saying, but wouldn't hurt to document since most of
> the databinding code is very good about documenting such restrictions).

This should be documented. Would you open a bug for this?

> 2) If the input is an IObservableList and you use it as the "children"
> of itself, it will be disposed with the viewer or on input change.
>
> Is there a best practice or workaround for this one?

The tree content providers are expected to clean up after themselves.
This is why they dispose all the observables they create through the
IObservableFactory.

My suggestion is to wrap the input observable in
Observables.unmodifiableObservableList.

Matthew
Re: ObservableCollectionTreeContentProvider duplicate TreeNode creation [message #20607 is a reply to message #20599] Tue, 14 July 2009 00:38 Go to previous message
Will Horn is currently offline Will HornFriend
Messages: 265
Registered: July 2009
Senior Member
"Matthew Hall" <matthall@woodcraftmill.com> wrote in message
news:h3g9kq$2a1$1@build.eclipse.org...
> Will Horn wrote:
>> "Matthew Hall" <matthall@woodcraftmill.com> wrote in message
>> news:h3g4af$j32$1@build.eclipse.org...
>>> You need to set an IElementComparer on the viewer before binding it.
>>> Your ObservableListTreeContentProvider will honor that element comparer.
>> Okay, thanks for the tip. Is that documented anywhere?
>
> I think this is documented in StructuredViewer.
This seems like a "gotcha" worth documenting in
ObservableListTreeContentProvider. From the StructuredViewer perspective,
the comparer seems to be an advanced feature used with setUseHashLookup
optimization. But when using ObservableListTreeContentProvider, it is a
requirement. Or am I mistaken?

>> In my recent investigation/usage of ObservableListTreeContentProvider, I
>> have come across some other caveats which I have not seen documented:
>>
>> 1) Constructor must be called on the realm of the current display (maybe
>> this goes without saying, but wouldn't hurt to document since most of the
>> databinding code is very good about documenting such restrictions).
>
> This should be documented. Would you open a bug for this?
http://bugs.eclipse.org/283351

>> 2) If the input is an IObservableList and you use it as the "children" of
>> itself, it will be disposed with the viewer or on input change.
>
> The tree content providers are expected to clean up after themselves. This
> is why they dispose all the observables they create through the
> IObservableFactory.
This makes sense.

While I'm at it: caveat number 3
3) The input to the viewer, if an observable, must be on the realm of the
current display. I've tried to get around this, but even I create a proxy
observable in IObservableFactory and use an identity element comparere,
errors still occur since the viewer calls equals directly on the input in
AbstractTreeViewer#internalIsInputOrEmptyPath. It's just a good idea to use
the display realm :o)
Previous Topic:ChangeManager#getRealm thread safety concern
Next Topic:[TableViewer] How to make selection visible when Editingsupport is set?
Goto Forum:
  


Current Time: Thu Apr 25 12:01:25 GMT 2024

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

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

Back to the top