Question

What i would like to do, is create TreeViewer using databinding for a POJO class, which has multiple list properties, and all of them needs to be observed, and displayed in the viewer.

I would like to display a tree like:

Person
 \
  |- Dog // dogs list
  |- Dog 
  |- Cat // cats list
  |- Cat
  |- Cat

Example:

public class Cat {
    // ...
}

public class Dog {
    // ...
}

The class which has a list reference with both types:

public class Person {
    private List<Dog> dogs = Lists.newArrayList();
    private List<Cat> cats = Lists.newArrayList();
    // getters and setters which fire property change listeners.
}

And then i create the TreeViewer, and set the content provider:

treeViewer = new TreeViewer(parent);

IObservableFactory observableFactory = new IObservableFactory() {

    public IObservable createObservable(final Object target) {
        // target is a Person. What should I return here?
        // If I return for example the observed dogs, cats wont be bound:
        return BeanProperties.list("dogs").observe(target);
    }
};

IContentProvider provider = new ObservableListTreeContentProvider(observableFactory, null);
treeViewer.setContentProvider(provider);

But because the factory can only return one IObservable, I can't observe both cats and dogs. How could i do that?

Was it helpful?

Solution

With your initial design, you can't do it. Why are dogs and cats on the same level in the tree? Levels usually contain same objects (because why would you put your cousins under your parents?).

OK, cats and dogs are both Animals, but then make them extending Animal class and use something like this:

class Person {

  List<Animal> pets; // both dog and cats

}

IObservableFactory observableFactory = new IObservableFactory() {

    public IObservable createObservable(final Object target) {
        return BeanProperties.list("pets").observe(target);
    }
};

And even this would not be a good idea, in case you want to display properties which are only related to cats, dogs, rabbits... .

I am not sure, why you want to use observable content provider (as usually Tree is convenient way to just display something). Wouldn't it be enough for you to use ITreeContentProvider? In this case you could stick with you model of having separate dogs and cats collections and do something like this:

class PetsContentProvider immplements ITreeContentProvider {
  public boolean hasChildren(Object element) {
    if (element instanceof Person) {
      Person person = (Person) element;
      return person.getCats().size > 0 || person.getDogs().size() > 0;
    }
      return false;
  }

  public Object getParent(Object element) {
    // TODO: still better to have a common class
    if((element instanceof Dog) || (element instanceof Cat)) {
        // cast to dog or cat (or better animal)
        // Animal pet = (Animal) element;
        return pet.getOwner();
    }
    return null;
  }

  public Object[] getChildren(Object parentElement) {
    if(parentElement instanceof Person) {
        Person person = (Person) parentElement; 
        return person.getCats().toArray(); // and dogs
    }
    return EMPTY_ARRAY;
  }
}

For more information, please see this very good article on JFace Trees.

And just traditionally Vogella's article on JFaceData Binding.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top