import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.beans.BeansObservables; import org.eclipse.core.databinding.observable.ChangeEvent; import org.eclipse.core.databinding.observable.IChangeListener; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.core.databinding.observable.list.IListChangeListener; import org.eclipse.core.databinding.observable.list.ListChangeEvent; import org.eclipse.core.databinding.observable.list.ListDiff; import org.eclipse.core.databinding.observable.list.ListDiffEntry; import org.eclipse.core.databinding.observable.list.WritableList; import org.eclipse.core.databinding.observable.map.IObservableMap; import org.eclipse.core.databinding.observable.value.WritableValue; import org.eclipse.jface.databinding.swt.SWTObservables; import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; import org.eclipse.jface.databinding.viewers.ObservableMapLabelProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Text; public class SnippetDirty { public static void main(String[] args) { ViewModel viewModel = new ViewModel(); Shell shell = new View(viewModel).createShell(); // The SWT event loop Display display = Display.getCurrent(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } } // Minimal JavaBeans support public static abstract class AbstractModelObject { private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( this); public void addPropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(propertyName, listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(propertyName, listener); } protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); } } // The data model class. This is normally a persistent class of some sort. static class Person extends AbstractModelObject { // A property... String name = "John Smith"; public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { String oldValue = this.name; this.name = name; firePropertyChange("name", oldValue, name); } } static String someOtherProperty = new String(); // The View's model--the root of our Model graph for this particular GUI. // // Typically each View class has a corresponding ViewModel class. // The ViewModel is responsible for getting the objects to edit from the // data access tier. Since this snippet doesn't have any persistent objects // ro retrieve, this ViewModel just instantiates a model object to edit. static class ViewModel { // The model to bind private List people = new LinkedList(); { people.add(new Person("Steve Northover")); people.add(new Person("Grant Gayed")); people.add(new Person("Veronika Irvine")); people.add(new Person("Mike Wilson")); people.add(new Person("Christophe Cornu")); people.add(new Person("Lynne Kues")); people.add(new Person("Silenio Quarti")); } public List getPeople() { return people; } } // The GUI view //implements IChangeListener , to listener to model changes static class View implements IChangeListener { private ViewModel viewModel; private Table committers; private Button delButton; private Text somePropertyText; private Text msgText; private int nb = 0; //Binding list change listener //Watch for binding list changes and register or remove IChangeListeners private IListChangeListener bindingsListener = new IListChangeListener() { public void handleListChange(ListChangeEvent event) { ListDiff diff = event.diff; ListDiffEntry[] differences = diff.getDifferences(); for (int i = 0; i < differences.length; i++) { ListDiffEntry listDiffEntry = differences[i]; Binding binding = (Binding) listDiffEntry.getElement(); if (listDiffEntry.isAddition()) { binding.getTarget().addChangeListener(View.this); } else { binding.getTarget().removeChangeListener(View.this); } } } }; public View(ViewModel viewModel) { this.viewModel = viewModel; } public Shell createShell() { // Build a UI Display display = Display.getDefault(); Shell shell = new Shell(display); GridLayout layout = new GridLayout(); layout.numColumns = 1; shell.setLayout(layout); committers = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION); committers.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 2)); committers.setLinesVisible(true); delButton = new Button(shell, SWT.NONE); delButton.setText("Remove person"); Label lab = new Label(shell,SWT.NONE); lab.setText("Some other model property:"); lab.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); somePropertyText = new Text(shell, SWT.NONE); somePropertyText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); Label lab2 = new Label(shell,SWT.NONE); lab2.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); msgText = new Text(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI); msgText.setEnabled(false); msgText.setEditable(false); GridData data = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1); data.heightHint = 50; msgText.setLayoutData(data); // Set up data binding. In an RCP application, the threading Realm // will be set for you automatically by the Workbench. In an SWT // application, you can do this once, wrpping your binding // method call. Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() { public void run() { DataBindingContext bindingContext = new DataBindingContext(); bindGUI(bindingContext); } }); // Open and return the Shell shell.pack(); shell.open(); return shell; } protected void bindGUI(DataBindingContext bindingContext) { final TableViewer peopleViewer = new TableViewer(committers); //Table binding final WritableList observablePeople = new WritableList(viewModel.getPeople(), Person.class); final WritableList targetPeople = new WritableList(); //Bind target list with model list //targetPeople is set as the viewer input. //Any change made by the user to the targetPeople will be automatically made by binding to //observablePeople. bindingContext.bindList(targetPeople, observablePeople, null, null); //Table viewer providers stuffs ObservableListContentProvider peopleViewerContentProvider = new ObservableListContentProvider(); peopleViewer.setContentProvider(peopleViewerContentProvider); IObservableMap[] attributeMaps = BeansObservables.observeMaps( peopleViewerContentProvider.getKnownElements(), Person.class, new String[] { "name" }); peopleViewer.setLabelProvider(new ObservableMapLabelProvider(attributeMaps)); //Set target list as input peopleViewer.setInput(targetPeople); //remove people button pressed listener delButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { IStructuredSelection selection = (IStructuredSelection)peopleViewer.getSelection(); if(!selection.isEmpty()) { for(Object selectionItem : selection.toArray()) { if(selectionItem instanceof Person) { //Remove selected item from target list //Note that dirty state should be set here //Because of registered IChangeListener, this is done automatically targetPeople.remove(selectionItem); } } } } }); //some other property binding bindingContext.bindValue( SWTObservables.observeText(somePropertyText, SWT.Modify), new WritableValue(someOtherProperty, null), null, null); //Listen to target changes to report dirty state //Binding list is iterated and each binding is added this class a change listener //handleChange will be called when any binded object changes bindingContext.getBindings().addListChangeListener(bindingsListener); for (Iterator it = bindingContext.getBindings().iterator(); it.hasNext();) { Binding binding = (Binding) it.next(); binding.getTarget().addChangeListener(this); } } public void handleChange(ChangeEvent event) { // report dirty //setDirty(true); //firePropertyChange(PROP!DIRTY); msgText.append("[" + nb ++ + "] dirty state fired !! \n"); } //Dispose method sample // public void dispose() // { // for (Iterator it = bindingContext.getBindings().iterator(); it.hasNext();) { // Binding binding = (Binding) it.next(); // binding.getTarget().removeChangeListener(this); // } // bindingContext.getBindings().removeListChangeListener(bindingsListener); // super.dispose(); // } } }