Bug 114286 - [Viewers] TreeViewer caches children of an expanded node
Summary: [Viewers] TreeViewer caches children of an expanded node
Status: ASSIGNED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.0   Edit
Hardware: PC Windows XP
: P5 enhancement (vote)
Target Milestone: ---   Edit
Assignee: Platform UI Triaged CLA
QA Contact:
URL:
Whiteboard:
Keywords: helpwanted
Depends on:
Blocks:
 
Reported: 2005-10-29 04:46 EDT by venkataramana m CLA
Modified: 2019-09-06 16:06 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description venkataramana m CLA 2005-10-29 04:46:38 EDT
This is an enhancement request.

We use JFace-TreeViewer to show MOF-Models stored in a non-local database. It is
a multi-user model-browser. So the tree should always reflect the latest model
without any user intervention. This puts us in a situation where
Content-Provider(CP) should always be queried when user clicks on + symbol. But
Eclipse 3.0's JFace TreeViewer caches the children of a tree-item and doesn't
query the CP again. We cannot afford to keep the tree in sync by registering
TreeViewers as observers of the model for the very reason that we do not want to
complicate the code by registering listeners with some model-server etc.,

We found a way of doing that by extending TreeViewer and overriding
createChildren(final Widget widget) API and commenting the code which checks for
children and returns without querying CP if there are any. But I feel CP should
have the authority whether to cache or build-afresh the children of a node
through getElements(Object element) API. Individual applications based on their
requirements may either decide to cache children or build-afresh.

I dont know how we are going to cope with the newer versions of Eclipse.

I request you to please take this up because it is not View's concern to cache
or build-afresh but rather Controller should decide the policy.

Thanks
Venkataramana M
http://www.tcs-trddc.com
Comment 1 Boris Bokowski CLA 2005-11-09 17:28:03 EST
Have you tried using ITreeViewerListener?
Comment 2 venkataramana m CLA 2005-11-10 14:37:08 EST
(In reply to comment #1)
> Have you tried using ITreeViewerListener?

Before coming to the discussion of ITreeViewerListener, some of the critical
requirements of distributed tree are as follows ...
1. ContentProvider::getChildren() should only be triggered once when + is
clicked and none when - is clicked for performance reasons. (Tree-model being
distributed in nature, cann't afford to query children not more than what is
required).

Yeah I have tried ITreeViewerListener as follows ...
public void treeCollapsed(TreeExpansionEvent event) 
{		
	ITreeNode node = (ITreeNode)(event.getElement());
	ITreeContentProvider cp = (ITreeContentProvider)fTree.getContentProvider();
	
	/* remove from viewer */
	fTree.remove(cp.getChildren(node));
				
	/* remove from model */
	node.clearChildren();
}
public void treeExpanded(TreeExpansionEvent event) {		
}

/* tree model */
abstract class TreeNode implements ITreeNode
{
	protected List fChildren;

	public List getChildren() 
	{
		if( fChildren != null )
			return fChildren;
		
		fChildren = new ArrayList();
		createChildren(fChildren);
			
		return fChildren;
	}
	
	protected abstract void createChildren(List children);
}

So what is done above is, when a tree-item collapses, treeCollapsed
event-handler clears modelchildren in viewer as well as in actual-model.
But the issue is that + sign needs to be retained for the user to be able to
again expand and see the new model children. (may be same or modified based on
modifications in the distributed model). Something like a "NEXT" button in HTML
pages on click of which distributed models are queried and shown.
So the above scenario is ruled out.

I could not get any other way of doing this.

I am attaching an example snippet illustrating above with Folder, File nodes.
(An explorer like facility where explorer should always show latest contents
without having to setup any listeners to listen to native file-system for updates.)

/* 
 * Driver code
 * -----------
 * DistributedModelTestDlg dlg = new DistributedModelTestDlg(<shell>);
 * dlg.open();
 */
class DistributedModelTestDlg extends Dialog implements ITreeViewerListener
{
	private TreeViewer fTree;
	
	public DistributedModelTestDlg(Shell parent) {
		super(parent);
	}
	
	protected Control createDialogArea(Composite parent)
	{
		Composite dlgAreaComposite = (Composite)super.createDialogArea(parent);
		createTree(dlgAreaComposite);
		return dlgAreaComposite;
	}
	
	private void createTree(Composite dlgAreaComposite)
	{
		fTree = new TreeViewer(dlgAreaComposite);
		GridData data = new GridData(GridData.FILL_BOTH);
		data.widthHint = 200;
		data.heightHint = 150;
		fTree.getControl().setLayoutData(data);
		
		fTree.setContentProvider(new TreeContentProvider());
		fTree.setLabelProvider(new TreeLabelProvider());
		
		fTree.setInput(new FolderNode(new File("C:/temp")));
		
		fTree.addTreeListener(this);
	}

public void treeCollapsed(TreeExpansionEvent event) 
{		
	ITreeNode node = (ITreeNode)(event.getElement());
	ITreeContentProvider cp = (ITreeContentProvider)fTree.getContentProvider();
	
	/* remove from viewer */
	fTree.remove(cp.getChildren(node));
				
	/* remove from model */
	node.clearChildren();
}

public void treeExpanded(TreeExpansionEvent event) {		
}
}

class TreeContentProvider implements ITreeContentProvider
{
	private static int fCounter = 0;
	
	public Object[] getChildren(Object parentElement) {
		System.out.println((fCounter++) + " getChildren");
		return ((ITreeNode)parentElement).getChildren().toArray();
	}

	public Object getParent(Object element) {
		return ((ITreeNode)element).getParent();
	}

	public boolean hasChildren(Object element) {
		return ((ITreeNode)element).hasChildren();
	}

	public Object[] getElements(Object inputElement) {
		return getChildren(inputElement);
	}

	public void dispose() {	
	}

	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
	}	
}

class TreeLabelProvider extends LabelProvider
{
	public String getText(Object element) {		
		return ((ITreeNode)element).getName();
	}
}

interface ITreeNode
{
	public String getName();
	public List getChildren();
	public boolean hasChildren();
	public ITreeNode getParent();
	public void clearChildren();
}

abstract class TreeNode implements ITreeNode
{
	protected ITreeNode fParent;
	protected List fChildren;
		
	public TreeNode(ITreeNode parent) {
		fParent = parent;
	}
	
	public boolean hasChildren() {		
		return true;
	}

	public ITreeNode getParent() {		
		return fParent;
	}
	
	public List getChildren() 
	{
		if( fChildren != null )
			return fChildren;
		
		fChildren = new ArrayList();
		createChildren(fChildren);
			
		return fChildren;
	}
	
	protected abstract void createChildren(List children);
	
	public void clearChildren() {
		fChildren = null;
	}
}

/* folder node */
class FolderNode extends TreeNode
{
	private File fFolder;
	
	public FolderNode(File folder) {
		this(null, folder);
	}
	
	public FolderNode(ITreeNode parent, File folder)
	{
		super(parent);
		fFolder = folder;
	}

	public String getName() {		
		return "FOLDER: " + fFolder.getName();
	}
	
	protected void createChildren(List children)
	{			
		File[] childFiles = fFolder.listFiles();
		for(int i=0; i<childFiles.length; i++)
		{
			File childFile = childFiles[i];
			if( childFile.isDirectory() )
				children.add(new FolderNode(this, childFile));
			else
				children.add(new FileNode(this, childFile));
		}
	}	
}

/* file node */
class FileNode extends TreeNode
{
	private File fFile;
	
	public FileNode(ITreeNode parent, File file)
	{
		super(parent);
		fFile = file;
	}
	
	public String getName() {		
		return "FILE: " + fFile.getName();
	}
	
	protected void createChildren(List children) {		
	}
	
	public boolean hasChildren() {		
		return false;
	}
}

Hope that makes a point to give the contentprovider the authority to cache or
build-afresh the children of a node. It could be just a style-bit so that
caching can be the default behavior. Whoever do not want caching
setCaching(false); may give them what they want :-)

Thanks
Venkat
Comment 3 Boris Bokowski CLA 2009-11-26 09:53:21 EST
Hitesh is now responsible for watching bugs in the [Viewers] component area.
Comment 4 Eclipse Webmaster CLA 2019-09-06 16:06:50 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.