Best practise for data binding a list in Eclipse RCP application

data-binding, eclipse, eclipse-rcp, java, jface

Solution

I recommend you reading JFace Databinding and make use of `ViewerSupport`, `ObservableListContentProvider` and `BeanProperties` to simplfy the job.

You can also see a working example JFace Databinding Snippet: Model to TableViewer binding for a reference, where the binding is done at last with the help of `ViewerSupport`:

(...)
TableViewer peopleViewer = new TableViewer(committers);
ViewerSupport.bind(peopleViewer, new WritableList(viewModel.getPeople(),
     Person.class), BeanProperties.value(Person.class, "name"));

With those helpers you won't need to implement the `Observer` for your list, and if you want your viewer to update its labels when data is modified take a look in the same example to `PropertyChangeSupport`, which allows you to refresh the viewer on every change on any element of the list that you notify through it. It's important that you use `BeanProperties` for the binding.

Problem

I am having trouble understanding the databinding in my Eclipse RCP application. I just can't figure out how it's supposed to work.. Here's what I want to do I have a View where a list of texts should be displayed. The texts are "stored" in a simple `List<String>` which is provided via a singleton (for demonstration purpose only ;)). So whoever uses the `ListProvider` will get the list of texts. When the list changes I want my View to automatically update the table contents. Here's what I've done so far My List provider is an `Observable` that will notify observers when the list changes. In my view I create an Observer to watch the list provider and when the observer is notified I refresh my view. Code for the `ListProvider`: ``` public class ListProvider extends Observable { private Stack<String> hist; private static ListProvider instance; // Singleton implementation public static ListProvidergetInstance() { if (null == instance) { instance = new ListProvider } return instance; } public void add(String text) { if (this.hist.size() == MAX_SIZE) { this.hist.remove(MAX_SIZE-1); } this.hist.add(0, text); // notify all observers this.setChanged(); this.notifyObservers(); } } ``` Code for the view: ``` public class TestView extends ViewPart { private TableViewer viewer; [...] class ViewContentProvider implements IStructuredContentProvider { public void inputChanged(Viewer v, Object oldInput, Object newInput) { } public void dispose() { } public Object[] getElements(Object parent) { return ClipboardHistory.getInstance().getList().toArray(); } } public void createPartControl(Composite parent) { viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); IContentProvider contentProvider = new ViewContentProvider(); viewer.setContentProvider(contentProvider); viewer.setLabelProvider(new ViewLabelProvider()); viewer.setInput(getViewSite()); Observer listObserver = new Observer() { @Override public void update(Observable o, Object arg) { // update the table viewer viewer.refresh(); } }; ListProvider.getInstance().addObserver(listObserver); } } ``` Question Is using `Observer` and `Observable` the "right" way to go or am I missing something? I am not sure I've grasped the concept of RCP Databinding...

Original source