CaiNiaoCoder
CaiNiaoCoder

Reputation: 3319

JFace Databinding with TreeViewer

I am trying to build a view in my RCP application, the view just contains a TreeViewer.

The tree can contain folders or leafs, a folder can contain folders and leafs. when I add a folder to the back-end data model of the root folder, the UI is updated automatically, but if I add a folder to any branch folder, the UI will not be updated automatically. please tell me what's wrong with my code.

The model class:

public class TreeNode extends BindableObject {

    private Folder parent;

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        super.firePropertyChange("name", this.name, this.name = name);
    }

    public Folder getParent() {
        return parent;
    }

    public void setParent(Folder parent) {
        this.parent = parent;
    }

}
public class Folder extends TreeNode {

    private List<TreeNode> children = new ArrayList<TreeNode>();

    public List<TreeNode> getChildren() {
        return children;
    }

    public void setChildren(List<TreeNode> children) {
        this.children = children;
    }

    public void add(TreeNode node){
        children.add(node);
    }

}

the view :

public class ExplorerView extends ViewPart {

    private WritableList data;
    private TreeViewer treeViewer;

    public WritableList getData() {
        return data;
    }

    public TreeViewer getViewer(){
        return treeViewer;
    }

    public ExplorerView() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public void createPartControl(Composite parent) {
        parent.setLayout(new FillLayout(SWT.HORIZONTAL));
        treeViewer = new TreeViewer(parent, SWT.BORDER);
        treeViewer.setContentProvider(new ObservableListTreeContentProvider(new ExplorerObservableFactory(), new ExploerTreeStructureAdvisor()));
        treeViewer.setLabelProvider(new ExplorerTreeLabelProvider());
        ArrayList<TreeNode> list = new ArrayList<TreeNode>();
        list.add(new ExplorerDataModel().getElements()[0]);
        data = new WritableList(list, TreeNode.class);
        treeViewer.setInput(data);
    }

    @Override
    public void setFocus() {

    }

}

the ObservableFactory:

public class ExplorerObservableFactory implements IObservableFactory {

    @Override
    public IObservable createObservable(Object target) {
        System.out.println(target.getClass().getName());
        if(target instanceof WritableList){
            return (WritableList)target;
        }
        else if(target instanceof Folder){
            List<TreeNode> children = ((Folder)target).getChildren();
            return new WritableList(children, TreeNode.class);
        }
        return null;
    }

}

the TreeStructureAdvisor:

public class ExploerTreeStructureAdvisor extends TreeStructureAdvisor {

    @Override
    public Object getParent(Object element) {
        return ((TreeNode)element).getParent();
    }

    @Override
    public Boolean hasChildren(Object element) {
        if(element instanceof Folder){
            return true;
        }else{
            return false;
        }
    }



}

the data :

public class ExplorerDataModel {
    public TreeNode[] getElements() {
        Folder f1 = new Folder();
        f1.setName("Database Connections");
        Folder f11 = new Folder();
        f11.setName("Credit Test");
        TreeNode t1 = new TreeNode();
        t1.setName("bank@localhost");
        f11.add(t1);
        t1.setParent(f11);
        TreeNode t2 = new TreeNode();
        t2.setName("credit@localhost");
        f11.add(t2);
        t2.setParent(f11);
        Folder f12 = new Folder();
        f12.setName("Credit Product");
        TreeNode t3 = new TreeNode();
        t3.setName("nbcbcredit@localhost");
        f12.add(t3);
        t3.setParent(f12);
        TreeNode t4 = new TreeNode();
        t4.setName("nbcbcredit_bak@localhost");
        f12.add(t4);
        t4.setParent(f12);
        f1.add(f11);
        f11.setParent(f1);
        f1.add(f12);
        f12.setParent(f1);
        return new TreeNode[] { f1 };
    }
}

the test command handler:

public Object execute(ExecutionEvent event) throws ExecutionException {
    ExplorerView v =(ExplorerView) HandlerUtil.getActiveWorkbenchWindow(event).getActivePage().findView("com.amarsoft.dmp.explorer.explorerView");
        Folder f = new Folder();
        f.setName("ODA Flat Files");
        v.getData().add(f);

        Folder f1 = (Folder) v.getData().get(0);
        f1.setName("Database Connections (3)");

        Folder f2 = new Folder();
        f2.setName("Report Test");
        f1.add(f2);

        return null;
    }

if I execute above command, the added folder "ODA Flat Files" will appear in the tree immediately, but the added folder "Report Test" will not be there, if call TreeViewer#refresh() everything is ok, but I want to know why.

Upvotes: 3

Views: 3917

Answers (3)

Matteo
Matteo

Reputation: 1377

It seems you misconfigured the data binding...

Have a look at the official snippets:

Have fun! (without any refresh ;-) )

ps. for EMF just look at this: http://tomsondev.bestsolution.at/2009/06/08/galileo-emf-databinding-%E2%80%93-part-3/

Upvotes: 2

Jakub Denk
Jakub Denk

Reputation: 11

In your ExplorerObservableFactory replace

... else if(target instanceof Folder){
            List<TreeNode> children = ((Folder)target).getChildren();
            return new WritableList(children, TreeNode.class);
     }

by following

     else if(target instanceof Folder){                
            return BeansObservables.observeList(target, "children");
     }

If you return WritableList here, the contentProvider's listener is registered on it (it should be registered on the Folder bean instead)

Upvotes: 1

codejammer
codejammer

Reputation: 1686

Modifying your model does not notify your tree. Refresh is one way of telling the tree that the data has changed and it needs to update. If you go through the java doc for jface viewers in eclipse you will find the following quote

To handle structural changes, use the refresh methods instead.

Upvotes: 4

Related Questions