Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practise for data binding a list in Eclipse RCP application

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...

like image 497
Friederike Avatar asked Jul 11 '13 13:07

Friederike


2 Answers

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.

like image 107
maureyes Avatar answered Nov 12 '22 02:11

maureyes


I don't think there's anything wrong with your approach with one possible exception. You need to make sure that the viewer is refreshed in the UI thread:

Display.getDefault().asyncExec(new Runnable() {
    @Override
    public void run() {
        viewer.refresh();
    }
});

However there are things that you can do to make the table update more efficient. In your code above it appears to only add a single item at the top of the table, so you'd be better with a call to:

viewer.insert( text, 0 );
like image 1
Nick Wilson Avatar answered Nov 12 '22 02:11

Nick Wilson