Community
Participate
Working Groups
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
Have you tried using ITreeViewerListener?
(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
Hitesh is now responsible for watching bugs in the [Viewers] component area.
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.