Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 224955

Summary: [Viewers] TreeViewer calls getElements() instead of getChildren() when inputElement==rootElement
Product: [Eclipse Project] Platform Reporter: sarah.ettritch
Component: UIAssignee: Platform-UI-Inbox <Platform-UI-Inbox>
Status: RESOLVED DUPLICATE QA Contact:
Severity: normal    
Priority: P3 CC: emoffatt, qualidafial, tom.schindl
Version: 3.3.2   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description sarah.ettritch CLA 2008-03-31 13:43:55 EDT
Posted to eclipse.platform.swt:

I'm having a problem with TreeViewer when I want the root node of the model 
to be visible (root being the node that doesn't have any parents). Expanding 
the root node always shows the root node as a child. For example, if I 
expand root, I see root, root. If I expand that, I see root, root, root, 
etc.

From debugging the code, it looks like the structured viewer ultimately 
calls getElements(), rather than getChildren(), when getting children for 
the root. Since I want the root to be visible, getElements() returns root, 
hence the root, root, root, etc.

In my case, the inputElement is also a rootElement (actually, it's the 
only root element).

Matthew Halls says:

Doing some further digging, it appears that TreeViewer does not make 
this distinction internally.  A single method is used to determine the 
children of the element (root or otherwise), and inside that method it 
decides whether to call getElements() or getChildren() based on whether 
the parent element is "equal" to the viewer's input.  Thus getChildren() 
is never called because the getElements() result is always { input }.
Comment 1 Eric Moffatt CLA 2008-04-02 16:14:36 EDT
Why not create an 'input' whose 'getElements' simply returns your 'root' ?
Comment 2 sarah.ettritch CLA 2008-04-02 16:45:05 EDT
(In reply to comment #1)
> Why not create an 'input' whose 'getElements' simply returns your 'root' ?

I'm doing that already. But I consider it a workaround to a bug. I would expect to be able to show a tree model in a TreeViewer by calling TreeViewer.setInput(rootOfModel). Having to create a bogus input object to show a tree model in a TreeViewer works, but it's awkward. I'd expect the viewer to handle what's probably its primary use case in a more intuitive and elegant manner. The problem is that TreeViewer is calling getElements() when it should be calling getChildren().
Comment 3 Matthew Hall CLA 2008-04-02 17:02:25 EDT
I concur with comment #3.  The first time I used TreeViewer I tried the following in my content provider:

Object[] getElements(Object inputElement) {
  return new Object[] { inputElement };
}

Object[] getChildren(Object parentElement) {
  return ((Model)parentElement).getChildren();
}

I found it very surprising when TreeViewer gave me the following:

Root
+-Root
  +-Root
    +-Root
      +-Root
        ...

In my mind this is a leaked implementation detail.
Comment 4 Matthew Hall CLA 2008-04-02 17:04:40 EDT
(In reply to comment #3)
> I concur with comment #3.  

I concur with comment #2, rather. :)

One of these days I'll sit down and teach myself to count.
Comment 5 Eric Moffatt CLA 2008-04-03 11:08:26 EDT
I just did a quick google ("JFace Viewers input") and came across the following article;

http://www.eclipse.org/articles/Article-TreeViewer/TreeViewerArticle.htm

It has a fairly explicit statement regarding why there are two separate mechanisms:

----------- Start Quote -----------

 - public Object[] getElements(Object inputElement) 

This is the method invoked by calling the setInput method on the tree viewer. In fact, the getElements method is called only in response to the tree viewer's setInput method and should answer with the appropriate domain objects of the inputElement. The getElements and getChildren methods operate in a similar way. Depending on your domain objects, you may have the getElements simply return the result of calling getChildren. The two methods are kept distinct because it provides a clean way to differentiate between the root domain object and all other domain objects. 

---------- End Quote -------------

This is the way that it has been operating since at least May 2002 and we can't arbitrarily change the protocol (i.e. to call 'getChildren()' on a setInput) since this is what we'd call a 'breaking change' (it ma break existing implementatons) I think we might have to live with it.

I've just had the logic behind this explained to me; the 'input' represents an -invisible- root to the tree. While you may think this odd consider that in almost every case where eclipse uses trees there are multiple sub-trees (PackageExplorer, Search results...). Without the invisible root you'd have no 'parent' to add a new sub-tree to. 



*** This bug has been marked as a duplicate of bug 9262 ***